GLSL 片段着色器速度变慢



在过去的几天里,我一直在编写一个片段着色器,它将处理 2D 游戏 im 制作的背景。但是,今天我注意到我的云渲染在渲染时非常慢(从 3000 帧/秒下降到 300 fps)。

起初我以为这是因为我在生成云时做了一些愚蠢的事情,但经过一些实验,我注意到只有当我在gl_FragColor中添加云时,速度才会变慢。计算它们似乎对性能没有任何影响。

我像这样生成云:

float rand(vec2 co){
  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
float hash( float n ) //Borrowed from voltage
{
    return fract(sin(n)*43758.5453);
}
float fBmWRand( vec2 p )//Borroowed from Mark Sleith
{
    float f = 0.0;
    f += 0.50000*rand( p ); p = p*2.02;
    f += 0.25000*rand( p ); p = p*2.03;
    f += 0.12500*rand( p ); p = p*2.01;
    f += 0.06250*rand( p ); p = p*2.04;
    f += 0.03125*rand( p );
    return f/0.984375;
}
float noise( in vec2 x )//Borroowed from Mark Sleith
{
vec2 p = floor(x);
vec2 f = fract(x);
    f = f*f*(3.0-2.0*f);
    float n = p.x + p.y*57.0;
    float res = mix(mix( hash(n+  0.0), hash(n+  1.0),f.x), mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y);
    return res;
}
float fbm( vec2 p ) //Borroowed from Mark Sleith
{
        float f = 0.0;
        f += 0.50000*noise( p ); p = p*2.02;
        f += 0.25000*noise( p ); p = p*2.03;
        f += 0.12500*noise( p ); p = p*2.01;
        f += 0.06250*noise( p ); p = p*2.04;
        f += 0.03125*noise( p );
        return f/0.984375;
}
vec3 bgGradient()
{
    //Getting the height of the current pixel
    float height = gl_FragCoord.y / iResolution.y;
    //Calculating the brightness of the pixel
    float brightness = 1.0 - 0.4 * height;
    //Combining everything into a background
    vec3 grad = vec3(1., 1., 1.);// * brightness;
    return grad;
}
bool star()
{
/*//Getting a position to run random calculations with
float pos = (gl_FragCoord.x / iResolution.x) * (gl_FragCoord.y / iResolution.y) + 0.5;
if(hash(pos) < 0.001)
{
    return true;
}
return false*/;
if(fBmWRand(gl_FragCoord.xy / iResolution.xy) < 0.08)
{
    return true;
}
return false;
}
float cloudFadeDist = 0.1; //The distance at which the clouds will start fading away
vec4 clouds( vec2 point )
{
vec4 result = vec4(0., 0., 0., 0.);
//Checking if the cloud is above
float fbmResult = fbm(point * 5.);
if(fbmResult > overcast)
{
    result = vec4(fbmResult, fbmResult, fbmResult, 1.0);
    //result = vec4(1., 1., 1., 1.);
}
else if(fbmResult > overcast - (cloudFadeDist / resFact)) //Outlining the clouds
{
    float dist = overcast - fbmResult;
    float colorFac = 1.0 - dist / (cloudFadeDist / resFact);
    if(colorFac > 0.0001)
    {
        result = vec4(fbmResult, fbmResult, fbmResult, colorFac);
    }
}
//Finer details
float fbmDetail = fbm(point * 20.);
vec4 details = vec4( 0.7 + fbmDetail, 0.7 + fbmDetail, 0.7 + fbmDetail, 1.0);
//result = mix(result, details, result.a);
result = result * details;
result = result * details;
return result;
}

我用这个将云添加到"图像"的其余部分

//Generating the clouds
vec4 cloudLayer = vec4(0., 0., 0., 0.);
for(int i = 0; i < 4; i++)
{
    //clouds( (15.0 * float(i)) + gl_FragCoord.xy / iResolution.xy + posX * float(i + 1));
    /*vec4 cloud = clouds( vec2((15. * float(i)) + gl_FragCoord.x / iResolution.x + posX * float(i + 1)),
                        (15. * float(i)) + gl_FragCoord.y / iResoulution.y);*/
    vec4 cloud = clouds( vec2( (15. * float(i)) + gl_FragCoord.x / iResolution.x + posX * float(i + 1),
        (15. * float(i)) + gl_FragCoord.y / iResolution.y + posY * float(i + 1)));
    //finalColor = finalColor + vec4(cloud, 1.);
    cloudLayer = mix(cloudLayer, cloud, cloud.a);
}
if(time > nStart || time < nEnd) //Nighttime
{
    finalColor = finalColor * nSky;
    finalColor = mix(finalColor, starLayer, starLayer.a);
    cloudLayer = cloudLayer * nCloud;
    //finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
    vec4 genericColor = cloudLayer;
    finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
    //finalColor = vec4(nSky.r, nSky.g, nSky.b, 1.0);
}
else if(time > dStart && time < dEnd)
{
    finalColor = finalColor * dSky;
    //cloudLayer = cloudLayer * dCloud;
    finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
}
else if(time > dEnd && time < nStart) //Evening
{
    float timeFact = (time - dEnd) / (nStart - dEnd);
    //Calculating the diffirence between night and day
    vec4 skyDiff = vec4(nSky.r - dSky.r, nSky.g - dSky.g, nSky.b - dSky.b, 1.);
    vec4 skyColor = vec4(dSky.r + (skyDiff.r * timeFact), dSky.g + (skyDiff.g * timeFact), dSky.b + (skyDiff.b * timeFact), 1.);
    finalColor = skyColor;
    //Stars
    finalColor = mix(finalColor, starLayer, starLayer * timeFact);
    //Clouds
    vec4 cloudDiff = vec4(nCloud.r - dCloud.r, nCloud.g - dCloud.g, nCloud.b - dCloud.b, 1.);
    vec4 cloudColor = vec4(dCloud.r + (cloudDiff.r * timeFact), dCloud.g + (cloudDiff.g * timeFact), dCloud.b + (cloudDiff.b * timeFact), 1.);
    vec4 cloudLayer = cloudLayer * cloudColor;
    finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
}
else if(time > nEnd && time < dStart) //Evening
{
    float timeFact = (time - nEnd) / (dStart - nEnd);
    //Calculating the diffirence between night and day
    vec4 skyDiff = vec4(dSky.r - nSky.r, dSky.g - nSky.g, dSky.b - nSky.b, 1.);
    vec4 skyColor = vec4(nSky.r + (skyDiff.r * timeFact), nSky.g + (skyDiff.g * timeFact), nSky.b + (skyDiff.b * timeFact), 1.);
    finalColor = skyColor;
    //Stars
    finalColor = mix(finalColor, starLayer, starLayer * 1. - timeFact);
    //Clouds
    vec4 cloudDiff = vec4(dCloud.r - nCloud.r, dCloud.g - nCloud.g, dCloud.b - nCloud.b, 1.);
    vec4 cloudColor = vec4(nCloud.r + (cloudDiff.r * timeFact), nCloud.g + (cloudDiff.g * timeFact), nCloud.b + (cloudDiff.b * timeFact), 1.);
    vec4 cloudLayer = cloudLayer * cloudColor;
    finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
}
gl_FragColor = finalColor;

只有当我这样做时,才会发生减速:

gl_FragColor = finalColor;

如果我删除云生成的详细信息部分,我还将 FPS 从 300 加倍到 600

是我做错了什么,还是当我做这样的事情时,着色器很自然地会占用这种性能。

作为参考,这是整个着色器

    uniform vec2 iResolution;
uniform vec2 iMouse;
uniform float time;
uniform float overcast;
uniform float posX;
uniform float posY;
uniform vec4 dSky; //The color of the sky during the day
uniform vec4 nSky; //The color of the sky during the night
uniform vec4 dCloud; //The color of the clouds at day
uniform vec4 nCloud; //The color of the clouds at night
float resFact = iResolution.x / 500;
//float overcast = iMouse.y / iResolution.y;
//float posX = iMouse.x / iResolution.x;
/*float nSkyR = 0.05;
float nSkyG = 0.05;
float nSkyB = 0.39;*/
float rand(vec2 co){
  return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
float hash( float n ) //Borrowed from voltage
{
    return fract(sin(n)*43758.5453);
}
float fBmWRand( vec2 p )//Borroowed from Mark Sleith
{
        float f = 0.0;
        f += 0.50000*rand( p ); p = p*2.02;
        f += 0.25000*rand( p ); p = p*2.03;
        f += 0.12500*rand( p ); p = p*2.01;
        f += 0.06250*rand( p ); p = p*2.04;
        f += 0.03125*rand( p );
        return f/0.984375;
}
float noise( in vec2 x )//Borroowed from Mark Sleith
{
    vec2 p = floor(x);
    vec2 f = fract(x);
        f = f*f*(3.0-2.0*f);
        float n = p.x + p.y*57.0;
        float res = mix(mix( hash(n+  0.0), hash(n+  1.0),f.x), mix( hash(n+ 57.0), hash(n+ 58.0),f.x),f.y);
        return res;
}
float fbm( vec2 p ) //Borroowed from Mark Sleith
{
        float f = 0.0;
        f += 0.50000*noise( p ); p = p*2.02;
        f += 0.25000*noise( p ); p = p*2.03;
        f += 0.12500*noise( p ); p = p*2.01;
        f += 0.06250*noise( p ); p = p*2.04;
        f += 0.03125*noise( p );
        return f/0.984375;
}
vec3 bgGradient()
{
    //Getting the height of the current pixel
    float height = gl_FragCoord.y / iResolution.y;
    //Calculating the brightness of the pixel
    float brightness = 1.0 - 0.4 * height;
    //Combining everything into a background
    vec3 grad = vec3(1., 1., 1.);// * brightness;
    return grad;
}
bool star()
{
    /*//Getting a position to run random calculations with
    float pos = (gl_FragCoord.x / iResolution.x) * (gl_FragCoord.y / iResolution.y) + 0.5;
    if(hash(pos) < 0.001)
    {
        return true;
    }
    return false*/;
    if(fBmWRand(gl_FragCoord.xy / iResolution.xy) < 0.08)
    {
        return true;
    }
    return false;
}
float cloudFadeDist = 0.1; //The distance at which the clouds will start fading away
vec4 clouds( vec2 point )
{
    vec4 result = vec4(0., 0., 0., 0.);
    //Checking if the cloud is above
    float fbmResult = fbm(point * 5.);
    if(fbmResult > overcast)
    {
        result = vec4(fbmResult, fbmResult, fbmResult, 1.0);
        //result = vec4(1., 1., 1., 1.);
    }
    else if(fbmResult > overcast - (cloudFadeDist / resFact)) //Outlining the clouds
    {
        float dist = overcast - fbmResult;
        float colorFac = 1.0 - dist / (cloudFadeDist / resFact);
        if(colorFac > 0.0001)
        {
            result = vec4(fbmResult, fbmResult, fbmResult, colorFac);
        }
    }
    //Finer details
    float fbmDetail = fbm(point * 20.);
    vec4 details = vec4( 0.7 + fbmDetail, 0.7 + fbmDetail, 0.7 + fbmDetail, 1.0);
    //result = mix(result, details, result.a);
    result = result * details;
    result = result * details;
    return result;
}
vec2 sunPos = vec2(0.15, 0.1);
float sunWidth = 0.03;
float sunGlow = 0.015;
float sunR = 1.;
float sunG = 1.;
float sunB = 0.8;
vec4 sun()
{
    vec4 result = vec4(0., 0., 0., 0.);
    float xPos = gl_FragCoord.x / iResolution.x;
    float yPos = gl_FragCoord.y / iResolution.x;
    float xDist = xPos - sunPos.x;
    float yDist = yPos - sunPos.y;
    float dist = sqrt(pow(xDist, 2.) + pow(yDist, 2.));

    if(dist < sunWidth)
    {
        result = vec4(sunR, sunG, sunB, 1.);
    }
    else if(dist < sunWidth + sunGlow)
    {
        float distFact = (dist - sunWidth) / sunGlow;
        result = vec4(sunR, sunG, sunB , 1. - distFact);
    }
    return result;
}
float nStart = 2200;
float nEnd = 600;
float dStart = 800;
float dEnd = 2000;
void main(void)
{
    //Cretaing the final color variable and adding the gradient
    vec4 finalColor = vec4(bgGradient(), 1.0);
    //Creating stars
    vec4 starLayer = vec4(0., 0., 0., 0.);
    if(star() == true)
    {
        starLayer = vec4(1., 1., 1., 1.);   //Make the pixel very bright
    }
    //Generating the clouds
    vec4 cloudLayer = vec4(0., 0., 0., 0.);
    for(int i = 0; i < 4; i++)
    {
        //clouds( (15.0 * float(i)) + gl_FragCoord.xy / iResolution.xy + posX * float(i + 1));
        /*vec4 cloud = clouds( vec2((15. * float(i)) + gl_FragCoord.x / iResolution.x + posX * float(i + 1)),
                            (15. * float(i)) + gl_FragCoord.y / iResoulution.y);*/
        vec4 cloud = clouds( vec2( (15. * float(i)) + gl_FragCoord.x / iResolution.x + posX * float(i + 1),
            (15. * float(i)) + gl_FragCoord.y / iResolution.y + posY * float(i + 1)));
        //finalColor = finalColor + vec4(cloud, 1.);
        cloudLayer = mix(cloudLayer, cloud, cloud.a);
    }
    if(time > nStart || time < nEnd) //Nighttime
    {
        finalColor = finalColor * nSky;
        finalColor = mix(finalColor, starLayer, starLayer.a);
        cloudLayer = cloudLayer * nCloud;
        //finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
        vec4 genericColor = cloudLayer;
        finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
        //finalColor = vec4(nSky.r, nSky.g, nSky.b, 1.0);
    }
    else if(time > dStart && time < dEnd)
    {
        finalColor = finalColor * dSky;
        //cloudLayer = cloudLayer * dCloud;
        finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
    }
    else if(time > dEnd && time < nStart) //Evening
    {
        float timeFact = (time - dEnd) / (nStart - dEnd);
        //Calculating the diffirence between night and day
        vec4 skyDiff = vec4(nSky.r - dSky.r, nSky.g - dSky.g, nSky.b - dSky.b, 1.);
        vec4 skyColor = vec4(dSky.r + (skyDiff.r * timeFact), dSky.g + (skyDiff.g * timeFact), dSky.b + (skyDiff.b * timeFact), 1.);
        finalColor = skyColor;
        //Stars
        finalColor = mix(finalColor, starLayer, starLayer * timeFact);
        //Clouds
        vec4 cloudDiff = vec4(nCloud.r - dCloud.r, nCloud.g - dCloud.g, nCloud.b - dCloud.b, 1.);
        vec4 cloudColor = vec4(dCloud.r + (cloudDiff.r * timeFact), dCloud.g + (cloudDiff.g * timeFact), dCloud.b + (cloudDiff.b * timeFact), 1.);
        vec4 cloudLayer = cloudLayer * cloudColor;
        finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
    }
    else if(time > nEnd && time < dStart) //Evening
    {
        float timeFact = (time - nEnd) / (dStart - nEnd);
        //Calculating the diffirence between night and day
        vec4 skyDiff = vec4(dSky.r - nSky.r, dSky.g - nSky.g, dSky.b - nSky.b, 1.);
        vec4 skyColor = vec4(nSky.r + (skyDiff.r * timeFact), nSky.g + (skyDiff.g * timeFact), nSky.b + (skyDiff.b * timeFact), 1.);
        finalColor = skyColor;
        //Stars
        finalColor = mix(finalColor, starLayer, starLayer * 1. - timeFact);
        //Clouds
        vec4 cloudDiff = vec4(dCloud.r - nCloud.r, dCloud.g - nCloud.g, dCloud.b - nCloud.b, 1.);
        vec4 cloudColor = vec4(nCloud.r + (cloudDiff.r * timeFact), nCloud.g + (cloudDiff.g * timeFact), nCloud.b + (cloudDiff.b * timeFact), 1.);
        vec4 cloudLayer = cloudLayer * cloudColor;
        finalColor = mix(finalColor, cloudLayer, cloudLayer.a);
    }
    //finalColor = vec4(1., 0., 0., 1.);
    //vec4 sunColor = sun();
    //finalColor = mix(finalColor, sunColor, sunColor.a);
    //If there is a star
    /*if(star() == true)
    {
        finalColor = vec4(1., 1., 1., 1.);  //Make the pixel very bright
    }*/
    /*for(int i = 0; i < 4; i++)
    {
        //clouds( (15.0 * float(i)) + gl_FragCoord.xy / iResolution.xy + posX * float(i + 1));
        //vec4 cloud = clouds( vec2((15. * float(i)) + gl_FragCoord.x / iResolution.x + posX * float(i + 1)),
                            (15. * float(i)) + gl_FragCoord.y / iResoulution.y);
        vec4 cloud = clouds( vec2( (15. * float(i)) + gl_FragCoord.x / iResolution.x + posX * float(i + 1),
            (15. * float(i)) + gl_FragCoord.y / iResolution.y + posY * float(i + 1)));
        //finalColor = finalColor + vec4(cloud, 1.);
        finalColor = mix(finalColor, cloud, cloud.a);
    }*/
    gl_FragColor = finalColor;
}

可以在此处找到没有时间内容的工作版本,以了解着色器的实际作用

一般来说,着色器编译器(glsl/hlsl)非常擅长删除死代码。

因此,如果您计算某个值但不使用它,编译器只会在将着色器字节码发送到显卡之前将其剥离。因此,在最终编译版本中,计算实际上不会发生。

一旦你开始使用这个值(一旦你把它分配给gl_FragColor,你就会这样做),那么它实际上"真正"地集成在你的最终着色器中。

而且噪声计算通常相当 ALU 密集,因此减速到 300 并不罕见(实际上甚至不太糟糕,具体取决于您使用的卡)。

相关内容

  • 没有找到相关文章

最新更新