天天看点

Bump map 和 Tangent space(切线空间)

在众多3d技术中,bump map算是一个重要而普遍的技术了。原本看了< Real-Time Rendering>只有很浅的了解,由于没有实际应用也就没多少体会。现在看到《Beginning Direct3D Game Programming》,其中有这样的实例,就研究了大约一天的时间。终于算是心中舒服很多。怕自己遗忘,特写下此篇,好让自己以后再拾起来,温故温故。

首先为什么要用bump map呢? 那是因为如果要实现高质量的渲染画面,模型必须细致,但是太细致的模型的需要增加大量顶点,这样顶点牵连的计算就急剧增多。而在3d游戏中,为了保持恒定帧率,一定要有个办法能让高质量的渲染得以实现,同时又不需要太大的计算。因此bump map出现了,只用一张图片就可以在粗糙的模型上制造出接近真实细致模型的效果。

Bum map可以在一个完全扁平的面上制造出凹凸感的技术但只需要一张纹理图片。

物体表面反射的颜色对人们的凹凸感有重要作用。如果一个扁平地方的颜色能像一个真正凹陷地方的颜色一样,并且能随着光线变化而产生与真正凹陷地方一样的效果,那么即使这个地方在物理上是扁平的,但人们看起来还是会以为是凹陷的。

而如何让扁平的地方让凹陷地方一样呢?寻根究底,所有的物体产生的颜色在3d游戏中都是通过着色方程计算的。而着色方程中让颜色随着光线角度变化而变化的重要参数就是法线(垂直于平面的直线),所以法线在着色方程中起着举足轻重的作用。我们只要能让扁平地方的法线像凹陷地方的法线一样就可以实现凹凸感了。这就是我猜想的bump map的一种由来方式,哈哈。

所以我们需要在bump map中存放物体表面的法线。通过纹理坐标去访问这个bump纹理,其中的颜色数值就是我们想要的法线,这样就可以平面能产生凹凸感。

但存放法线,必须要确定法线所在的坐标系。要不然一个没有参考系的坐标没有任何意义。

在bump map中采用的Tangent space(切线空间)。

为什么不采用局部空间(局部坐标系)呢?

如果采用局部坐标系,在各种各样的情况中工作效果不好。例如,如果我们制造一个树的模型,我们采用局部坐标记录法线。那么我们的树如果在局部坐标转动一下,那么刚才记录的法线就不适合了,必须将记录的发现和树一起转动后才能应用。再者如果这颗树能随风摆动,那么局部坐标系下的法线就会与摆动后的树的法线有一定的偏差,或者直接是错误的。所以只有让每个点都要有自己的坐标系,才能适应这些变动而不产生错误。这样只要建立好其他坐标系到这个坐标系的转换矩阵,那么无论模型怎么变都没问题。所以我们需要Tangent space。

那么Tangent space切线空间是什么呢?

切线空间也是一个3d空间。三角形网格的每个三角形所在的平面有一个UV坐标系(纹理坐标系),而T,B所构建的平面就是每个三角形所在的平面。切线空间中的T(tangent),B(Bitangent)就与这个U,V方向一致。而 N = ( T X B )。这个比较抽象,很难想象。下面一些数学表述更严格的说明的在局部坐标系中的Tangent Space的3的基础向量.(即 T,B,N三个向量是基于局部坐标的)

三角形三个坐标p0(u0, v0), p1(u1,v1), p2(u2,v2).

三角形中的每个点 p(u,v)可以用如下公式表达:

p - p0 = ( u - u0 ) * T + ( v - v0 ) * B;

但通过方程可以直接计算:

p0 - p1 = ( u0 - u1 )  * T + ( v0 - v1 ) * B;

p0 - p2 = ( u0 - u2 ) * T + ( v0 - v2 ) * B;

通过上述方程可以计算出T,B,间接的可以计算出N。

计算出构成Tangent space的三个基础向量后,我们就可以构建局部坐标到切线空间的转换矩阵.

matLocalToTangent =

{

 T.x, B.x, N.x ,

T.y, B.y,  N.y,

T.z, B.z,  N.z,

};

比较好的理解方法,拿局部坐标系到世界坐标系转换的方法。

当某模型在世界坐标系中的的朝向是这三个基础向量

( 1, 0, 0 ),

( 0, 1, 0 ),

( 0, 0, 1 ).

当将模型绕z旋转后45度后,三个基础向量

( cos45, sin45, 0 )

( -sin45, cos45, 0 )

(0, 0, 1)

因为起初的三个向量构成矩阵是单位矩阵,旋转后三个向量构成的矩阵就直接记录的旋转矩阵。

当将这个旋转矩阵求逆,由于旋转矩阵的正交矩阵,所以逆矩阵等于转置矩阵。所以由世界坐标到局部坐标的变化就成了下面的矩阵

( cos45, -sin45, 0 )

( sin45, cos45, 0 )

(0, 0, 1).

就这样吧,随便写的。

继续阅读