1. 程式人生 > >OpenGL es 2.0使用shadow mapping方法制作陰影時,陰影穿透實體現象的形成原因及初步應對思路

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日)鄙人已經想到了一個方法,完美的解決該問題。

附效果圖一張: