0

私はディファード シェーディング プログラムに取り組んでおり、シーンに 50 の異なるライトを設定する必要があります。そのために、次のコードを使用して属性 (位置、拡散色、反射色) をランダムに生成しています。

void FBORender::BuildLights()
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(0.0, 0.1);

    for (int i = 0; i < NUM_LIGHTS; i++)
    {
        float dc_r = (float) dis(gen);
        float dc_g = (float) dis(gen);
        float dc_b = (float) dis(gen);

        printf("%f\n", dc_r);

        float lp_x = (float)(rand() % 40 - 20);
        float lp_y = (float)(rand() % 100 + 10);
        float lp_z = (float)(rand() % 40 - 20);

        DC[i * NUM_LIGHTS] = dc_r;
        DC[i * NUM_LIGHTS + 1] = dc_g;
        DC[i * NUM_LIGHTS + 2] = dc_b;

        LP[i * NUM_LIGHTS] = lp_x;
        LP[i * NUM_LIGHTS + 1] = lp_y;
        LP[i * NUM_LIGHTS + 2] = lp_z;
    }
}

ただし、複数のライトでライティングを実行する方法がよくわかりません。アンビエント ライトはディフューズ ライトと等しくなければならず、スペキュラー ライトは白であるべきだと言われました。

Phong Ilumination を実行するために必要だったシェーダーを適応させると、次のようになります。

#version 410 core

#define numLights 5

uniform sampler2D tDiffuse; 
uniform sampler2D tPosition;
uniform sampler2D tNormals;

uniform vec4 specularColor;
uniform vec3 diffuseColor[numLights];
uniform vec3 vLightPosition[numLights];

in vec2 texCoord;

out vec4 fragColor;


void main( void )
{
    vec3 tex = texture( tDiffuse, texCoord.st ).xyz;
    vec3 vPosition = texture( tPosition, texCoord.st ).xyz;
    vec3 vNormal = normalize( texture( tNormals, texCoord.st ).xyz * 2 - 1 );

    vec3 vVaryingNormal = vNormal;

    for (int i = 0; i < numLights; i++)
    {
        vec3 vVaryingLightDir = normalize( vLightPosition[i] - vPosition );

        float diff = max( 0.0, dot( normalize( vVaryingNormal ), normalize( vVaryingLightDir ) ) );
        vec4 partialColor = diff * vec4(diffuseColor[i], 1.0);
        partialColor = vec4( mix( partialColor.rgb, tex, 0.5 ), partialColor.a );
        partialColor += vec4( diffuseColor[i], 1.0 );
        vec3 vReflection = normalize( reflect( -normalize( vVaryingLightDir ), normalize( vVaryingNormal )));
        float spec = max( 0.0, dot( normalize( vVaryingNormal ), vReflection ));
        if( diff != 0 )
        {
            float fSpec = pow( spec, 128.0 );
            partialColor.rgb += vec3( fSpec, fSpec, fSpec );
        }

        fragColor += partialColor;
    }
}

ただし、次の図に示すように、(間違っていない場合でも) 醜い結果が得られます。

ここに画像の説明を入力 ここに画像の説明を入力

この結果は 2 つのライトのみを使用しています。50を使わないといけないので、真っ白な画面ばかりだと思いますが…

4

2 に答える 2

1

遅延レンダリングでは、通常、各ライトを個別にレンダリングし、GPU に結果をブレンドさせます。これにより、シェーダーの複雑さが軽減されます。

ライティングの計算を詳しく見てみましょう。

partialColor = vec4( mix( partialColor.rgb, tex, 0.5 ), partialColor.a );

うーん...この行は何をするはずですか? その際、partialColor拡散シェーディングされた色が含まれます (白いマテリアルを想定)。混合によってマテリアルの色を本当に計算したい場合 (これは少し奇妙に思えます)、後でシェーディングを行う必要があります。

vec3 materialColor = mix( vec3(1.0, 1.0, 1.0), tex, 0.5 );
vec4 partialColor = vec4(diffuseColor[i] * diff * materialColor, 1.0);

コードの次の行:

partialColor += vec4( diffuseColor[i], 1.0 );

これが何をするべきなのか、私にはわかりません。それを残してください。

次の行:

vec3 vReflection = normalize( reflect( -normalize( vVaryingLightDir ), normalize( vVaryingNormal )));
float spec = max( 0.0, dot( normalize( vVaryingNormal ), vReflection ));

Phong と Blinn-Phong が混在しています。Phong には、反射光ベクトルと目ベクトルの内積が必要です。Blinn-Phong では、通常のベクトルと、光と目のベクトルの間の半分のベクトルの内積が必要です。

次の行:

partialColor.rgb += vec3( fSpec, fSpec, fSpec );

これは、ライトのスペキュラー カラーで乗算する必要があります。また、 をチェックする代わりに、 をチェックdiff != 0.0する必要がありますspec > 0

それでも問題が発生する場合は、スペキュラー ライティングをオフにして、ディフューズ ライティングが正しいかどうかを確認します。

さらに、ライトが少し明るく見えます。光の色の期待値は です(0.05, 0.05, 0.05)。そのうちの 50 個で合計 が(2.5, 2.5, 2.5)補われ、これは単なる白色光よりもはるかに明るいです。

于 2015-05-26T20:52:09.537 に答える
0

距離ベースの計算は表示されませんが、これは必要です。そうしないと、シーン内のすべてが同じように各ライトの影響を受けます。

距離ベースのライトを計算するにはさまざまな方法がありますが、最も一般的なのは逆平方根です。これは基本的に次のとおりです。

 intensity = 1 / sqrt(distance * distance)

GameDev に関するこの記事もご覧ください。もちろん、PBS (物理ベースのシェーディング。例: Unreal Engine 4 シェーディング) を使用すると、見栄えが大幅に向上します。

于 2015-05-26T20:15:08.190 に答える