OpenGL es 2.0使用shadow mapping方法制作陰影時,陰影穿透實體現象的形成原因及初步應對思路
在本人開發手機遊戲《KF坦克》時,發現了一個問題,具體如下:
一、開發環境描述:
window7+adt-bundle-windows-x86_64-20131030
純java程式設計,OpenGL es 版本為2.0
二、問題描述:
使用shadow mapping方法產生陰影,陰影會穿透實體。具體見陰影穿透實體效果圖。
此時,使用glsl部分程式碼為程式碼為(該程式碼為fragment程式碼):
void main()
{
.
.
.
// Shadow
float shadow = 1.0;
//if the fragment is not behind light view frustum
if (vShadowCoord.w > 0.0) {
shadow = shadowPCF();
//scale 0.0-1.0 to 0.2-1.0
//otherways everything in shadow would be black
shadow = (shadow * 0.8) + 0.2;
}
// Final output color with shadow and lighting
gl_FragColor = (vColor * (diffuseComponent + ambientComponent) * shadow);
}
產生該現象的原因為:
當繪製背陰面的牆面時,系統會發現該牆面的一部分在陰影中,故而顯示出陰影。這個問題其實和自陰影的問題一樣。但問題是,不能使用消除自陰影的方式消除它,因為該陰影就是由背光面產生的。
解決思路:
仔細觀察遊戲場景,發現:背影的牆面一定不能出現陰影,而陰影一定只會出現在向陽面中,在分析一下背陰面的特徵,其diffuseComponent一定為0。這時,鄙人產生了一個解決該問題的想法,既然我們可以確定背陰面的gl_FragColor,那麼,我們將陰影的gl_FragColor的值設定的與背陰面相同不就可以消除背陰面的陰影了!所以鄙人將fragment的glsl語言修改如下:
void main()
{
.
.
.
float shadow = 1.0;
if (vShadowCoord.w > 0.0)
{
shadow = shadowSimple();
}
if (shadow > 0.0)
gl_FragColor = texture2D(u_TextureUnit,v_TextureCoordinates) * (diffuseComponent + ambientComponent +specular());
else
gl_FragColor = texture2D(u_TextureUnit,v_TextureCoordinates) * (ambientComponent+specular());
}
仔細分析一下該程式碼:
背陰面的gl_FragColor=texture2D(u_TextureUnit,v_TextureCoordinates) * (0+ ambientComponent +specular());
陰影的gl_FragColor=texture2D(u_TextureUnit,v_TextureCoordinates) * (ambientComponent +specular());
此時,背陰面與陰影的gl_FragColor相同,則陰影自然不會出現了。效果圖如下:
如上圖所示,背陰面的牆上沒有了陰影,但問題也來了。
因為在陰影的表示式中沒有了diffuseComponent 分量,所以,在陰影中的物體失去了光照效果,悲劇啊!!!所以該方法也有副作用。
先將上述問題釋出,希望與有志者共同討論,以求進步,歡迎留言,謝謝。
以上文字釋出於2016年3月7日,現在(2016年3月10日)鄙人已經想到了一個方法,完美的解決該問題。
附效果圖一張: