OpenGL学习笔记(法线贴图、视差贴图)
目录
- 法线贴图
- 切线空间
- 视差贴图
GitHub主页:https://github.com/sdpyy1
OpenGL学习仓库:https://github.com/sdpyy1/CppLearn/tree/main/OpenGLtree/main/OpenGL):https://github.com/sdpyy1/CppLearn/tree/main/OpenGL
法线贴图
用普通的纹理看起来是平的,通过修改每个像素的法线,得到更好的效果。这种每个fragment使用各自的法线,替代一个面上所有fragment使用同一个法线的技术叫做法线贴图(normal mapping)或凹凸贴图(bump mapping)。应用到砖墙上,效果像这样:
这张法线贴图颜色偏蓝,是因为砖头表面的法线是(0,0,1),缝隙偏绿是因为缝隙的法线为(0,1,0)
uniform sampler2D normalMap; void main()
{ // 从法线贴图范围[0,1]获取法线normal = texture(normalMap, fs_in.TexCoords).rgb;// 将法线向量转换为范围[-1,1]normal = normalize(normal * 2.0 - 1.0); [...]// 像往常那样处理光照
}
但是这样就有问题了,如果你修改了物体的朝向,那法线贴图的数据将无法再起作用,因为它记录的是绝对值,然而物体的移动也会伴随着法线的移动
切线空间
切线空间是位于三角形表面之上的空间:法线就是正z方向,切线是x,副切线为y。切线空间是相对于单个三角形的局部坐标系,所以三角形无论如何旋转,正z方向都是法线方向。但X轴(切线)和Y轴(副切线)的方向可能因纹理坐标或模型定义而变化
通过左乘一个TBN矩阵,让法线从切线空间转到全局空间中
N是法线方向,T是切线方向,B是副切线方向。
切线和副切线与UV方向对齐
我们可以用一个三角形的顶点和纹理坐标(因为纹理坐标和切线向量在同一空间中)计算出切线和副切线你就已经部分地达到目的了,用切线空间的切线左乘这个TBN矩阵,就得到了可以直接使用的切线。
视差贴图
它对根据储存在纹理中的几何信息对顶点进行位移或偏移。一种实现的方式是比如有1000个顶点,根据纹理中的数据对平面特定区域的顶点的高度进行位移。这样的每个纹理像素包含了高度值纹理叫做高度贴图。一张简单的砖块表面的高度贴图如下所示:
高度贴图中存储的是每个点的高度值,每个顶点取高度贴图的一个位置值来进行偏移,从而实现凹凸不平的效果,但是显著增加了计算量(每个顶点都得实实在在进行位移)
涉茶贴图不需要额外的顶点数据来表达深度,它像法线贴图一样采用一种聪明的手段欺骗用户的眼睛。视差贴图背后的思想是修改UV坐标使一个fragment的表面看起来比实际的更高或者更低。为了理解它如何工作,看看下面砖块表面的图片:
红线代表高度贴图代表的高度,当视线在看A点时,实际上B点的高度会把A点挡住,所以使用点B的纹理而不是点A。
计算方法是:取A点的高度旋转到观察方向,再投影到平面上,就取投影终点位置的UV坐标B当作A点的UV坐标
这个技巧在大多数时候都没问题,但点B是粗略估算得到的。当表面的高度变化很快的时候,看起来就不会真实,因为向量P¯最终不会和B接近,就像下图这样
视差贴图的另一个问题是,当表面被任意旋转以后很难指出从P¯获取哪一个坐标,在切线空间中完成更好