2011-07-20 18 views
3

私はOpenGLでシャドーマッピングを行っています。光の視点からシーンの奥行きをレンダリングするフレームバッファオブジェクトを作成しました。OpenGL - フレームバッファの深さテクスチャと色の濃さテクスチャ

glBindRenderbuffer(GL_RENDERBUFFER, color_buffer); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_buffer); 

glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_buffer); 

glGenTextures(1, &color_texture); 
glBindTexture(GL_TEXTURE_2D, color_texture); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0); 

glGenTextures(1, &depth_texture); 
glBindTexture(GL_TEXTURE_2D, depth_texture); 
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_texture, 0); 

これは、光のパースペクティブからシーンを通常どおりにレンダリングします。唯一の追加は、カスタムシェイダーを使ってシーンの深さを "color_texture"にレンダリングすることです。

varying vec4 screen_position; 

void main() 
{ 
    screen_position = gl_ModelViewProjectionMatrix * gl_Vertex; 
    gl_Position = screen_position; 
} 

-------------- 

varying vec4 screen_position; 

void main() 
{ 
    float depth = screen_position.z/screen_position.w; 
    gl_FragColor = vec4(depth, depth, depth, 1.0); 
} 

フルスクリーンクワッドを使用して、これらの2つのテクスチャ「color_texture」と「depth_texture」を画面に書き込むことができます。どちらも確かに奥行きマップであり、正確に見えます。今、奇妙なビットです。

オブジェクトの影を実際にレンダリングするときは、「color_texture」の奥行きはうまくいきますが、サンプリング「depth_texture」に切り替えると、奥行きはあるスケールと一定の違いによって異なります。

このサンプリングされた深さにファジーファクターの数字を追加したとき、私はそれをうまく機能させることができましたが、それは本当に難しく、ちょうど恐ろしい感じでした。

私は本当に何が間違っているのかを知ることはできません。技術的には、2つのテクスチャはサンプリング時に同一でなければなりません。私はRGBの精度のために "color_texture"を使うことができません。私は本当に切り替える必要がありますが、私の人生は深さのテクスチャが別の価値を与える理由を理解することができません。

以前は何度かシャドーマッピングをプログラムしていましたが、それは私には新しい概念ではありません。

誰もがこれにどのような光を当てることができますか?

答えて

6

シェーダに問題があります。まず、screen_positionはスクリーン位置ではありません。クリップ空間の頂点の位置です。画面のスペースはモニタに相対的なものになりますので、ウィンドウを移動すると画面のスペースが変わります。あなたは決してスクリーンスペースの位置を得ることはできません。 OpenGLはウインドウスペース(ウインドウの位置を基準にして)までしか移動しません。

第二に、これは:

float depth = screen_position.z/screen_position.w; 

深さを計算しません。 [-1,1]の範囲の正規化装置座標(NDC)空間Z位置を計算します。 Depthはウィンドウスペースの値で、NDC空間値が(glViewportとglDepthRangeで指定された)ビューポート変換で変換された後に来ます。この変換は深さを[0、1]の範囲に置きます。

第3に、これはすべて手作業です。あなたにGLSLにそれをさせてください:

void main() 
{ 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
} 

-------------- 

void main() 
{ 
    gl_FragColor = vec4(gl_FragCoord.zzz, 1.0); 
} 

参照してください?ずっといい。今

それが正常に動作しますが、私は「depth_texture」をサンプリングに切り替えると、深さはいくつかの規模によって異なると一部で、実際に「color_texture」深さをサンプリングしたオブジェクトに影をレンダリングしています定数。

もちろんです。それは深さがNDCのZ値であると信じたからです。 OpenGLは実際のウィンドウスペースのZ値を深度として書き込みます。ですから、ウィンドウスペースで作業する必要があります。 OpenGLはこれをより簡単にするためにはuniforms to your fragment shaderを提供するのに十分です。これらのユニフォームを使用して、NDCスペースZ値をウィンドウスペースZ値に変換することができます。

+0

偉大な答えをありがとう! NDCのZ値とウィンドウの深さとの違いを説明できますか?前面と近位のクリッププレーンは既に投影行列に供給されているので、確かに奥行きの範囲は違いがありませんか? [-1,1]を[0,1]にマッピングするだけですか、または浮動小数点精度のスケーリングを行うのですか?私はどのようにxとyの座標をglViewportでウィンドウ空間に拡大することができるのか理解しています。おそらく私は深みのあるものを見逃しています。 いずれにせよ多くの感謝、私は今それを動作させることができると信じています。 –

+0

@Daniel:奥行き範囲は、NDC空間からZ位置のウィンドウ空間へのマッピングを定義します。だから 'glDepthRange(0.0、0.5)'を使うと、[0、0.5]の範囲の奥行値しか得られません。したがって、シャドウマップの比較を行う際には、奥行き範囲を尊重する必要があります。 –

関連する問題