首页 » 技术分享 » Shader山下(二十八) 切空间

Shader山下(二十八) 切空间

 

以下摘录自《Unity 3D ShaderLab开发实战详解》,18.1。

如果要理解法线贴图的用法,就要知道Tangent Space,即切空间。什么是切空间?想象一下这样一个假设的情形:“2013年2月14日,上帝创造完世界之后,没错,他刚刚把世界造好,然后他让全世界70亿人民全体力争,昂首挺胸,双脚着地,头朝上,面朝南,报告一下此时太阳的方位。”我可以肯定地告诉各位读者,会有70亿个不同的答案。因为每个人都是以自己为原点,以从脚到脑袋指向天空的方向为z轴,以正前方为x轴,右手为y轴。所谓的切线空间就是一个法线Normal(从脚到头的方向)、Tangent切方向(双眼直视正前方)和Binormal(水平抬起你的右胳膊)这3个矢量构造了一个空间,然然后把这3个方向矢量,也就是当前像素位置的Tangent、Binormal、Normal表示为一个矩阵,那么就是一个和_World2Object类似的矩阵,乘以它就会得到某一个向量在当前位置切空间的表示,具体来说就是太阳对于当前这个人来说的角度。这个时候,如果你在当前位置挖个坑,这坑的Normal也就是从BumpMap读取到的Normal,此时你可以放心地用当前太阳方位来进行计算,不用担心有人提醒你太阳的角度不对。记住,以你自己为中心所观察到的世界就是切空间。

以下转载自知乎为什么要有切线空间(Tangent Space),它的作用是什么?

1 .什么是切线空间?

Tangent Space,其实一个坐标系,也就是原点+三个坐标轴决定的一个相对空间,我们只要搞清楚原点和三个坐标轴是什么就可以了。在Tangent Space中,坐标原点就是顶点的位置,其中z轴是该顶点本身的法线方向(N)。另外两个坐标轴就是和该点相切的两条切线。这样的切线本来有无数条,但模型一般会给定该顶点的一个tangent,这个tangent方向一般是使用和纹理坐标方向相同的那条tangent(T)。而另一个坐标轴的方向(B)就可以通过normal和tangent的叉乘得到。
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

通常我们所见的法线纹理还是基于原法线信息构建的坐标系来构建出来的。那种偏蓝色的法线纹理其实就是存储了在每个顶点各自的Tangent Space中,法线的扰动方向。也就是说,如果一个顶点的法线方向不变,那么在它的Tangent Space中,新的normal值就是z轴方向,也就是说值为(0, 0, 1)。但这并不是法线纹理中存储的最终值,因为一个向量每个维度的取值范围在(-1, 1),而纹理每个通道的值范围在(0, 1),因此我们需要做一个映射,即pixel = (normal + 1) / 2。这样,之前的法线值(0, 0, 1)实际上对应了法线纹理中RGB的值为(0.5, 0.5, 1),而这个颜色也就是法线纹理中那大片的蓝色。这些蓝色实际上说明顶点的大部分法线是和模型本身法线一样的,不需要改变。总结一下就是,法线纹理的RGB通道存储了在每个顶点各自的Tangent Space中的法线方向的映射值。

2.为什么要有切线空间

实际上,法线本身存储在哪个坐标系中都是可以的,例如存储在World Space、或者Object Space、或者Tangent Space中。但问题是,我们并不是单纯的想要得到法线,后续的光照计算才是我们的目的。不管使用哪个坐标系,都面临着一个选择,就是最后光照计算使用的坐标系究竟是哪个。对于Tangent-Space Normal Map,我们一般就是在Tangent Space里计算的,也就是说,我们需要把viewDir、lightDir在Vertex Shader中转换到Tangent Space中,然后在Fragment Shader对法线纹理采样后,直接进行光照计算。 Tangent-Space还有如下一些优点:自由度很高。Tangent-Space Normal Map记录的是相对法线信息,这意味着,即便把该纹理应用到一个完全不同的网格上,也可以得到一个合理的结果。可进行UV动画。比如,我们可以移动一个纹理的UV坐标来实现一个凹凸移动的效果,这种UV动画在水或者火山熔岩这种类型的物体会会用到。可以重用Normal Map。比如,一个砖块,我们可以仅使用一张Normal Map就可以用到所有的六个面上。可压缩。由于Tangent-Space Normal Map中法线的Z方向总是正方向的,因此我们可以仅存储XY方向,而推导得到Z方向。

作者:潘友成
链接:https://www.zhihu.com/question/23706933/answer/161968056
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

转注:binormal=cross(normal, tangent) * tangent.w
切空间矩阵(从对象空间到切线空间)matrix=[tangent.xyz, binormal, normal]

转载自原文链接, 如需删除请联系管理员。

原文链接:Shader山下(二十八) 切空间,转载请注明来源!

0