shadowmap基於的原理:sm演算法是乙個2-pass繪製演算法,第一pass從光源視點繪製場景,生成sm紋理,第2pass從視點檢視按常規方法繪製場景
從光源的位置觀察場景,這時候我們看不到的地方就是該有陰影的地方,於是可以使用比較畫素到光源距離的方法來確定某個畫素是否在陰影之中。
於是我們需要記錄我們看得到的畫素的距離值,以便做比較。
首先,建立在光源位置處的觀察座標系,這一步應該在cpu階段完成,這裡為描述方便,寫為hlsl**
這裡假設觀察方向指向原點
float3 dirz = -normalize(lightpos);
float3 up = float3(0,0,1);
float3 dirx = cross(up, dirz);
float3 diry = cross(dirz, dirx);
接下來,把場景中所有頂點變換到這個光源-觀察空間中(light-view-space)
實際中應使用矩陣進行變換,這裡直接做
float4 vpos;
vinpos.xyz-=vlightpos.xyz; //首先是平移變換
vpos.x=dot(vinpos,x_dir); //接下來是分別繞3個軸旋轉
vpos.y=dot(vinpos,y_dir);
vpos.z=dot(vinpos,z_dir);
vpos.w=1;
然後進行light-view-space空間裡的投影變換,所使用的矩陣要根據光源的特點進行改變,如fov等
最後將這時得到的結果渲染到一張紋理上,把它稱作shadowmap
這張紋理一般使用r16f,或者r32f格式,而一些整合顯示卡中或者opengl不支援這樣的格式,還可以使用整數紋理,這時需要對深度值進行壓縮。
渲染結束後,在紋理中儲存的就是在光源處能看見的畫素到光源的距離了,為了節省shader指令,可以使用距離的平方
即在浮點紋理中為 return dot(vlightvec,vlightvec);
在整數紋理中為 float fdepth=dot(vlightvec,vlightvec);
return float4( floor(fdepth) / 256.0f, frac(fdepth), frac(fdepth), frac(fdepth), frac(fdepth));
通過把frac(fdepth)同時寫入藍色和alpha通道,這樣可以節省一條指令,否則需要另乙個指令來填充這些通道
mov r2.gba r0.g //r0.g包含frac(fdepth)
vertex shader
pixel shader
到這裡準備工作就結束了,接下來就是要渲染陰影的時候了
這時回到正常觀察位置即camera位置,不再在light-view-space中觀察
將場景中每個頂點再變換到light-view-space中,這是為了要找到頂點在light-view-space中的位置,以便與紋理中的距離值做比較
將已經變換的頂點再進行投影,再將投影平面座標變換到紋理座標空間,即把範圍為[-1,1]的x,y座標變換到[0,1]的範圍中去,以便匹配相應的紋素texel
然後就是光照,既然有陰影必然有光照效果,而且應該是逐畫素光照,可以使用任何光照模型,phong,blinn或者oren-nayar
最後的距離比較決定是否為陰影,光照計算,都在畫素shader中進行
由於sm演算法基於影象空間,所以有一些缺陷,如果視點與光源位置差異很大,會產生明顯走樣,陰影邊緣處會出現明顯的階梯狀,這可以使用靠近百分比過濾pcf來改善,因為sm紋理中每個紋素texel可能不是投影到單一螢幕畫素上,紋理解析度越低,走樣越嚴重。
這裡的演算法也不適用於點光源,僅僅在聚光燈時有效,要用於點光源,則需要3d紋理,進行6次渲染,過幾天把這個做一下。
ShadowMap實現軟陰影,使用整數紋理
陰影貼圖技術一般都是使用浮點紋理,這樣有足夠的精度來儲存深度值,不過,為了在不支援浮點紋理的顯示卡上使用陰影貼圖 比如很多整合顯示卡 就只好使用整數紋理,對效果的影響不是很大.於是,使用a8r8g8b8格式的紋理來儲存深度值,將深度值壓縮進rgba通道,方法如下 float4 floor fdept...
遊戲裡的動態陰影 ShadowMap實現原理
shadowmap是比較流行的實時陰影實現方案,原理比較簡單,但真正實現起來還是會遇到很多問題的,我這裡主要記錄下實現方式 先看效果 實現原理 shadowmap技術是從燈光空間用相機渲染一張rendertexture,把深度值寫入其中所以稱之為深度圖,在把接受陰影的物體從模型空間轉換到燈光空間中,...
ShadowMap自陰影在PS 1 x下的實現方法
目前至少有兩種廣泛採用的實時陰影發生技術。一種是shadowvolume,還有一種就是shadowmap。shadowvolume基於的是幾何體演算法,通過延伸光照輪廓區域進行正反面兩次渲染在螢幕的模板緩衝區內分離出陰影區域 本站中有z fail陰影的演算法要點 shadowvolume能夠得到十分...