凹凸映射
凹凸映射就是通过一些特殊的纹理来增加信息量,通过这些附加信息来修改模型表面的法线
有两种实现方法:
- 高度纹理
- 法线纹理
法线纹理
法线纹理直接存储了表面法线,本质就是将法线转换成了颜色存储了起来,算是一种数据可视化了
值得注意的是法线纹理中的法线和模型中法线一点关系都没有,就如球体的法线都是过球心向外的射线,而法线纹理可以由你自己决定(因为是额外的调整信息)
法线的 xyz
分量都在 [-1,1] 之间,而像素的(颜色)分量在 [0,1] 之间
所以存储时需要简单的映射
p
i
x
e
l
=
n
o
r
m
a
l
+
1
2
pixel=\frac{normal+1}{2}
pixel=2normal+1
从法线纹理读取数据后,逆映射获取法线
n
o
m
a
l
=
2
∗
p
i
x
e
l
−
1
nomal = 2*pixel-1
nomal=2∗pixel−1
法线纹理分为两种:模型空间下的法线纹理、切线空间下的法线纹理
模型空间下的法线纹理
模型空间下的法线纹理五颜六色,所有法线共用一个模型坐标系,朝各个方向的法线都有,映射后颜色差异极大

切线空间下的法线纹理
切线空间是对每个顶点来说的
坐标原点是顶点本身,z 轴是顶点本身(即模型)的法线方向,x 轴是顶点的切线方向,y 轴(又叫副切线)可由其他两轴叉积出来,副切线的方向由切线的w
分量决定
如果顶点没有凹凸效果,即当前顶点在切线空间中的法线就是 z 轴本身(0, 0, 1)
,映射后的为RGB(0.5, 0.5, 1) 浅蓝色
由于凹凸效果一般只要对原法线做微小的变化,所以切线空间下的法线纹理一般都有大面积的蓝色,如下图:

两种法线纹理的优缺点
模型空间:更直观,突变较少,不可压缩
切线空间:可压缩(z
可由xy
推导),
一般使用切线空间下的法线纹理
切线空间下对切线空间的法线纹理的使用
模型空间到切线空间的转换
将光源方向和视角方向转换至切线空间计算
假
设
切
线
空
间
下
的
矢
量
坐
标
(
a
,
b
,
c
,
0
)
即
a
x
t
+
b
y
t
+
c
z
t
每
个
轴
由
模
型
空
间
下
的
x
y
z
定
义
的
a
(
M
o
d
e
l
t
a
n
g
e
n
t
.
x
y
z
)
+
b
(
M
o
d
e
l
b
i
n
o
r
m
a
l
.
x
y
z
)
+
c
(
M
o
d
e
l
n
o
r
m
a
l
.
x
y
z
)
(
x
0
,
y
0
,
z
0
)
=
(
a
+
b
+
c
)
x
+
(
a
+
b
+
c
)
.
y
+
(
a
+
b
+
c
)
.
z
从
切
线
空
间
到
模
型
空
间
的
矩
阵
[
∣
∣
∣
t
a
n
g
e
n
t
.
x
y
z
b
i
n
o
r
m
a
l
.
x
y
z
n
o
r
m
a
l
.
x
y
z
∣
∣
∣
]
假设切线空间下的矢量坐标(a,b,c,0)\\ 即ax_t+by_t+cz_t\\ 每个轴由模型空间下的xyz定义的\\ a( Model_{tangent}.xyz)+b( Model_{binormal}.xyz)+c( Model_{normal}.xyz)\\ (x_0,y_0,z_0)=(a+b+c)x+(a+b+c).y+(a+b+c).z\\ 从切线空间到模型空间的矩阵 \left[ \begin{matrix} |&|&|\\tangent.xyz&binormal.xyz&normal.xyz\\|&|&|\\ \end{matrix} \right]
假设切线空间下的矢量坐标(a,b,c,0)即axt+byt+czt每个轴由模型空间下的xyz定义的a(Modeltangent.xyz)+b(Modelbinormal.xyz)+c(Modelnormal.xyz)(x0,y0,z0)=(a+b+c)x+(a+b+c).y+(a+b+c).z从切线空间到模型空间的矩阵⎣⎡∣tangent.xyz∣∣binormal.xyz∣∣normal.xyz∣⎦⎤
模
型
空
间
到
切
线
空
间
的
矩
阵
就
是
上
面
的
逆
矩
阵
[
—
—
t
e
n
g
e
n
t
.
x
y
z
—
—
—
—
b
i
n
o
r
m
a
l
.
x
y
z
—
—
—
—
n
o
r
m
a
l
.
x
y
z
—
—
]
模型空间到切线空间的矩阵就是上面的逆矩阵\\ \left[ \begin{matrix} ——tengent.xyz——\\——binormal.xyz——\\——normal.xyz——\\ \end{matrix} \right]
模型空间到切线空间的矩阵就是上面的逆矩阵⎣⎡——tengent.xyz————binormal.xyz————normal.xyz——⎦⎤
推导 z 值
由于法线都是单位向量,利用三维的勾股定理可求出 z
举个例子 假设读取到上面的RGB(0.5, 0.5 ,1)
如果有压缩就是不存储 z,即读取到(0.5, 0.5)
先 逆 映 射 n o r m a l = p i x e l ∗ 2 − 1 = ( 0 , 0 ) / / x 2 + y 2 = ( x , y ) ⋅ ( x , y ) z = s q r t ( 1.0 − d o t ( n o r m a l . x y , n o r m a l . x y ) ) = 1.0 n o r m a l ( 0 , 0 , 1.0 ) 先逆映射 \\ normal=pixel*2-1=(0, 0) \\ //x^2+y^2=(x, y)·(x,y)\\ z=sqrt(1.0-dot(normal.xy, normal.xy))=1.0\\ normal(0,0,1.0) 先逆映射normal=pixel∗2−1=(0,0)//x2+y2=(x,y)⋅(x,y)z=sqrt(1.0−dot(normal.xy,normal.xy))=1.0normal(0,0,1.0)
到这里就已经获取了切线空间下所有光照计算有关的矢量了
视差贴图
法线贴图仍然无法解决一些问题,例如当物体的凹凸部分存在遮挡的情况下,由于法线贴图只是扰动了法线,所以所有顶点都会参被渲染,所以有些时候我们会看到突起的背面,所以法线贴图产生的凹凸感往往不是很强烈。
所以可以利用一张高度图,实现视差贴图
原理很简单,通过视线方向和高度图计算当前位置应该出现的纹理,
一种更精确的方法是陡峭视差贴图,可以根据细分程度控制精确度