9

全方向性ポイントライトを使用しています。キューブマップテクスチャを6つのフレームバッファのカラーアタッチメントとして使用し、その各ピクセルの光からフラグメントまでの距離をエンコードするシャドウマッピングをすでに実装しました。

可能であれば、実装を次のように変更したいと思います。

  • 1)色ではなく、デプスキューブマップテクスチャをフレームバッファのデプスバッファにアタッチします。
  • 2)深さのみをレンダリングし、このパスには色を書き込まないでください
  • 3)メインパスで、キューブマップテクスチャから深度を読み取り、それを距離に変換して、現在のフラグメントがライトによって遮られているかどうかを確認します。

私の問題は、キューブマップからの深度値を距離に戻すときに発生します。光からフラグメントへのベクトル(世界空間)を使用して、キューブマップの深度値を取得します。この時点では、6つの面のどれが使用されているのか、またどの2Dテクスチャ座標が私が読んでいる深度値と一致するのかわかりません。次に、その深度値を距離に変換するにはどうすればよいですか?

これが私のコードの抜粋です。

深さのテクスチャ:

glGenTextures(1, &TextureHandle);
glBindTexture(GL_TEXTURE_CUBE_MAP, TextureHandle);
for (int i = 0; i < 6; ++i)
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT,
              Width, Height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

フレームバッファの構築:

for (int i = 0; i < 6; ++i)
{
    glGenFramebuffers(1, &FBO->FrameBufferID);
    glBindFramebuffer(GL_FRAMEBUFFER, FBO->FrameBufferID);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
            GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, TextureHandle, 0);
    glDrawBuffer(GL_NONE);
}

コードを実現するために作成しようとしているフラグメントシェーダーの一部:

float ComputeShadowFactor(samplerCubeShadow ShadowCubeMap, vec3 VertToLightWS)
{   
    float ShadowVec = texture(ShadowCubeMap, vec4(VertToLightWS, 1.0));
    ShadowVec = DepthValueToDistance(ShadowVec);
    if (ShadowVec * ShadowVec > dot(VertToLightWS, VertToLightWS))
        return 1.0;

    return 0.0;
}

DepthValueToDistance関数が私の実際の問題です。

4

2 に答える 2

11

したがって、解決策は、キューブマップから読み取った深度を距離に変換するのではなく、光からフラグメントへのベクトルを深度値に変換することでした。

変更されたシェーダーコードは次のとおりです。

float VectorToDepthValue(vec3 Vec)
{
    vec3 AbsVec = abs(Vec);
    float LocalZcomp = max(AbsVec.x, max(AbsVec.y, AbsVec.z));

    const float f = 2048.0;
    const float n = 1.0;
    float NormZComp = (f+n) / (f-n) - (2*f*n)/(f-n)/LocalZcomp;
    return (NormZComp + 1.0) * 0.5;
}

float ComputeShadowFactor(samplerCubeShadow ShadowCubeMap, vec3 VertToLightWS)
{   
    float ShadowVec = texture(ShadowCubeMap, vec4(VertToLightWS, 1.0));
    if (ShadowVec + 0.0001 > VectorToDepthValue(VertToLightWS))
        return 1.0;

    return 0.0;
}

説明VectorToDepthValue(vec3 Vec)

LocalZCompVecキューブマップの一致する錐台に与えられたもののZコンポーネントになるものに対応します。これは実際にはの最大のコンポーネントですVec(たとえば、Vec.yが最大のコンポーネントである場合、キューブマップのY +またはY-面のいずれかを調べます)。

このウィキペディアの記事を見ると、直後の数学が理解できます(理解のために正式な形式で保持しました)。これは、LocalZCompを正規化されたZ値([-1..1]の間)に変換してからマップします。デプスバッファ値の実際の範囲である[0..1]に入れます。(変更しなかったと仮定します)。nfは、キューブマップの生成に使用される錐台の近距離と遠距離の値です。

ComputeShadowFactor次に、キューブマップの深度値をフラグメントからライトへのベクトル(ここで名前を付けた)から計算された深度値と比較しVertToLightWS、小さな深度バイアス(質問では欠落していた)を追加し、フラグメントがない場合は1を返します。光に遮られた。

于 2012-05-28T19:24:45.630 に答える
5

導出に関する詳細を追加したいと思います。

V光からフラグメントへの方向ベクトルとします。

ベンリッツがすでに述べたように、それぞれの立方体側錐台/「目の空間」のZ値は、 Vの成分の絶対値の最大値をとることによって計算できます。

Z = max(abs(V.x),abs(V.y),abs(V.z))

次に、正確には、Zを否定する必要があります。これは、OpenGLでは、負のZ軸が画面/ビュー錐台を指しているためです。

次に、その-Zのデプスバッファの「互換性のある」値を取得します。

OpenGLパースペクティブマトリックスを見て...

http://www.songho.ca/opengl/files/gl_projectionmatrix_eq16.png

http://i.stack.imgur.com/mN7ke.png(バックアップリンク)

...その行列を乗算した同種のベクトルの場合、結果のz値はベクトルのxおよびy成分から完全に独立していることがわかります。

したがって、この行列に同次ベクトル(0,0、 -Z 、1)を単純に乗算すると、ベクトル(コンポーネント)が得られます。

x = 0
y = 0
z = (-Z * -(f+n) / (f-n)) + (-2*f*n / (f-n))
w = Z

次に、パースペクティブ除算を実行する必要があるため、zをw(Z)で除算すると、次のようになります。

z' = (f+n) / (f-n) - 2*f*n / (Z* (f-n))

このz'はOpenGLの正規化されたデバイス座標(NDC)範囲[-1,1]にあり、[0,1]の深度バッファー互換範囲に変換する必要があります。

z_depth_buffer_compatible = (z' + 1.0) * 0.5

その他の注意事項:

  • (f + n)、(fn)、および(f * n)の結果をシェーダーユニフォームとしてアップロードして、計算を節約することは理にかなっています。

  • シャドウキューブマップは通常、ワールドスペースで軸に沿って配置されるため、 Vはワールドスペースにある必要があります。したがって、「max(abs(Vx)、abs(Vy)、abs(Vz)) 」-パーツは、 Vがワールドスペースである場合にのみ機能します。方向ベクトル。

于 2014-05-03T14:09:04.387 に答える