我试图将vec3数组作为统一传递,然后在每个像素上迭代它们。数组的大小因情况而异,所以我无法使循环具有恒定的迭代次数。
以下是代码:
precision highp float;
precision highp int;
varying vec4 v_fragmentColor;
varying vec4 v_pos;
uniform int u_numberOfParticles;
const int numberOfAccumsToCapture = 3;
const float threshold = 0.15;
const float gooCoeff = 1.19;
uniform mat4 u_MVPMatrix;
uniform vec3 u_waterVertices[100];
void main()
{
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
vec2 currPos = v_pos.xy;
float accum = 0.0;
vec3 normal = vec3(0, 0, 0);
for ( int i = 0; i < u_numberOfParticles; ++i )
{
vec2 dir2 = u_waterVertices[i].xy - currPos.xy;
vec3 dir3 = vec3(dir2, 0.1);
float q = dot(dir2, dir2);
accum += u_waterVertices[i].z / q;
}
float normalizeToEdge = 1.0 - (accum - threshold) / 2.0;
if (normalizeToEdge < 0.4)
finalColor = vec4( 0.1, normalizeToEdge + 0.5, 0.9-normalizeToEdge*0.4, 1.0);
if ( normalizeToEdge < 0.2 )
{
finalColor = vec4( 120.0/255.0, 245.0/255.0, 245.0/255.0, 1.0);
float shade = mix( 0.7, 1.0, normal.x);
finalColor *= shade;
}
gl_FragColor = vec4(finalColor);
}
问题在于:
for ( int i = 0; i < u_numberOfParticles; ++i )
{
vec2 dir2 = u_waterVertices[i].xy - currPos.xy;
vec3 dir3 = vec3(dir2, 0.1);
float q = dot(dir2, dir2);
accum += u_waterVertices[i].z / q;
}
当我像这样制作for循环时
for ( int i = 0; i < 2; ++i )
{
//...
}
即使u_numberOfParticles也是2
,我的帧速率也会提高一倍像这样做
for ( int i = 0; i < 100; ++i )
{
if (i == u_numberOfParticles)
break;
//...
}
没有改善。
我知道应对这种情况的唯一方法是创建多个着色器。但是数组的大小可能会在1到40之间变化,因为for循环是愚蠢的,因此制作了40个不同的着色器。任何帮助或想法如何处理这种情况?
答案 0 :(得分:1)
我同意@badweasel的说法,你的方法并不适合着色器。
根据我的理解,您正在计算从当前像素到每个粒子的距离,总结一下并使用结果确定颜色。
也许您可以为每个粒子渲染一个点精灵,并通过智能混合来确定颜色。
您可以使用gl_PointSize
在顶点着色器中设置点精灵的大小。在片段着色器中,您可以使用gl_PointCoord.xy
(在纹理坐标中,即[0..1])确定点精灵中当前像素的位置。通过了解点精灵的大小,您可以计算当前像素与粒子中心的距离,并将颜色设置为某个值。通过额外启用混合,您可以实现循环内的总和,但帧速率要高得多。
这里是顶点和片段着色器,我用它来通过点精灵渲染“假”球体,作为如何使用点精灵的例子。
VS
#version 150
in vec3 InPosition;
uniform mat4 ModelViewProjectionMatrix;
uniform int Radius = 10;
void main()
{
vec4 Vertex = vec4(InPosition, 1.0);
gl_Position = ModelViewProjectionMatrix * Vertex;
gl_PointSize = Radius;
}
FS
#version 150
out vec4 FragColor;
void main()
{
// calculate normal, i.e. vector pointing from point sprite center to current fragment
vec3 normal;
normal.xy = gl_PointCoord * 2 - vec2(1);
float r2 = dot(normal.xy, normal.xy);
// skip pixels outside the sphere
if (r2 > 1) discard;
// set "fake" z normal to simulate spheres
normal.z = sqrt(1 - r2);
// visualize per pixel eye-space normal
FragColor = vec4(gl_PointCoord, normal.z, 1.0);
}
注意,您需要启用:GL_POINT_SPRITE
,GL_PROGRAM_POINT_SIZE
才能使用点精灵。