分散シャドウマップは適切にレンダリングしたくない


8

エンジンにVSM(およびESM)を実装しましたが、ネットワークで公開されている多くの例で期待した結果が得られませんでした。

シャドウマップのフィルタリングをGL_LINEARに設定しましたが、結果を通常のシャドウマップと比較すると、明らかに悪くなります。

画面

ほとんどのチュートリアルと同じように、ポイントライトシェーダーで直接モーメントを計算するか、テクスチャから取得しましたが、結果は同じです。

コード:

uniform samplerCubeShadow shadowMap;

...

vec4 worldSpace=inverse(ViewMatrix)*vec4(pos,1);

vec4 coord=LightViewMatrix*worldSpace;
vec4 abs_coord=abs(coord);

float fs_z=-max(abs_coord.x, max(abs_coord.y, abs_coord.z));

vec4 clip=LightProjectionMatrix*vec4(0.0,0.0,fs_z,1.0);
float d2=(clip.z / clip.w)*0.5+0.5; // clamp to [0..1]

...

float shadowTexel=texture(shadowMap,vec4(coord.xyz,d2));

// VSM (Variance Shadow Map)
// get partial derivatives
float dx = dFdx(d2);
float dy = dFdy(d2);
vec2 moments = vec2(d2, d2*d2+0.25*(dx*dx+dy*dy));
return chebychevInequality(moments, shadowTexel);

このコードを使用すると、上の画像のような結果が得られます。また、samplerCubeShadowではなくsamplerCubeを使用しようとしましたが、結果はさらに悪化しました。まず、ハードシャドウを取得しました。第2に、他のテクスチャからモーメントを取得するときに必要なように、シャドウは領域を塗りつぶします。セカンドスクリーンを見てください。ここでは、生成されたキューブマップも確認します。3つのチャネルすべてにdepth / moment1を配置しても、デプスマップにあるものとは異なります。

瞬間を取得するためのシェーダー:

// Vartex shader
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;

// Fragment shader
float depth = v_position.z / v_position.w ;
depth = depth * 0.5 + 0.5;          //Don't forget to move away from unit cube ([-1,1]) to [0,1] coordinate system

float moment1 = depth;
float moment2 = depth * depth;

// Adjusting moments (this is sort of bias per pixel) using derivative
float dx = dFdx(depth);
float dy = dFdy(depth);
moment2 += 0.25*(dx*dx+dy*dy) ;

FragColor = vec4( moment1,moment2, 0.0, 0.0 );

画面

私は本当に行き詰まっています。私の問題をmiが解決するのを手伝ってくれることを願っています。

編集:

2番目の問題の解決策を見つけました。ブレンドを有効にしていたため、深度マップが間違っていました。

また、最初の問題の結果も良くなりましたが、シャドウマップの深度と比較するために、適切な深度で戦っています。

単純なSMでは、次のコードを使用します。

vec4 worldSpace=inverse(ViewMatrix)*vec4(pos,1);

vec4 coord=LightViewMatrix*worldSpace;
vec4 abs_coord=abs(coord);

float fs_z=-max(abs_coord.x, max(abs_coord.y, abs_coord.z));

vec4 clip=LightProjectionMatrix*vec4(0.0,0.0,fs_z,1.0);
float d=(clip.z / clip.w)*0.5+0.5; // clamp to [0..1]

ここで、posはビュースペース内の位置です。次に、以下を使用してシャドウマップから値を読み取ります。

texture(shadowMap,vec4(coord.xyz,d))

VSMでは、RG32FテクスチャのRチャネルに深度を保存します。深度値は次のように計算されます。

// VS
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;

// FS
float depth = v_position.z/v_position.w;
depth = depth * 0.5 + 0.5;

次に、ポイントライトのシェーダーで、(標準のSMのように)座標ベクトルを使用してシャドウマップから値を読み取ります。これで問題ありません。しかし、問題はこの部分にあります:

// No shadow if depth of fragment is in front
if ( moments.x <= distance)
    return 1.0;

どの座標で距離を取得する必要がありますか?シャドウマップからの深度はどの座標にありますか?それは線形でなければなりませんか?誰かが私にそれを説明できますか?私は今少し混乱しています。これを取得するために多くの方法を試しましたが、すべての結果が期待どおりではありません。

EDIT2 JarkkoLのヒントとこのチュートリアルに従って、コードを変更しました。今、私はこのコードを使用して深さを保存しています:

// VS
v_position=ModelViewMatrix*Vertex;
gl_Position=ProjectionMatrix*v_position;

// FS
const float Near = 0.1;
const float Far = 90.0; // camera far plane
const float LinearDepthConstant = 1.0 / (Far - Near);

float depth = length(v_position)*LinearDepthConstant;

そして私はそれを私がこのようにして得た値と比較します:

float dist=length( vec3(inverse(ViewMatrix)*vec4(pos,1.0)) - PointLight.position )*LinearDepthConstant; // pos is read from depth buffer and is in view space so I want invert it to world space as it was in tutorial

そしてここに結果があります:

画面3

赤い円で、立方体のマップ面の間に見える境界をマークしました。まだ何か問題があります。View Matrixを反転することで問題が発生する可能性があると思いますが、よくわかりません。


現在の進捗状況に関する情報を追加しました。
ハリー

1
現在使用している非線形深度は使用しないでください
JarkkoL 2014年

先端をありがとう。私はそれを試してみて、新しい結果で投稿を編集しました。
ハリー

アドレスモードを設定して、キューブマップをクランプします
JarkkoL

これは確かに役立ちます。私はキューブマップにGL_REPEATを設定し、それを完全に忘れていました。とにかく、vsmのシャドウは、単純なシャドウマップのようにレンダリングされません。
ハリー

回答:


1

キューブマップの継ぎ目については、エッジ全体をフィルタリングできます。

見る: glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

実際のシャドウ品質に関する限り、VSMおよびESMテクニックの全体的な利点は、可視性テストが行​​う特別な形式にあります。エッジがそれほど難しくならないように、シャドウを暗くしたり暗くしたりするための一定の係数を導入したいと思うでしょう。

ESMデータの場合、それは簡単です。

light = exp(factor * (occluder - receiver));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.