法线贴图的一点理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010468553/article/details/80622403

切线空间

假设三角形的三点为P1 P2 P3,设该三角形所对应的一个空间为(T,B,N),其中T和B构成的平面为三角形所在的平面,而T和B分别对应U和V方向。

切线空间的作用是让任何向量从Tangent Space变换到World Space。

法线贴图

有时候需要模拟一些场景,比如带有浮雕的墙面、带有花纹的茶壶等,如果使用多个三角形模拟平面的凹凸感,则计算量较大并且影响性能。研究人员发现,人眼对于物体表面的凹凸感是通过表面光照明暗变化体现的。如果可以通过一幅贴图实现光照明暗的变化,就能模拟平面表面的凹凸感。法线贴图就是为了解决这一问题而产生的。

使用法线贴图可以使用更少的顶点表现出更多的细节。

纹理坐标定义在切线空间中,U坐标对应切线空间的T轴,V坐标对应切线空间的B轴,顶点法向量N对应切线空间的N轴。

法线贴图的原理

一般3D场景中模拟光照时是在世界空间中计算的,而从法线贴图中取出的法线向量是位于切线空间的,采用法线贴图时,必须将法线向量光照相关变量变换到同一空间中才能得到正确的结果。

一般有两种方式:1、将法线向量变换到世界空间;2、将光照相关向量变换到法线向量所在的切线空间

  • 世界空间中计算:在顶点着色器中计算得到TBN矩阵, 并将其传入到片元着色器,然后把采样得到的法线用TBN矩阵从切线空间转入到世界空间。这种方式是对每个片元进行变换。
  • 切线空间中计算:在顶点着色器中用TBN矩阵的逆矩阵将所有相关的世界空间向量转化到切线空间,然后将切线空间下的光源位置、观察位置、以及顶点位置发送给片元着色器。这种方式是对每个顶点进行变换。

效率对比

在着色器执行的过程中,影响顶点着色器效率的主要因素是输入的顶点的个数。影响片元着色器效率的主要因素是传入到片元着色器中的像素的个数。一般情况下,顶点着色器中输入的顶点的数量远远低于片元着色器中输入的像素的数量,所以为了提高效率,都将在片元着色器中做的运算移到顶点着色器中去算,这样会极大的提高其效率。

一般情况下在法线贴图的计算中,都在切线空间中进行计算。

计算TBN矩阵

TBN矩阵是将任一向量从世界空间转换到切线空间下。
计算过程:

// 将向量从切线空间转到世界空间
vec3 N = normalize(mat3(Model) * in_Normal);
vec3 T = normalize(mat3(Model) * in_Tangent);
vec3 B = normalize(mat3(Model) * in_Binormal);// or vec3 B = normalize(corss(T,N));
mat3 TBN = mat3(T,B,N); 

通过这种转换,就可以把在切线空间中Normal Map中的法线转换到对应的世界空间下,与这个空间下的光线进行计算,从而能够算出对应此点的正确光照。Normal Map的法线为什么存储在“切空间”下,但它不能直接被使用。经过这样的转换,就可以与世界空间联系起来了。

不过经常用的,还不是把Normal值转换到世界空间下,而是反过来,把光线“反”转换到到切线空间下,与Normal计算出光照值。为什么?因为一个模型可能有非常多的点,对应normal map中的normal值数量必然也是巨大的,如果把每一根normal都做转换,这种计算量的成本是相当高的。但反过来,光线就那么几条,转换一次光线就能给所有切线空间下的normal使用,相对来说这种计算要“便宜”得多,所以反转光线值这种做法是更为常见的做法。

因为TBN矩阵中三个向量正交,那么它的逆矩阵就是它的转置矩阵:

// 将向量从世界空间转到切线空间
vec3 N = normalize(mat3(Model) * in_Normal);
vec3 T = normalize(mat3(Model) * in_Tangent);
vec3 B = normalize(mat3(Model) * in_Binormal);// or vec3 B = normalize(corss(T,N));
mat3 TBNinverse = inverse(mat3(T,B,N)); 

注意在片元着色器中从法线贴图中采出来的normal并不一定是归一化之后的,所以需要:

// 根据传入的法线贴图使用得到其切线空间下的法线位置
vec3 getNormalFromMap()
{
    vec3 tangentNormal = texture(normalMap, TexCoords).xyz * 2.0 - 1.0;
    return normalize(tangentNormal); 
}

猜你喜欢

转载自blog.csdn.net/u010468553/article/details/80622403
今日推荐