Shader 常用顶点函数中的空间转换

模型的Shader的数据来源为Unity中的Mesh组键,也就是a2v的结构体定义获取想要的数据。
a2v的意思就是application to vertex即app到顶点,由CPU发送场景(灯光、相机等)、模型顶点、模型材质数据到GPU开始处理,Shader逻辑即为处理逻辑,因此每次发送会产生一个Draw Calls(即一个材质球产生一个Draw Calls)。

模型的顶点Shader的顶点数据最终的出口为裁剪空间。

一个顶点从模型空间到屏幕空间的流程通常为:
模型空间-世界空间-观察空间-裁剪空间-屏幕空间

模型空间:就是以模型自身的中心点(模型软件设置的中心点)为中心的坐标系,每个顶点会有相对的坐标
世界空间:就是以世界坐标(0,0,0)为中心,转换来的每个顶点坐标
观察空间:就是以相机为中心,转换来的每个顶点坐标,也有人叫做相机空间
裁剪空间:就是在相机的空间基础上,增加了一个显示范围的界定,并且算出来每个顶点坐标
屏幕空间:就是通过上面的裁剪空间算出来的坐标,再映射到近裁面上,就是最终的显示的顶点坐标
乐乐书里的图

Unity中常用变换矩阵

矩阵用法含义
UNITY_MATRIX_Mo.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;即上图中的模型(Model)变换的矩阵
UNITY_MATRIX_V即上图观察变换也叫视图(View)变换的矩阵
UNITY_MATRIX_P即上图中的投影(Projection)变换的矩阵
UNITY_MATRIX_MVMV的组合,通常用于把顶点方向矢量从模型空间转换到观察空间
UNITY_MATRIX_VPVP的组合,通常用于把顶点方向矢量从世界空间转换到裁剪空间
UNITY_MATRIX_MVPo.pos = UnityObjectToClipPos(v.vertex);使用最多的,模型空间直接到裁剪空间矩阵,官方推荐直接用方法,效率高

前期学习我们常用的其实也就两个,一个是万年的MVP也就是模型空间直接转到裁剪空间,另一个M就是当需要顶点的世界坐标的时候用到。


其他的xx空间名词:
视口空间:就是最终Game视图的屏幕坐标系单位化,即左下角为(0, 0),右上角为(1, 1),z轴坐标是相机的世界坐标中z轴坐标的负值,几乎用不上。
切线空间:这篇讲的是最好的。这里摘抄一下,添加一些理解:

1 .什么是切线空间?

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

image.png
image.png
image.png
image.png

通常我们所见的法线纹理还是基于原法线信息构建的坐标系来构建出来的。那种偏蓝色的法线纹理其实就是存储了在每个顶点各自的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中。但问题是,我们并不是单纯的想要得到法线,后续的光照计算才是我们的目的,(这里就相当于把每个顶点作为原点,法线方向作为y轴,计算相对的光源位置就能得出渲染的结果,如果使用其他坐标系则会涉及到两个点的位置、方向的复杂运算)。不管使用哪个坐标系,都面临着一个选择,就是最后光照计算使用的坐标系究竟是哪个。对于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方向。

常用顶点函数中的方向获取

//顶点转裁剪空间下的坐标(即最终显示的坐标)
//等同于o.vertex = mul(UNITY_MATRIX_MVP,v.vertex);  
o.pos = UnityObjectToClipPos(v.vertex);

//普通纹理
o.uv0 = v.uv0; o.uv0 = TRANSFORM TEX(v.uv0, MainTex ST);

//LightMap UV
o.uv1 = v.uv1; o.uv1 = v.uv1 * unity LightmapST.xy + unity LightmapST.zw; o.posWS = mul(unity ObjectToWorld, v.vertex);

//世界空间法线方向
o.nDirWS = UnityObjectToWorldNormal(v.normal);

//世界空间切线方向
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz);

//世界空间副切线方向,通过法线方向和切线方向叉乘获取垂直于两者的向量,再乘以tangent.w以确定方向
o.bDirWS = normalize(cross(o.nDirWS, o.tDirWS) * v.tangent.w);

//顶点色
o.color = v.color;
image.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值