水面反射貼圖爲什麼會出現扭曲現象

最近在研究如何製作水面反射,當渲染好反射貼圖後,需要將反射貼圖貼到湖面上。

 

最開始,我想到最直接的辦法就是利用湖面頂點在View-Projection空間的X、Z座標值進行插值,來映射紋理,紋理座標=ViewProj空間X、Z座標 * 0.5 + 0.5。

但是發現反射圖像出現奇怪的扭曲現象,一開始以爲是紋理座標環繞設置有問題( 設置成D3DTADDRESS_WRAP或者D3DTADDRESS_CLAMP等值後發現沒有任何改觀 )。同時,又發現一個奇怪的現象:如果湖面的頂點數量越多,則扭曲程度越小。由於我一直在紋理座標尋址上轉不過彎,所以始終沒有找到解決辦法。


後來,通過參考微軟DX SDK的程序,發現這麼一段話
If D3DPTEXTURECAPS_PROJECTED is set, projected textures are computed per pixel,
so this sample will work fine with just a quad for the water model.  If it's 
not set, textures are projected per vertex rather than per pixel, so distortion
will be visible unless we use more vertices.

這段話揭示了我發現的頂點數量越多,則扭曲程度越小的現象,同時指出如果“D3DPTEXTURECAPS_PROJECTED”標誌被設置,則紋理是按照逐像素方式計算投影座標,逐像素方式可以避免扭曲的出現。

再通過查找DX的Help檔,發現這麼一段針對PixelShader中的_dw/_da/_dz/_db操作符的重要的說明:

For pixel shader version 1.4, the D3DTTFF_PROJECTED flag under D3DTSS_TEXTURETRANSFORMFLAGS
is ignored because a projective divide is accomplished by the source register modifiers 
listed previously.( 在PS1.4中,由於在紋理座標寄存器具有預先除法的功能,所以,“D3DTTFF_PROJECTED”標誌可以忽略。)

所以,結論是通過利用PS.1.4中的texcrd指令和dw操作符組合,可以解決扭曲現象。

至此,終於明白了扭曲的原因,因爲紋理座標 U = X / w * 0.5 + 0.5, V = Y / w * 0.5 + 0.5,其中:由於齊次座標中的w分量是一個變化量而非一個常數,所以U與X並非一個線性變化( 比如,X擴大2倍,U並非同時擴大2倍,因爲w也變化了 ),所以,如此通過per-Vertex方式插值出來的UV座標必然是不對的( U = x / w並非一個線性變化 ),所以,只能把X、Y、W統統送到PS中去運算纔對,而在VS中運算好後再通過硬件插值的方案是行不通的。

最終,可以很容易得到如下逐像素投影紋理座標的解決方案:
PS.1.4
texcrd r0.rg, t0_dw.xyw
...
phase
texld r0, r0
....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章