Unity法线贴图原理理解(为什么存在切线空间?存的值是什么?)

news2024/11/16 13:45:43

Unity法线贴图原理理解(为什么存在切线空间?存的值是什么?)

  • 写在前面
    • 1、为什么用法线贴图?
    • 2、用什么存法线?
    • 3、法线向量为什么存在切线空间?法线贴图存得是什么?
    • 4、法线贴图为什么会偏蓝?
    • 5、如何生成法线贴图?
    • 6、怎样用法线贴图计算光照?
  • 写在后面

写在前面

最近写Shader使用到了法线贴图,一直没搞懂为什么法线贴图是存在切线空间的?以及法线贴图里到底存的是什么?
看来了网上很多博客以及《Unity Shader入门精要》都没太明白。
我当时很疑惑的点是:法线贴图存储的是模型在切线空间下的法线方向。而切线空间z轴是顶点的法线方向,x轴是顶点的切线方向,y轴由法线和切线叉积的副切线。法线贴图到底存的是什么呢?切线空间都把法线拿去当z轴了,还不所有法线都是(0,0,1)了嘛
最终在https://www.gxlsystem.com/hulianwang-1859689.html中得到了比较合理的解释。
下面是真的上面的引用再加上个人的理解,若有错误欢迎讨论。

1、为什么用法线贴图?

精细的模型虽然光照的效果很好,但是凹凸面太多,导致光照计算量太大。而粗模的凹凸面太少,导致光照效果不好。因为光照效果是受模型法线方向影响的,精模凹凸面多->面的法线方向越多样->光照效果好,粗模凹凸面少->面的法线方向多样少->光照效果不好->导致看起来没有凹凸感。
所以人们想到,能不能把高模的法线存起来用在低模上,从而让低模实现类似高模的光照效果。所以发明了法线贴图用来存高模的法线信息。

2、用什么存法线?

法线向量的3个分量xyz正好对应图片的三通道rgb,所以想到用图片去存法线信息,所以这张存了法线信息的图片就叫法线贴图。

3、法线向量为什么存在切线空间?法线贴图存得是什么?

法线用什么坐标系去存呢?
有三种选择方式:世界坐标系、模型坐标系、切线坐标系
世界坐标系:
法线向量相对于世界原点,那么法线向量与模型本身位置,如果模型换个位置,或则换个场景,就出出错,所以不行。
模型坐标系:
法线相对于模型原点,那么如果模型不动,但某个三角形网格变了,面上的法线向量本应该变了。但是模型原点坐标没变,法线向量是相对于模型原点的,所以法线实际是不会变,这就有问题了。并且由于模型空间下的法线向量是相对于这个模型原点的,不同模型的模型坐标系是不一样的,所以也导致这些模型空间下的法线只能应用于这个模型,换一个模型就不行了。
切线坐标系:
既然世界坐标和模型坐标都不太好,那么人们就想能不能让法线依赖于向量既不依赖于场景又不依赖于模型,而是依赖于模型上的面呢?当面变的时候,法线跟着变。从而让法线始终保持处于这个面的上方。人们为了实现这个目标,提出了切线空间。
坐标系定义:对于粗模 (注意是粗模!!!) 的每个顶点,它都有自己的切线空间,这个切线空间的原点就是该原点本身,而z轴是顶点的法线方向,x轴是顶点的切线方向,y轴由法线和切线叉积而得,称为副切线(bitangent)。
切线坐标系储存的值:
储存的是精模法线向量从模型坐标系转到粗模的切线坐标系的向量。也就是用粗模的切线空间储存精模的法线。

这样,由于每个表面顶点都有自己的切线空间,这个切线空间是以粗模顶点的法线方向为z轴,顶点的切线方向为x轴,副切线为y轴,储存的是精模的法线向量。因此这个精模的法线是相对当前粗模该顶点的切线空间的法线,这里我们假设值为(0,0,1),即精模法线与粗模法线重合(因为粗模法线是z轴嘛)。如果粗模发生变化,这时粗模顶点法线和切线变化,那么这个切线空间变了。此时的(0,0,1)依然代表这个变化后的粗模的顶点法线方向,也就是说你只要知道变化后的粗模的法线方向,那么对应的精模的法线也就是这个法线,那么应用在粗模的光照效果依然是精模的光照效果。
这里我画一个示意图,图上的红绿蓝坐标系就是粗模的切线空间。这里我们假设来自于精模的四个四边形变成粗模的一个四边形。我画的粉色框就是精模的四边形,这时这个四边形顶点的法线就是精模法线向量,然后把这个坐标系放到粗模切线坐标系,此时这个法线向量的值就是法线贴图的值。
在这里插入图片描述

4、法线贴图为什么会偏蓝?

因为法线向量各个分量xyz取值区间是[-1,1],而rgb颜色分量范围是0-1,所以需要映射一下:rgb = (xyz + 1) / 2。
上面提到了法线贴图存的值是精模法线向量从模型坐标系转到粗模的切线坐标系的向量。比如说粗模的三角形数量相对于粗模来说没有减少,也就是粗模和精模是同一个模型。这时因为切线空间的z轴是粗模的法向量,由于假设粗模和精模是同一个模型法线是完全相同的,也就是精模的所有法线向量就是z轴,即值为(0,0,1)。这时的法线贴图所有值都是rgb=(0.5,0.5,1),也就淡蓝色。因此只要粗模相对于精模三角形数量和为没有太大变化,那法线贴图大多数颜色就是(0.5,0.5,1)淡蓝色。

5、如何生成法线贴图?

这个问题也就是再说,如何让精模模型空间下的法线转到粗模切线空间下。也就是我们需要一个变化矩阵让精模法线经过变化矩阵变化的粗模切线空间。
这里直接给结论:从一个空间T变换到空间N的变换矩阵,就是T空间的三个基向量xyz在N空间下的表示。

结论来自https://zhuanlan.zhihu.com/p/361417740

因此从切线空间->模型空间:相当于切线空间中三个基坐标(TBN,T为切线、B为副切线、N为法线)在模型空间三个基坐标上的投影(XYZ)。因此变换矩阵为
在这里插入图片描述
同理从模型空间->切线空间是切线空间->模型空间的转置,因为是逆向操作
在这里插入图片描述
这样我们就得到了从模型空间->切线空间变换矩阵。再用模型空间的法线左乘这个变换矩阵就能得到切线空间的法线了。
注意:因为粗模一个三角面需要对应多个精模的三角面,因此多个法线向量就可以共享一个低模切线坐标系。

6、怎样用法线贴图计算光照?

因为法线贴图是切线空间的,但是光照是在世界空间计算的,因此要计算光照有两种方式。法一:把光照方向和视角法线转到切线空间去计算。法二:把法线从切线空间转到世界空间去计算。
这里我们主要讲法二,把法线贴图中法线转到世界空间去计算光照。
首先我们就要获得从切线空间->世界空间的变换矩阵
切线空间->世界空间:使用法线贴图,如果光照在世界空间中计算,就需要把法线从切线空间转换到世界空间。Matrix = 切线空间三分量在世界空间的表示。
在这里插入图片描述
矩阵再乘上切线空间下的法线,获得世界空间法线。
在这里插入图片描述
对应shader的代码,o.tangent.w是副切线的方向性的。

//粗模顶点法线
float3 worldNormal = mul((float3x3)unity_ObjectToWorld,o.normal);
//粗模顶点切线
float3 worldTangent = mul((float3x3)unity_ObjectToWorld,o.tangent.xyz);
//粗模顶点副切线
float3 worldBinormal = cross(worldNormal,worldTangent)*o.tangent.w;
//切线空间->世界空间的变换矩阵
r.matrixRow1 = float3(worldTangent.x,worldBinormal.x,worldNormal.x);
r.matrixRow2 = float3(worldTangent.y,worldBinormal.y,worldNormal.y);
r.matrixRow3 = float3(worldTangent.z,worldBinormal.z,worldNormal.z);

有了切线空间->世界空间的变换矩阵,我们就只需要把法线贴图的法线向量左乘这个矩阵就能得到世界空间下的法线向量。主要要反映射一下,因为贴图是rgb[0,1]而法线范围是[-1,1]。

//对法线纹理进行采样,取出其值,这是在切线空间的法线
fixed4 bumpColor = tex2D(_BumpTexture,o.uvNormalTexture);
//解出法线纹理,这是对法线纹理的采样结果的一个反映射操作, normal.xy = packednormal.xy * 2 - 1;
fixed3 bump = UnpackNormal(bumpColor);
bump *= _BumpScale;
//得到副切线
bump.z = sqrt(1 - max(0, dot(bump.xy, bump.xy)));
//法线向量从切线空间转到世界空间
bump = fixed3(
    dot(o.matrixRow1,bump),
    dot(o.matrixRow2,bump),
    dot(o.matrixRow3,bump));

这样我的就得到了法线贴图,然后用这张法线贴图去做漫反射光照即可。

fixed3 diffuseColor = _LightColor0.rgb*mainTextureColor.rgb*max(0,dot(normalize(bump),normalize(_WorldSpaceLightPos0.xyz)));

完整代码
见https://blog.csdn.net/iiiiiiimp/article/details/125505828中的Phong光照模型(顶点片元Shader、表面体Shader)
在这里插入图片描述

写在后面

看来一天的博客,才有点弄明白了。由此可见《深海》的图形学技术功底。大家去看看《深海》吧!博主当时哭得好惨!听说12亿才回本!!!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/350497.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL字段值如何区分大小写

MySQL字段值如何区分大小写 注意:设置的是字段值区分大小写 1. 查询时指定大小写敏感,加关键字‘BINARY’ (1)删表,建表,新增数据 drop table binary_test; CREATE TABLE binary_test (id INT unsigned P…

2023年浙江建筑施工物料提升(建筑特种作业)模拟试题及答案

百分百题库提供特种工(物料提升机)考试试题、特种工(物料提升机)考试预测题、特种工(物料提升机)考试真题、特种工(物料提升机)证考试题库等,提供在线做题刷题,在线模拟考…

Zebec完成BNB Chain以及Near链上协议部署,多链化进程加速

从去年开始,Zebec 就开始以多链的形式来拓展自身的流支付生态,一方面向更多的区块链系统拓展自身流支付协议,即从Solana上向EVM链上对协议与通证等进行迁移与拓展。目前基本完成了在BNB Chain以及Near上的合约部署,且能够在这些EV…

handler解析(4)-Message及Message回收机制

Message中可以携带的信息 Message中可以携带的数据比较丰富,下面对一些常用的数据进行了分析。 /*** 用户定义的消息代码,以便当接受到消息是关于什么的。其中每个Hanler都有自己的命名控件,不用担心会冲突*/ public int what; /*** 如果你…

Mrkdown相关快捷键

Mrkdown相关快捷键欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚…

ChatGPT持续“狂飙“,有这么人工智能吗?

最近,一款新聊天工具ChatGPT火了,可以聊天、写作、编程、翻译,甚至可以质疑和拒绝你的要求。自2022年11月底推出以来,ChatGPT已经成为历史上增长最快的消费者应用程序之一。ChatGPT的狂飙突进引来谷歌、百度等众多互联网巨头的跟进…

案例分享 | 某券商利用AI技术进行告警关联分析(下)

本内容来自公众号“布博士”------(擎创科技资深产品专家)在上期内容中,我们了解到跨行业数据挖掘标准流程包括6大过程,分别为业务理解(Business Understanding)、数据理解(Data Understanding&…

JavaWeb3-线程的3种创建方式7种写法

目录 1.方式一:继承Thread(2种写法) 写法①(常规): a.使用jconsole观察线程 b.启动线程——start方法 PS:(常见面试题)start 方法与 run 方法的区别: 写…

免费CRM客户管理系统真的存在吗?不仅有,还有5个!

免费CRM客户管理系统真的存在吗?当然有! 说到CRM客户管理系统,相信很多企业并不陌生,是因为CRM客户管理系统已经成为大多数企业最不可或缺的工具。但是对于很多小微企业和个人用户来说,购买和实施CRM的成本仍然难以承…

上海亚商投顾:沪指午后放量跳水两市上涨个股不足500只

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。市场情绪指数早间震荡走高,沪指盘中收复3300点,午后集体跳水,创业板指一度跌超2%。ChatGP…

Spring 系列之 MVC

Spring 系列文章目录 文章目录Spring 系列文章目录前言一、介绍二、项目搭建1.创建空项目2.设置maven和lombok3.创建maven web module4. 配置Tomcat启动运行项目(选择local本地)5. 导入jar依赖包6.在web.xml中配置DispatcherServlet7. 加入SpringMVC的配…

第六章——抽样分布

文章目录1、统计量的定义2、常用的统计量3、经验分布函数4、正态总体常用统计量的分布4.1、卡方分布4.1.1、卡方分布的定义4.1.2、卡方分布的性质4.2、t分布4.2.1、t分布的定义4.2.2、t分布的性质4.3、F分布4.3.1、F分布的定义4.3.2、F分布的性质5、正态总体的样本均值与样本方…

Hexo搭建个人博客流程全记录

建站缘由 有些东西过不了审,不方便给他人查看,于是就利用Hexo框架搭建了一个个人博客,部署在Github上,取名为“zstar的安全屋”。 链接:http://xdxsb.top 安装Git Bash 无需多言,下载链接:ht…

全网招募P图高手!阿里巴巴持续训练鉴假AI

P过的证件如何鉴定为真?三千万网友都晒出了与梅西的合影?图像编辑技术的普及让人人都能P图,但也带来“假图”识别难题,甚至是欺诈问题。 为此,阿里安全联合华中科技大学国家防伪工程中心、国际文档分析识别方向的唯一顶…

【集合】JAVA基础篇(二)

【集合】JAVA基础篇(二)一、java常用集合1、Java集合接口的作用2、Java集合常用实现类的作用二、Collection 常用的方法三、List 集合接口1、ArrayList类的常用方法2、LinkList类中的方法3、Vector4、ArrayList 类和 LinkedList 类的区别四、Set 集合1、…

图解LeetCode——剑指 Offer 27. 二叉树的镜像

一、题目 请完成一个函数&#xff0c;输入一个二叉树&#xff0c;该函数输出它的镜像&#xff0c;返回镜像后的根节点TreeNode。 二、示例 2.1> 示例 1&#xff1a; 【输入】root [4,2,7,1,3,6,9] 【输出】[4,7,2,9,6,3,1] 限制&#xff1a; 0 < 节点个数 < 1000 …

Hadoop核心组成和生态系统简介

一、Hadoop的概念 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下&#xff0c;开发分布式程序。充分利用集群的威力进行高速运算和存储。Hadoop实现了一个分布式文件系统&#xff08; Distributed File System&#xff09;&am…

Word处理控件Aspose.Words功能演示:使用 C++ 将电子邮件消息转换为 PDF

Aspose.Words 是一种高级Word文档处理API&#xff0c;用于执行各种文档管理和操作任务。API支持生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现和打印文档&#xff0c;而无需在跨平台应用程序中直接使用Microsoft Word。此外&#xff0c;API支持所有流行的Word处理文件…

数据结构基础(力扣算法)(数组、字符串、链表、栈、部分树)(1-16天计划)

数据结构基础数组136. 只出现一次的数字169. 多数元素15. 三数之和75. 颜色分类56. 合并区间706. 设计哈希映射119. 杨辉三角 II48. 旋转图像59. 螺旋矩阵 II240. 搜索二维矩阵 II334. 递增的三元子序列238. 除自身以外数组的乘积435. 无重叠区间560. 和为 K 的子数组字符串415…

基于TC377的MACL-ADC General配置解读

目录标题一、MACL-ADC General1.Config Variant与AdcConfigSet2. AdcGeneral3.AdcPublishedInformation二、最终对应达芬奇生成内容一、MACL-ADC General 1.Config Variant与AdcConfigSet Config Variant &#xff1a;变体配置&#xff0c;默认选择VariantPostBuild就好了&…