对于不曾学过、用过法线贴图的人来说,提到法线贴图,经常会提到的问题是什么是法线贴图?法线贴图用于解决什么问题?法线贴图的原理是什么?本文将就这三个问题阐述本人的一些见解,各位不喜勿喷!!!

谈到法线贴图首先提到的是切线空间,参考网站 http://blog.csdn.net/bonchoix/article/details/8619624

PS:常提到的纹理坐标就是定义在切线空间的,U坐标对应切线空间的T轴,V轴对应切线空间的B轴,顶点法向量N对应切线空间的N轴,模型中每个三角形都有对应的切线空间,其位于三角形所在的平面。由T轴向量、B轴向量和N轴向量组成的TBN矩阵用于切线空间和世界空间转换。

一、什么是法线贴图?法线贴图用于解决什么问题?

有时候需要模拟一些场景,比如带有浮雕的墙面、带有花纹的茶壶等,如果使用多个三角形模拟平面的凹凸感,则计算量较大并且影响性能。研究人员发现,人眼对于物体表面的凹凸感是通过表面光照明暗变化体现的。如果可以通过一幅贴图实现光照明暗的变化,就能模拟平面表面的凹凸感。法线贴图就是为了解决这一问题而产生的。

使用法线贴图可以使用更少的顶点表现出更多的细节。

二、法线贴图的原理

一般3D场景中模拟光照时是在世界空间中计算的,而从法线贴图中取出的法线向量是位于切线空间的,采用法线贴图时,必须将法线向量和光照相关变量变换到同一空间中才能得到正确的结果。

一般有两种方式:1.将法线向量变换到世界空间;2.将光照相关向量变换到法线向量所在的切线空间。

(1)在顶点着色器中计算得到TBN矩阵,并将其传到片元着色器,然后把采样得到的法线用TBN矩阵从切线空间转到世界空间,这样法线向量就和其他光照变量处于世界空间了,这种方式是针对每个片元进行变换。

(2)从性能方面考虑选择第二种方式更合理。首先在顶点着色器中用TBN矩阵的逆矩阵将所有相关的世界空间向量转化到切线空间,然后将切线空间的光源位置,观察位置以及顶点位置发送给片元着色器。那么在片元着色器中不用对法线向量和其他光照向量进行空间变换。这种方式是针对每个顶点进行变换。第一种方式是在片元着色器中进行,第二种方式是在顶点着色器中执行,而片元着色器执行的次数远远多于顶点着色器的执行次数。

三、具体实现

(1)从法线贴图纹理采样出法线纹理,并将其转化到[-1,1]之间。

vec3 cNormal = texture2D(sTexture,vTexCoor).xyz;

cNormal = normalize(cNormal * 2.0 - 1.0);

(2)根据顶点法向量、切向量计算副法向量。

// newPosition  世界坐标系下的顶点位置

// newNormal 世界坐标系下的顶点法向量

vec3 newNormal = position + normal;

newNormal = (uMMatrix * vec4(newNormal,1.0)).xyz - newPosition;

newNormal = normalize(newNormal);

vec3 newTangent = position + tangent;

newTangent = (uMMatrix * vec4(newNormal,1.0)).xyz - newPosition;

newTangent = normalize(newTangent);

vec3 bitangent = normalize(cross(newTangent,newNormal));

mat3 TBN = mat3(newTangent,bitangent,newNormal);

(3)计算世界坐标系下的光照向量和视线向量

四、法线贴图的缺点

法线贴图最明显的缺点就是视角问题,因为法线贴图只是改变物体表面的光照结果,并没有改变物体表面的形状,因此只要视线不接近于水平,就不会出现视角问题。

五、问题总结

1.为什么法线贴图是偏蓝色的?

法线贴图中的法向量是偏向z轴(0,0,1),其范围是[-1,1],而法线贴图采样得到的结果是[0,1],因此将法向量从[-1,1]转换到[0,1]之间的结果是(0.5,0.5,1.0)——(转换公式是(normal + 1.0)/2.0),此值对应的颜色是偏蓝色,因此法线贴图呈现的颜色是偏蓝色。

2.已知三个顶点的顶点坐标、纹理坐标是否可以计算T向量和B向量?

已知三个顶点p0,p1,p2,对应的纹理坐标(s0,t0),(s1,t1),(s2,t2)

向量vec1 = p1 - p0;vec2 = p2 - p0;

纹理坐标差:ds1 = s1 - s0; dt1 = t1 - t0;

      ds2 = s2 - s0;dt2 = t2 - t0;

关系式:vec1 = ds1 * T + dt1 * B;

    vec2 = ds2 * T + dt2 * B;

联立方程式可以解出T和B,此时计算得到的T和B可能不是正交的,此时需要进行的操作是N1 = T * B;

得到T1 = B * N1;

然后构建TBN矩阵 mat3 TBN = mat3(T1,B,N顶点);

3.矩阵与逆矩阵之间的变换关系:

已知矩阵mat1 = | a  b |            1.0             |d  -b|

        | c  d |,则其逆矩阵mat2  = ————--- *  |-c   a|

                      ad - bc

4.矩阵乘法:T1 = T2 * T3,则T3 = T2的逆矩阵 * T1.

5.在计算机程序中,某个矩阵的逆矩阵的计算比其转置矩阵的计算开销更大。

最后的最后,给大家分享一下鸡汤,一起共勉!!!

白天求生存,晚上谋发展。

平日求生存,周末谋发展。

法线贴图——Normal Mapping的更多相关文章

  1. 翻译:非常详细易懂的法线贴图(Normal Mapping)

    翻译:非常详细易懂的法线贴图(Normal Mapping) 本文翻译自: Shaders » Lesson 6: Normal Mapping 作者: Matt DesLauriers 译者: Fr ...

  2. 3DShader之法线贴图(normal mapping)

    凹凸贴图(bump mapping)实现的技术有几种,normal mapping属于其中的一种,这里实现在物体的坐标系空间中实现的,国际惯例,上图先: 好了讲下原理 可以根据高度图生成法线量图,生成 ...

  3. 切线空间(Tangent Space)法线映射(Normal Mapping)【转】

    // 请注明出处:http://blog.csdn.net/BonChoix,谢谢~) 切线空间(Tangent Space) 切换空间,同局部空间.世界空间等一样,是3D图形学中众多的坐标系之一.切 ...

  4. 【Unity Shaders】法线纹理(Normal Mapping)的实现细节

    写在前面 写这篇的目的是为了总结我长期以来的混乱.虽然题目是"法线纹理的实现细节",但其实我想讲的是如何在shader中编程正确使用法线进行光照计算.这里面最让人头大的就是各种矩阵 ...

  5. 【转载】法线贴图Nomal mapping 原理

    法线贴图多用在CG动画的渲染以及游戏画面的制作上,将具有高细节的模型通过映射烘焙出法线贴图,贴在低端模型的法线贴图通道上,使之拥有法线贴图的渲染效果,却可以大大降低渲染时需要的面数和计算内容,从而达到 ...

  6. 【Unity Shader】六、使用法线贴图(Normal Map)的Shader

    学习资料: http://www.sikiedu.com/course/37/task/456/show# http://www.sikiedu.com/course/37/task/458/show ...

  7. 《The Cg Tutorial》阅读笔记——凹凸贴图 Bump Mapping

    本文为大便一箩筐的原创内容,转载请注明出处,谢谢:http://www.cnblogs.com/dbylk/p/5018103.html 凹凸贴图 Bump Mapping 一.简介 凹凸贴图用于在不 ...

  8. 3D游戏常用技巧Normal Mapping (法线贴图)原理解析——高级篇

    1.概述 上一篇博客,3D游戏常用技巧Normal Mapping (法线贴图)原理解析——基础篇,讲了法线贴图的基本概念和使用方法.而法线贴图和一般的纹理贴图一样,都需要进行压缩,也需要生成mipm ...

  9. shader复杂与深入:Normal Map(法线贴图)1

    转自:http://www.zwqxin.com/archives/shaderglsl/review-normal-map-bump-map.htmlNormal Map法线贴图,想必每个学习计算机 ...

随机推荐

  1. Eclipse下快速打开本地文件插件EasyExplorer(转)

    EasyExplorer  是一个类似于 Windows Explorer的Eclipse插件,它可以帮助你在不退出Eclipse的环境下浏览本地文件系统,类似的插件也有很多,但是本人喜欢使用这个版本 ...

  2. Python补充02 Python小技巧

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在这里列举一些我使用Python时积累的小技巧.这些技巧是我在使用Python过程 ...

  3. 聚合查询中的Group by

    2005版本以上的sql server 查询中如果既包含聚合函数列(诸如sum ,count,avg,max等)又存在一般列的情况,则查询字符串结尾必须包含Group By [某一般列].  其实微软 ...

  4. Scroll滚动后发生的改变

    条件:一个panel,足以让panle产生滚动条的N多控件. 动作:拖动滚动条. 影响:呈现在当前panle视图中的控件的Location.Y或Top值>=0,隐藏在滚动条上方的控件的Locat ...

  5. 【收藏用】--切勿转载Java处理XML的三种主流技术及介绍

    原帖地址 : http://www.ibm.com/developerworks/cn/xml/dm-1208gub/ XML (eXtensible Markup Language) 意为可扩展标记 ...

  6. 为何你的php代码没有写结束标签

    PHP闭合标签"?>"在PHP中对PHP的分析器是可选的.但是,如果使用闭合标签,任何由开发者,用户, 或者FTP应用程序插入闭合标签后面的空格都有可能会引起多余的输出.ph ...

  7. SAP_20140304

    1.  SAP 主打产品  R/3 :分布式 客户端/服务器 环境的标准ERP软件. 2. 主要功能模块:销售和分销,物料管理,生产计划,质量管理,工厂维修,人力资源,工业方案,办公室和通信,项目系统 ...

  8. secureCRT如何远程桥接CentOS.

    1.将虚拟机的网络连接方式设置为桥接 2.关闭CentOS的防火墙,这里我是直接从页面上关闭的,没有使用命令 3.设置CentOS的ip为静态地址,不允许自动获取,这样远程连接不需要总修改地址.由于我 ...

  9. 判断Windows操作系统的版本

    private void Form1_Load(object sender, EventArgs e) { if (!IsWin7()) { Application.Exit(); } } bool ...

  10. ubuntu 服务管理

    在Linux系统下,一个Services的启动.停止以及重启通常是通过/etc/init.d目录下的脚本来控制的.然而,在启动或改变运行级别时,是在/etc/rcX.d中来搜索脚本.其中X是运行级别的 ...