在过去的几天里,我一直在编写一个片段着色器,它将处理 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 并不罕见(实际上甚至不太糟糕,具体取决于您使用的卡)。