初めてのシャドウマッピングの問題


9

OpenGLでシェーダーを使用して初めて基本的なシャドウマッピングを実装しましたが、いくつかの問題に直面しています。以下に、レンダリングされたシーンの例を示します。

ここに画像の説明を入力してください

私がフォローしているシャドウマッピングのプロセスは、光の視点からのビューマトリックスと、通常のレンダリングに使用される投影およびモデルマトリックスを使用して、シーンをフレームバッファーにレンダリングすることです。

2番目のパスでは、上記のMVPマトリックスをライトの視点から、位置をライトスペースに変換する頂点シェーダーに送信します。フラグメントシェーダーは遠近法による分割を行い、位置をテクスチャー座標に変更します。

これが私の頂点シェーダーです、


#version 150 core

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 MVPMatrix;
uniform mat4 lightMVP;

uniform float scale;

in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_TexCoord;

smooth out vec3 pass_Normal;
smooth out vec3 pass_Position;
smooth out vec2 TexCoord;
smooth out vec4 lightspace_Position;

void main(void){
    pass_Normal = NormalMatrix * in_Normal; 
    pass_Position = (ModelViewMatrix * vec4(scale * in_Position, 1.0)).xyz;
    lightspace_Position = lightMVP * vec4(scale * in_Position, 1.0);
    TexCoord = in_TexCoord;

    gl_Position = MVPMatrix * vec4(scale * in_Position, 1.0);
}

そして私のフラグメントシェーダー、


#version 150 core

struct Light{
    vec3 direction;
};

uniform Light light;
uniform sampler2D inSampler;
uniform sampler2D inShadowMap;

smooth in vec3 pass_Normal;
smooth in vec3 pass_Position;
smooth in vec2 TexCoord;
smooth in vec4 lightspace_Position;

out vec4 out_Color;


float CalcShadowFactor(vec4 lightspace_Position){

    vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;

    vec2 UVCoords;
    UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
    UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;

    float Depth = texture(inShadowMap, UVCoords).x;
    if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
    else return 1.0;
}

void main(void){

    vec3 Normal = normalize(pass_Normal);
    vec3 light_Direction = -normalize(light.direction);
    vec3 camera_Direction = normalize(-pass_Position);
    vec3 half_vector = normalize(camera_Direction + light_Direction);

    float diffuse = max(0.2, dot(Normal, light_Direction));
    vec3 temp_Color = diffuse * vec3(1.0);

    float specular = max( 0.0, dot( Normal, half_vector) );

    float shadowFactor = CalcShadowFactor(lightspace_Position);

    if(diffuse != 0 && shadowFactor > 0.5){
        float fspecular = pow(specular, 128.0);
        temp_Color += fspecular;
    }

    out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}

問題の1つは、写真でわかるようにセルフシャドウイングです。クレート自体に独自のシャドウが投影されています。私が試したのは、ポリゴンオフセットを有効にすること(つまり、glEnable(POLYGON_OFFSET_FILL)、glPolygonOffset(GLfloat、GLfloat))ですが、あまり変化しませんでした。フラグメントシェーダーでわかるように、静的オフセット値を0.001に設定しましたが、ライトの距離に応じて値を変更して、より望ましい効果を得る必要があるため、あまり便利ではありません。また、フレームバッファーにレンダリングするときに前面カリングを使用しようとしましたが、あまり変化しませんでした。

もう1つの問題は、ライトの視錐台の外側のピクセルがシェーディングされることです。影を落とすことができると思われる唯一の物体は木箱です。より適切な投影法とビュー行列を選択する必要があると思いますが、それを行う方法がわかりません。一般的な方法は何ですか、正射投影を選択する必要がありますか?

少しググるところから、これらの問題はささいなことではないことを理解しています。これらの問題の解決策を簡単に実装できる人はいますか?追加のヒントを教えていただけますか?

私のコードについてさらに情報が必要かどうか私に尋ねてください。

ここでとクレートのクローズアップのシャドウマッピングなしの比較です。セルフシャドウがより見やすくなります。


問題をより詳しく説明する必要があるようです。あなたの問題について1つの文があり、次の文は1つの修正を示唆しています。問題が何であるか、そしてそれを試し、修正するためにすでに何をしたかを正確に教えてください。
MichaelHouse

私は自分の投稿を編集しました。
グリーバーハート

回答:


6

ライトの背面にあるポリゴンをシャドウしないでください。

フラグメントシェーダーを以下のコードに変更しました。

float CalcShadowFactor(vec4 lightspace_Position)
{

    vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;

    vec2 UVCoords;
    UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
    UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;

    float Depth = texture(inShadowMap, UVCoords).x;
    if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
    else return 1.0;
}

void main(void)
{

    vec3 Normal = normalize(pass_Normal);
    vec3 light_Direction = -normalize(light.direction);
    vec3 camera_Direction = normalize(-pass_Position);
    vec3 half_vector = normalize(camera_Direction + light_Direction);

    float fndotl = dot(Normal, light_Direction);
    float shadowFactor = CalcShadowFactor(lightspace_Position);
    float diffuse = max(0.0, fndotl) * shadowFactor + 0.2;
    vec3 temp_Color = vec3(diffuse);

    float specular = max( 0.0, dot( Normal, half_vector) );

    if(shadowFactor > 0.9){
        float fspecular = pow(specular, 128.0);
        temp_Color += fspecular;
    }

    out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}

8

セルフシャドウイングに関しては、あなたが何を言っているのかわかりません。スクリーンショットのクレートに「シャドウニキビ」は見当たりません。光から離れた顔が暗いということであれば、もちろんそうですが、そうでなければなりません!:)側面は少し変に見えますが、対角線を半分照らして半分影に分割します。ライティングにNドットLを使用していて、正常な法線(つまり、スムーズな法線ではなく、この立方体のハード法線)がある場合は、発生しないはずです。

ポリゴンオフセットを使用したり、背面をシャドウマップに描画したりすることは、シャドウニキビの標準的な解決策(実際には...回避策です)です。

射影行列については、ライトをカメラと考える必要があります。ポイントライトの場合はパースビューカメラ、ディレクショナルライトの場合は正射投影カメラのようになります。カメラの場合と同じように、ライトの視野、アスペクト比などを使用して、投影行列を作成します。

ピクセルシェーダーがライトの視錐台にのみピクセルを描画するように制限するには、シャドウマップのUVを計算したら、それらが0と1の間にあるかどうかを確認しますdiscard(またはライトの色をゼロに設定します)。もう1つの方法は、シャドウマップテクスチャを「clamp to border」モードに設定し、ボーダーの色をゼロに設定することです。これにより、シャドウマップの外側のすべてが完全にシャドウされます。


これはボックスのクローズアップであり、シャドウマッピングリンクがある場合とない場合の比較です。セルフシャドウは、ここでより見やすくなっています。ポイントライトに透視カメラを使用し、指向性に正投影を使用する理由を説明していただけませんか?
グリーバーハート

さて、そのショットでは、それは影のにきびのように見えません。(前面ではなく)シャドウマップに背面を描画すると、問題が修正されます。あなたがそれを試したと言ったのは知っていますが、何か問題があったのでしょうか?それだけglCullFace(GL_FRONT)です。ポイント対指向性に関しては、それはすべて光線に関するものです。カメラ光線はパースペクティブカメラの点に収束し、光線は点光源の点に収束します。正射投影カメラではカメラ光線は平行で、指向性ライトでは光線は平行です。
ネイサンリード

そうですね。 フェイスカリングありとなしの別の比較を次に示します。下部にあるものでは、フェイスカリングが有効になっています。ライトビューマトリックスに正射影を使用しようとしますが、セルフシャドウイングの問題には影響しませんか?多分私のクリップの範囲が大きすぎます(つまり、0.1から100)。
グリーバーハート

それらはまったく同じに見えます。シーンの残りの部分で裏面カリングを使用していますよね?しましたglEnable(GL_CULL_FACE)か?
ネイサンリード、

それらはまったく同じではありません。ボックスをよく見てください。上の図では、シャドウラインは凸型で、下のラインは凹型です。
グリーバーハート

3

ライトビューの外側のピクセルは、ライトデプステクスチャの外側からサンプリングされているため、暗いです。

頂点を射影行列で変換すると、フラグメントのクリップ座標[lightspace_Position]が取得されます。次に、それをテクスチャ座標[UVCoords]に変換します。ただし、フラグメントのクリップ空間座標は依然として-1.0〜1.0の範囲外(画面外のため、クリップされるため)であり、変換されたテクスチャ座標はテクスチャの0.0〜1.0の範囲外になる可能性があります。

これを試して:

if(UVCoords.x >= 0.0 && UVCoords.x <= 1.0 && UVCoords.y >= 0.0 && UVCoords.y <= 1.0 && (Depth < (ProjectionCoords.z + 0.001)))
    return 0.5;

[lightMVP]にバイアスマトリックスを掛けて、フラグメントシェーダーで座標変換を行わないようにすることもできます。


バイアス行列は通常、人々が行く方法です。フラグメントシェーダーでコードを分岐するよりもはるかに高速です。
イアンヤング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.