对于法线贴图(Normal Map) 的深入研究
前几篇文章写过有关法线贴图的内容,这次文章将讨论其原理及相关优化。回过头来看一下原来的文章真有种想删掉的感觉。。。
为什么叫法线贴图,我们知道法线(Normal)是垂直于一个面的直线,通过计算光线与这条法线的角度就可以知道与面的角度,进而可以计算出面应得到的颜色值。如果我们知道物体每个面的法线就能实现对这个物体进行光照渲染。但是一堵墙也许只有四个顶点,也就是只有一个面,它最终的渲染效果将会非常单一,假设这堵墙上有更多的砖的凹凸痕迹,我们增样实现仅用四个顶点渲染出立体感很强,细节层次感很强的这堵墙呢,答案就是 法线贴图(Normal Map)。
在法线贴图技术中,我们就是通过把墙面的每个像素的法线存储在一张纹理中,渲染的时候根据每个像素的法线确定他们的阴暗程度,而这张法线贴图是可以用photoshop软件从一张墙的纹理生成对应的法线贴图的。到此,熟悉法线贴图的朋友会对以上内容很熟悉的。
试想在渲染过程中,如果把每个法向量都转换到世界空间中跟光向量计算角度的话,那么这么多的像素法向量肯定影响性能,但是如果把光向量转换到法向量所在的空间中,岂不快哉?因此我们这里提到一个正切空间(Tangent Space)。正切空间就是法向量所在的空间,在这个坐标系中,法向量作为高度轴,类似Z轴。再找到其他的两个轴问题就会变得简单,但恰好这里是比较麻烦的。
其实我们已经知道 高度轴了,再找到一个轴,第三个轴就可以通过已知的两个轴做叉乘得到。我们要找的那个轴就叫做 正切向量(Tangent Vector)。正切向量是需要平行于法向量的平面的。
明白了这些问题就来实际的操作:
在正切空间中,三个基向量分别叫做T、B、N,T代表Tangent,B代表Binormal,N代表Normal。在Texture Space(纹理空间中),两个二维基向量分别叫做U、V,B就可以映射到纹理空间中的U,T就可以映射到纹理空间中的V。下面我们来推导一下三个向量的计算公式:
假设一个世界空间中一点pi,其纹理坐标为ui,vi,则:
pi = ui.T + vi.B
一个面有三个点p1,p2,p3,则:
p1 = u1.T + v1.B
p2 = u2.T + v2.B
p3 = u3.T + v3.B
等价形式:
p2 - p1 = (u2 - u1).T + (v2 - v1).B
p3 - p1 = (u3 - u1).T + (v3 - v1).B
最终的变换形式:
(v3 - v1).(p2 - p1) - (v2 - v1).(p3 - p1)
T = ---------------------------------------
(u2 - u1).(v3 - v1) - (v2 - v1).(u3 - u1)
(u3 - u1).(p2 - p1) - (u2 - u1).(p3 - p1)
B = ---------------------------------------
(v2 - v1).(u3 - u1) - (u2 - u1).(v3 - v1)
而N轴可以由两轴叉乘得到:
N = cross(T, B)
写成TBN矩阵的形式:
|Tx Bx Nx|
|Ty By Ny|
|Tz Bz Nz|
正切空间到世界空间转换:
VWorld = TBN VTangent = VTangentT TBNT
世界空间到正切空间转换:
VTangent = TBN-1 VWorld = VWorldT TBN-T
而刚才说过N我们是可以存储到纹理中,是已知的。所以只需要找到每个面的三个点来计算T,要知道这种计算式相当耗时间的,所以对于T或者B的计算,我们依然可以选择预先处理的办法,即存储在模型中,而大部分建模软件中的导出插件都具备这样的功能,即导出信息中包含Tangent分量。如果非要自己计算也是可以的,但是我们会遇到一个问题:
每个面即每个三角形有三个点,通过这三个点计算每个点的T向量,但是如果一个点被两个以上的面所共用,我们应该选择哪个面作为计算的依据?答案是,先分别计算每个面中该点的T向量,然后得出平均值,更严格的来讲应该加权求均值,这里的权应该怎样计算?获许是根据面的角度吧,我没有具体实现过,所以不确定。
有人说,对于xyz严格对齐的模型,时刻以人工指定其T值的,但是这样也有漏洞,比如一面对其x轴的墙超北,显示正常,同时朝南的墙也就会不正常。
通过这个方法,我得到了一个启发,我们为什么要费这么大劲甲酸TBN空间?不就是为了把光线转换到TBN空间中,然后和法向量做角度计算 确定颜色值吗?我们完全可以直接在法相量所在的空间中定义光线的方向啊!
计算TBN的部分shader代码:
float3 normal = tex2D(NormapTex,inTxr) * 2 - 1;
float3 TBNLightPos = mul(lightPos,TBN_matrix);
float DiffuseAttn = clamp(0, 1,dot(normal, TBNLightPos ));
不计算TBN直接指定光向量部分shader代码:
float3 normal = tex2D(NormapTex,inTxr) * 2 - 1;
float DiffuseAttn = clamp(0, 1,dot(normal, float3(1,-1,1)));
省去了TBN的计算,性能下降几乎为0。
但是这样做有缺点,就是不能实时更新光源位置。这里我指定的float3(1,-1,1),是比较普遍适用的,它表示光源从斜45度方向向下照射。效果还是可以接受的。
以下是未使用法线贴图效果:
以下是使用不计算TBN空间的法线贴图效果:
- 上一篇:DirectX 框架(二)-- bsp场景管理
对于法线贴图(Normal Map) 的深入研究相关推荐
- 凹凸贴图(Bump Map)实现原理以及与法线贴图(Normal Map)的区别
凹凸贴图(Bump Map)实现原理 以及与法线贴图(Normal Map)的区别 1 前言 翻译这篇教程的目的是为了帮助那些对图形渲染技术有兴趣却又苦于找不到免费中文学习资料的人.在我的身边没有任何 ...
- 置换贴图(Displacement map),凹凸贴图(Bump map)与法线贴图(Normal map)的区别
英文原文地址<Difference between Displacement , Bump and Normap Maps> By Pluralsight on August 14, 20 ...
- 非常详细易懂的法线贴图(Normal Mapping)
翻译:非常详细易懂的法线贴图(Normal Mapping) 本文翻译自: Shaders » Lesson 6: Normal Mapping 作者: Matt DesLauriers 译者: Fr ...
- 【翻译】非常详细易懂的法线贴图(Normal Mapping)
翻译:非常详细易懂的法线贴图(Normal Mapping) 本文翻译自: Shaders » Lesson 6: Normal Mapping 作者: Matt DesLauriers 译者: Fr ...
- OpenGL 法线贴图Normal Mapping
OpenGL法线贴图Normal Mapping 法线贴图Normal Mapping简介 法线贴图 切线空间 手工计算切线和副切线 切线空间法线贴图 复杂物体 最后一件事 法线贴图Normal Ma ...
- 3DShader之法线贴图(normal mapping)
凹凸贴图(bump mapping)实现的技术有几种,normal mapping属于其中的一种,这里WALL的实现在物体坐标系空间中,其他都在物体的切线空间中实现,国际惯例,上图先: 由于时间关系我 ...
- 【GTASA】圣安地列斯人物眼睛发光教程 - 法线贴图发光 Normal Map
[GTASA]人物眼睛发光教程 - 法线贴图 Normal Map 教程小记 一.展示 额,人物算是随便挑一个,但是不是任意的,视实际情况而定. 你好,折纸大师! 二.遇到的困难 实际上,我这个法线贴 ...
- 计算机图形学:详解法线与法线贴图原理
再游戏中,渲染多面是比较消耗性能的,法线贴图可以让在一张平面图片上面模拟出凹凸的效果 首先看下wiki上的解释: 在三维计算机图形学中,法线贴图(英語:Normal mapping)是一种模拟凹凸处光 ...
- 灰度图,法线贴图,置换贴图和位移贴图
查看全文 http://www.taodudu.cc/news/show-5684567.html 相关文章: OC置换可以混合.相乘.相加吗?多个置换贴图叠加 unity-shader-曲面细分与置 ...
- 深入了解3D模型相关知识(建模、材质贴图、UV、法线),置换贴图、凹凸贴图与法线贴图的区别
推荐几篇好文: 什么是3D建模?高低中模.法线贴图.低模拓扑都是啥? - 哔哩哔哩 [译文]置换贴图.凹凸贴图与法线贴图的区别 - 知乎 Difference between Displacement ...
最新文章
- TSM备份Windows数据
- pthread_cond pthread_mutex
- linux异地文件同步软件,rsync完成异地文件的同步
- 1分钟深入了解CSS3的动画属性animation
- mysql语句 查询前5个_MySQL 查询语句--------------进阶5:分组查询
- dnSpy反编译、部署调试神器
- Windows 8系统平台上应用软件安装心得
- qt5.8连接mysql代码_qt5.8如何连接mysql
- notePad++安装及json,xml格式化插件安装
- 如何在ant脚本中获得svn版本号
- Maven报错Please ensure you are using JDK 1.4 or above and not a JRE解决方法!
- GAN 网络讲解(一):生成式对抗网络(GANs)简介
- Power bi_商品销售案例分析
- 字节跳动Java金三银四解析:阿里巴巴技术专家之作
- powerdns 安装部署备忘
- java : 实现微信网页授权,超详细!
- 嵌入式知识-ARM裸机-学习笔记(2):利用GPIO来控制LED(附mkv210_image.c文件解析)
- 如何撰写出优秀的技术文档
- 3GPP TS 23501-g51 中英文对照 | 4.4.7 MSISDN-less MO SMS Service
- 线性代数[矩阵的秩]
热门文章
- Hive Privilege 分析
- 堆积木——GBQ4.0设置“统一设置安装费用”中的“高层建筑增加费”
- DPI与DFI技术分析
- 如何给代码起个好名字
- Metro风格用户界面设计原则
- 元气骑士超级科学计算机有什么用,元气骑士超级科学计算机攻略 天赋及获取方式汇总...
- lighttpd和php关系,Lighttpd是什么
- html中背景渐变斜着渐变,CSS3 斜向渐变背景
- win7-去掉快捷方式小箭头.bat
- amr java 播放_Java ME中.amr文件的语音或音频播放器