4

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 ですが、フレームレートが 2 倍になります

こんな感じに作ってます

for ( int i = 0; i < 100; ++i )
{
    if (i == u_numberOfParticles)
        break;
    //...
}

改善はありません。

この状況に対処する唯一の方法は、複数のシェーダーを作成することです。しかし、配列のサイズは 1 から 40 まで変化する可能性があり、for ループのためだけに 40 の異なるシェーダーを作成するのはばかげています。この状況に対処する方法やアイデアはありますか?

4

1 に答える 1

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

于 2013-08-05T02:04:13.730 に答える