文档章节

对于法线贴图的深入研究

FreeBlues
 FreeBlues
发布于 2016/07/23 23:18
字数 1483
阅读 74
收藏 0

对于法线贴图的深入研究

原文地址: http://blog.csdn.net/debugconsole/article/details/18990153

正文

前几篇文章写过有关法线贴图的内容,这次文章将讨论其原理及相关优化。回过头来看一下原来的文章真有种想删掉的感觉。。。

为什么叫法线贴图,我们知道法线(Normal)是垂直于一个面的直线,通过计算光线与这条法线的角度就可以知道与面的角度,进而可以计算出面应得到的颜色值。如果我们知道物体每个面的法线就能实现对这个物体进行光照渲染。但是一堵墙也许只有四个顶点,也就是只有一个面,它最终的渲染效果将会非常单一,假设这堵墙上有更多的砖的凹凸痕迹,我们增样实现仅用四个顶点渲染出立体感很强,细节层次感很强的这堵墙呢,答案就是法线贴图(Normal Map)。

法线贴图技术中,我们就是通过把墙面的每个像素的法线存储在一张纹理中,渲染的时候根据每个像素的法线确定他们的阴暗程度,而这张法线贴图是可以用photoshop软件从一张墙的纹理生成对应的法线贴图的。到此,熟悉法线贴图的朋友会对以上内容很熟悉的。

试想在渲染过程中,如果把每个法向量都转换到世界空间中跟光向量计算角度的话,那么这么多的像素法向量肯定影响性能,但是如果把光向量转换到法向量所在的空间中,岂不快哉?因此我们这里提到一个正切空间Tangent Space)。正切空间就是法向量所在的空间,在这个坐标系中,法向量作为高度轴,类似Z轴。再找到其他的两个轴问题就会变得简单,但恰好这里是比较麻烦的。

其实我们已经知道高度轴了,再找到一个轴,第三个轴就可以通过已知的两个轴做叉乘得到。我们要找的那个轴就叫做 正切向量Tangent Vector)。正切向量是需要平行于法向量的平面的。

明白了这些问题就来实际的操作:

正切空间中,三个基向量分别叫做TBNT代表Tangent,B代表Binormal,N代表Normal。在Texture Space纹理空间中), 两个二维基向量分别叫做UVT就可以映射到纹理空间中的UB就可以映射到纹理空间中的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空间的法线贴图效果:

输入图片说明

本文转载自:http://blog.csdn.net/debugconsole/article/details/18990153

共有 人打赏支持
FreeBlues
粉丝 98
博文 280
码字总数 493678
作品 0
其它
程序员
私信 提问
学界 | 用GAN自动生成法线贴图,让图形设计更轻松

  选自arXiv   作者:Wanchao Su、Dong Du、Xin Yang、Shizhe Zhou、Hongbo Fu   机器之心编译   参与:Panda      如果设计工具能根据简单的素描自动生成法线贴图,那将能够为图...

机器之心
2018/04/20
0
0
Substance Painter 烘焙法线贴图:使用Cage处理UV接缝

这里SP版本为2017.3;Maya版本为2018.1。 1,准备好高模、低模、Cage 这里以Maya为例。 高模 硬边低模 低模UV,因为全部是硬边,这里全部切开 平均法线的Cage Cage的制作方式: 这里的Cage是...

玄冬Wong
2017/12/09
0
0
【Unity3D技术文档翻译】第2.3.3.6篇 法线贴图(凹凸贴图)

上一章:【Unity3D技术文档翻译】第2.3.3.5篇 平滑度(Smoothness) 本章原文所在章节:【Unity Manual】→【Graphics】→【Graphics Overview】→【Materials, Shaders & Textures】→【Sta...

何三思
2018/06/24
0
0
【《Unity Shader入门精要》 提炼总结】(十)第十章·法线贴图概念&切线空间下法线Shader实现&模型空间下法线Shader实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/iceSony/article/details/84591877 本文由@唐三十胖子出品,转载请注明出处。 文章链接:https://blog.csdn.n...

唐三十胖子
2018/11/28
0
0
【Unity3D技术文档翻译】第2.3.3.7篇 高度图(Heightmap)

上一章:【Unity3D技术文档翻译】第2.3.3.6篇 法线贴图(凹凸贴图) 本章原文所在章节:【Unity Manual】→【Graphics】→【Graphics Overview】→【Materials, Shaders & Textures】→【Sta...

何三思
2018/06/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

使用Airflow来调度Data Lake Analytics的任务

今天我们来介绍一下使用Airflow来调度 Data Lake Analytics(后面简称DLA)的任务执行。DLA作为一个数据湖的解决方案, 客户有每天周期性的调度一些任务从DLA查询数据回流到业务系统的需求。因...

迷你芊宝宝
26分钟前
3
0
简单的file获取文本内容且, 修改文本内容(java8)

题主, 因入职新公司, 表设计混乱, 不得不手动写一个小脚本,获取所有字段后,重新写入至新表中; 思路 顺序如下 原sql 具体, 获取行 , 根据行开头的" ,"截取内容, 重新输入到txt, 中就可以了; 代...

尾生
33分钟前
3
0
嵌入式编程(一):51单片机如何将函数 定义到指定程序地址

在单片机编程使用中,会涉及到将某些函数定义到指定的code区。此时需要对工程文件进行配置修改才可完成。本期针对单片机平台做出说明介绍 1、测试目标 将函数testaddr定义到0x6000地址 2、测...

Music121
37分钟前
1
0
Java Android几个重要的基础知识

Java 1.数据类型 bit(位):0或1计算机存储处理信息的最基本的单位 byte(字节):8个bit(上面表格数字的单位是byte) 2. m与n数值交换 //m=2,n=3; m=m^n; //m=2^3 n =m^n; //n =2^3^3=2 m=m...

Coding缘
40分钟前
4
0
好程序员教程之配置H5的滚动条样式示例代码

配置H5的滚动条样式示例代码有不少的小伙伴在网上寻找,本篇文章好程序员小编和大家分享一下配置H5的滚动条样式示例代码,希望对HTML5开发感兴趣的小伙伴有所帮助,下面我们一块来看一下吧:...

好程序员IT
42分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部