因为我是一个完全不懂着色器的人,所以我在尝试使用2D照明系统时遇到了一些问题,该系统基本上用2D黑色纹理覆盖屏幕,并在发光区域有透明孔。
由于我只使用一个纹理,我想我必须在碎片着色器中这样做,对吧?
片段着色器:
#ifdef GL_ES
precision mediump float;
#endif
// Texture, coordinates and size
uniform sampler2D u_texture;
varying vec2 v_texCoord;
uniform vec2 textureSize;
uniform int lightCount;
struct LightSource
{
vec2 position;
float radius;
float strength;
};
uniform LightSource lights[10];
void main()
{
float alpha = 1.0;
vec2 pos = vec2(v_texCoord.x * textureSize.x, v_texCoord.y * textureSize.y);
int i;
for (i = 0; i < lightCount; i++)
{
LightSource source = lights[i];
float distance = distance(source.position, pos);
if (distance < source.radius)
{
alpha -= mix(source.strength, 0.0, distance/source.radius);
}
}
gl_FragColor = vec4(0.0, 0.0, 0.0, alpha);
}
问题是性能真的很糟糕(不能在2盏灯的情况下以60fps的速度运行,屏幕上没有其他东西),有什么建议可以让它变得更好,甚至用不同的方法来解决这个问题吗?
顺便说一句,我是从cocos2d-x开始做这件事的,所以如果有人有任何使用cocos2d元素的想法,那也很受欢迎:)
我完全同意蒂姆的观点。如果你想提高总速度,你必须避免绕圈。我建议您,如果lights数组的大小始终为10,则将循环语句与循环内容的10个副本进行交换。您应该注意,在循环语句中声明的任何变量都将在循环结束时释放!因此,将循环分为十部分是个好主意(很难看,但这是一个老派把戏;))
此外,我还建议你在每一句话中都印上一些println,看看有什么说明在乱写。我敢打赌,混合行动是罪魁祸首。我对椰子2d一无所知,但是,在这个过程结束时,是否可以发出一个独特的混合呼吁,将距离和强度进行汇总?在某个时刻,似乎有一个相当耗时的浮点操作
我会尝试两件事(不能保证有帮助)
-
删除for循环,只在两个指示灯中进行硬编码。如果驱动程序没有正确处理For循环,则其成本可能很高。如果知道这是否会让你慢下来,那就太好了。
-
If语句可能很昂贵,而且我认为这不是
mix
的一个好应用(您正在做a*(1-c) + 0.0 * c
,该术语的后半部分毫无意义)。我可能会尝试替换这个if语句:if (distance < source.radius) { alpha -= mix(source.strength, 0.0, distance/source.radius); }
使用这条单行:
alpha -= (1.0-min(distance/source.radius, 1.0)) * source.strength;