2

最近几天我一直在写一个片段着色器,它将处理我正在制作的 2d 游戏的背景。然而,今天我注意到我的云渲染在渲染时非常慢(从 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;
}

可以在这里找到一个没有时间的工作版本,以了解着色器的实际作用

4

1 回答 1

2

通常着色器编译器(无论是 glsl/hlsl)都非常擅长删除死代码。

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

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

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

于 2013-09-17T18:01:35.693 回答