iPhone GLSL动态分支问题

标签 iphone opengl-es opengl-es-2.0 glsl shader

我试图将 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 个不同的着色器是愚蠢的。如何处理这种情况有任何帮助或想法吗?

最佳答案

我同意@badweasel的观点,你的方法并不真正适合着色器。

据我了解,您正在计算从当前像素到每个粒子的距离,总结一些内容并使用结果确定颜色。

也许您可以为每个粒子渲染一个点 Sprite ,并通过智能混合确定颜色。

您可以使用gl_PointSize在顶点着色器中设置点 Sprite 的大小。在片段着色器中,您可以使用 gl_PointCoord.xy (位于纹理坐标中,即 [0..1])确定点 Sprite 内当前像素的位置。通过了解点 Sprite 的大小,您可以计算当前像素距粒子中心的距离并将颜色设置为某种颜色。通过另外启用混合,您也许能够实现在循环内进行的求和,但帧速率要高得多。

这里是我用来通过点 Sprite 渲染“假”球体的顶点和片段着色器,作为如何使用点 Sprite 的示例。

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_SPRITEGL_PROGRAM_POINT_SIZE 才能使用点 Sprite 。

关于iPhone GLSL动态分支问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15789478/

相关文章:

java - W/OpenGLRenderer : Points are too far apart

java - 有没有办法在 Android 的 OpenGL ES 2.0 和 Java 中使用顶点缓冲区中的对象?

opencv - GLSL和OpenCV

iphone - 调用宏

iphone - 在后台轮询服务器的正确方法

iphone - 在模态视图关闭时从选项卡栏项目中删除选择图像

安卓 OpenGL ES : Rotation against arbitrary axis?

java - 我可以在 OpenGL ES 2.0 中使用哪些版本的 GLSL?

colors - 使用 Alpha channel /不透明度时颜色变深

ios - 可以限制某些国家/地区的应用内购买吗?