標籤:
最近在使用OpenGL折騰Normal Mapping。說白了就是有一個紋理,裡面儲存的是法向量。在計算光照時,用該紋理中採樣得到的法向量來替代幾何體原法向量進行光照計算。這個儲存法向量的紋理叫做Normal Map。有時候情境資源不會直接給你Normal Map,而是給你一個Height Map,該紋理中只儲存了一個通道,是[0,1]的灰階值,可以理解成幾何體表面凹凸不平的高度,可以根據這個Height Map產生Normal Map。產生過程如下:
uniform sampler2D HeightMapTex;float h21 = textureOffset(HeightMapTex,Coord,ivec2(1,0)).r;float h01 = textureOffset(HeightMapTex,Coord,ivec2(-1,0)).r;float h10 = textureOffset(HeightMapTex,Coord,ivec2(0,-1)).r;float h12 = textureOffset(HeightMapTex,Coord,ivec2(0,1)).r;vec3 vr = normalize(vec3(2.0f,0.0f,h21 - h01));vec3 vt = normalize(vec3(0.0f,2.0f,h12 - h10));// normal in tangent spacevec3 normal = normalize(cross(vr,vt));
直接從Normal Map中採樣得到的和從Height Map中計算得到的normal向量是在tangent space之中。值得注意的是,直接從Normal Map中擷取的法向量的每個軸的值是縮放到[0,1]之後的法向量,要先還原才能使用,而從HeightMap計算得到的法相可以直接使用。縮放和還原過程如下:
// 縮放normal = normal * 0.5f + vec3(0.5f);//還原normal = normal * 2.0f - vec3(1.0f);
在進行光照計算時,我們需要光的方向LightDir,視角的方向ViewDir,和法向量n,這些向量必須在轉換到同一個座標系中進行計算。為了提高計算效率,通常我們在VertexShader中把LightDir和ViewDir變換到tangent space中,經過插值後傳遞到Fragment Shader中,然後對Normal Map進行採樣,得到tangent space的法向量之後,進行光照計算。
關於Tangent Space到Object Space的變換矩陣構建,可參考以下連結:http://www.terathon.com/code/tangent.html
OpenGL Normal Mapping瞎折騰有感