天天看點

Irrlicht引擎Shader渲染的BUG

----------修改2----------------------------------------------------------------------------------------------------------------

丢人了, 回頭一看原來的了解還是不夠完整。

如果在視圖空間計算光照等, 一般都會将法線變換到視圖空間。想當然的做法是用視圖矩陣來變換法線,這麼做隻有在物體沒有縮放或是一緻性縮放的情況下才是正确的。若是物體有非一緻性縮放(uniform-scale),變換出來的法線方向是不正确的。如下圖。

Irrlicht引擎Shader渲染的BUG
Irrlicht引擎Shader渲染的BUG

這也是gl_NormalMatrix這個矩陣的作用,法線的變換需要使用的是視圖矩陣的逆的轉置,具體的推導可參見http://blog.csdn.net/racehorse/article/details/6664775

Irrlicht引擎Shader渲染的BUG

OpenGL計算出的這個矩陣就儲存在gl_NormalMatrix裡。

如果在世界空間裡計算光照  變換法線要用的矩陣就是世界矩陣逆的轉置了。

那麼再回到正題, 為什麼之前的 ”世界矩陣的逆矩陣“ 改成  “世界矩陣”   就正确了? 就是因為沒有縮放

Irrlicht引擎Shader渲染的BUG

是以在Example10裡正确的做法是  先取出世界矩陣  求逆  求轉置  再傳到 shader 裡,  如此  大功告成!

----------修改----------------------------------------------------------------------------------------------------------------

最近才發現這個BUG的原因:

vexter shader裡在将法線變換到世界坐标系時,乘的是世界矩陣的逆矩陣,導緻法線變換錯誤。

隻需将逆世界矩陣改成世界矩陣就可以了

----------原文-------------------------------------------------------------------------------------------------------------------------------

Irrlicht的SDK裡帶有一系列Example,第10個是關于Shader的。細看了一下,發現有些問題。

我先簡單說一下這個demo,它在場景中(sceneMgr)添加了三個CubeBox,一個沒有shader,預設使用材質video::EMT_SOLID,另外兩個使用了shader,但材質類型分别是video::EMT_SOLID和video::EMT_TRANSPARENT_ADD_COLOR,然後都加了Y方向的自身旋轉 。

它使用IShaderConstantSetCallBack來給shader的參數指派, demo裡使用的shader也很簡單。

uniform mat4 mWorldViewProj;
uniform mat4 mInvWorld;
uniform mat4 mTransWorld;
uniform vec3 mLightPos;
uniform vec4 mLightColor;

void main(void)
{
	gl_Position = mWorldViewProj * gl_Vertex;
	
	vec4 normal = vec4(gl_Normal, 0.0);
	normal = mInvWorld * normal;
	normal = normalize(normal);
	
	vec4 worldpos = gl_Vertex * mTransWorld;
	
	vec4 lightVector = worldpos - vec4(mLightPos,1.0);
	lightVector = normalize(lightVector);
	
	float tmp2 = dot(-lightVector, normal);
	
	vec4 tmp = mLightColor * tmp2;
	gl_FrontColor = gl_BackColor = vec4(tmp.x, tmp.y, tmp.z, 0.0);
	
	gl_TexCoord[0] = gl_MultiTexCoord0;
}
           
uniform sampler2D myTexture;

void main (void)
{
    vec4 col = texture2D(myTexture, vec2(gl_TexCoord[0]));
    col *= gl_Color;
    gl_FragColor = col * 4.0;
}
           

它使用目前camera的位置為mLightPos,然後根據法線算一個點乘的值做為受光的強度因子,這樣當運作時,随着BOX的旋轉,面對鏡頭的面都是受光的(亮的)。

為了測試結果,我把三個BOX都去了,換成了一個Spere, 使用shader,材質是video::EMT_SOLID,依然有Y方向旋轉(從右向左),并且将shader裡的貼圖顔色去了,隻使用光的顔色。

Irrlicht引擎Shader渲染的BUG
Irrlicht引擎Shader渲染的BUG

可以看到竟然出現了半黑和全黑的情況,官方demo裡那兩個使用了shader的cubebox,旋轉時也會“黑”

Irrlicht引擎Shader渲染的BUG
Irrlicht引擎Shader渲染的BUG

接下來,我将spere的旋轉去掉,然後在camera上加了一個“FlyCircle”的旋轉,讓其圍繞場景(0,0,0)點運動,終于出現了想像中的結果,“面向鏡頭的始終是亮的”。

難道在Shader計算時 “gl_Normal"的值不對嗎?

繼續閱讀