OpenGL Normal Mapping瞎折腾有感

最近在使用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 space
vec3 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

 

posted @ 2015-07-08 15:59  风过枫默  阅读(1146)  评论(0编辑  收藏  举报