Unity的unity_ObjectToWorld里的每一列分别代表什么意思?换个方向反向理解-更简单

官方关键UnityObjectToWorldNormal() 代码

从乐乐姐的书中得知,当我们在shader想获得法线,大概会这么些

o.wordDir = UnityObjectToWorldNormal(i.normal)

(这行代码就包含了官方对“unity_ObjectToWorld”的终极理解+极致应用)

也可以说,掌握了这行代码,就掌握了unity_ObjectToWorld

(这行代码的源码在楼下。。。)

这时候,肯定有一堆高人跳出来分析了, 这个很复杂,分两种情况,巴啦巴啦

我复杂个P,法线转世界坐标就复杂了??下面会一一展开说,甚至关键代码都是幼儿园数学,加减乘除而已

如下面代码,确实是if ... else .. ,也确实分两种“复杂”情况;

但是在大部分情况下,大部分的智商都差不多,所以都不要没搞懂一行代码逻辑,就if .. else ...去企图把两段代码都搞懂,反向一下逻辑很清楚的:如果两段代码是差不多,接近的,就会用一个方法传不同的参数解决。,而不是if .. else .. ;但既然用了if .. else ..解决, 也就是UnityObjectToWorldNormal()里的两段代码南辕北辙, 

那么问题来了?你是希望:

1.先把第一段代码搞懂,(而省下了读第两段代码时间,以至于有经历集中完全掌握关键代码?),

2.还是头铁,两段一起搞,每一段都搞不通,而且两段互调一起又加深混乱?

如楼下这段代码,我们只需要了解, 根本不用管第二种情况(有兴趣同学可课外自行研究)

normalize(mul (unity_objecttoWorld,dir))//这个方法即可

未知代码1

首先,请看下面代码,看不懂没关系的,(未知1)后面会补上幼儿园数学,加减乘除而已,只要上过小学就没问题,初中辍学也能懂,

这段1代码主要是要计算_19的结果,而输入的参数_7,我们从 layout(location ) _7大概就知道这是:法线(normal)

//代码1
layout(location = 1) in vec3 _7;
layout(set = 1, binding = 0, std140) uniform _23_25
{
    vec4 _m0[4];
    vec4 _m1[4];
    vec4 _m2[4];
    vec4 _m3;
} _25;

void main()
{
    _16.x = dot(_7, _25._m1[0u].xyz);
    _16.y = dot(_7, _25._m1[1u].xyz);
    _16.z = dot(_7, _25._m1[2u].xyz);
    _19 = dot(_16.xyz, _16.xyz);
    _19 = inversesqrt(_19);
}

未知代码2

因为未知1,所以我们需要未知2,还是不懂没关系的,请接着往下看,

(会越说越简单的)

//代码2

矢量 - 大概是这么一个东西

        var pos = new Vector3(1, 1.5, 1);

矩阵 - 是大概这么一个东西(3个矩阵相乘)

这个图不是矩阵最终结果

根据某大牛说的:

矩阵:模型顶点从模型空间转换到世界空间用的矩阵,就是unity_ObjectToWorld,那么这个矩阵的内容是什么呢,没错,就是这个模型相对于世界空间原点的缩放,旋转和平移

矩阵最后一列代表的是模型中心点的世界坐标

M - local2World 的三列分别是:

1.最后一列,第4列代表的是模型中心点的世界坐标(明显的最后一列是tx,ty,tx,1)

2.另外第1,2, 3列后面再说

由于我们知道1列1列是有含义的(最后一列是世界坐标(真不需要说模型中心点的,世界坐标就是世界坐标,台湾省难道有任何可能会不是中国台湾省么))

我们知道了列的含义

所以楼上的代码_25[0u] _25[1u], _25[2u]就分别代表了,第1,2,3列,而不是代表行

(后面证明是错了,0,1,2就是行的列,_25行[0,1,2]列,

是:

m1[1] m1[2] 25[3]

m2

m2

而不是
m[1] m2 m3

m[2]

m[3]

那么。。。localToWorld矩阵的第1,2,3列(行)到底是什么意思呢?

最简单的解释localToWorld

    _16.x = dot(_7, _25._m1[0u].xyz);
    _16.y = dot(_7, _25._m1[1u].xyz);
    _16.z = dot(_7, _25._m1[2u].xyz);

从楼上的代码(代码1)我们可知道

用法线 "_7" dot点乘 x 矩阵unity_objectToWorld "_25" 的第一列是什么意思呢

这里还做了3个dot

这里还做了3个dot

这里还做了3个dot

矩阵x 矢量(法线==矢量)数学含义

刚刚好,结果形成了新的矢量

//代码-2

点乘的数学含义

两个矢量的点乘,就是各自的分量.xyz相乘后,再相加

dot(vec a,  vec b)= x_1x_2 + y_1y_2 + z_1z_2;

凑巧,就是,矩阵的第一行,3个数分别乘以矢量的x,y,z,结果就是dot点乘的结果

对应楼上的代码:就是那么刚好,刚刚同学遇到凑巧同学,所以,

//形成新的矢量 ——16
    _16.x = dot(_7, _25._m1[0u].xyz);//如楼上伪代码,x==16
    _16.y = dot(_7, _25._m1[1u].xyz);//如楼上伪代码,y==4
    _16.z = dot(_7, _25._m1[2u].xyz);//如楼上伪代码,z==7

所以计算——16就是得出了法线——7的世界坐标(因为_7是从Localtion(2)声明,是从Vectex Shader传入,vertex为模型自身顶点坐标|法线也是自身坐标,还不是世界坐标)

未知代码3 - 法线归一

然后,这3行代码后面,还有2行代码:

下面——19这两行代码就太简单了,就是矢量的"归一化":

    //形成新的矢量 ——16
    _16.x = dot(_7, _25._m1[0u].xyz);//如楼上伪代码,x==16
    _16.y = dot(_7, _25._m1[1u].xyz);//如楼上伪代码,y==4
    _16.z = dot(_7, _25._m1[2u].xyz);//如楼上伪代码,z==7

    //这两行代码就太简单了
    _19 = dot(_16.xyz, _16.xyz);
    _19 = inversesqrt(_19);

    //法线的世界坐标的dir(_19)=nomalize(mul(法线,objectToWorld矩阵)

归一化是什么意思?我不打算解释了,总之上面代码

好了,说到这里,我们只需要掌握

  • 矢量基本加减乘除,法线也是矢量
  • 矩阵 = 
  • 矩阵相乘 = 3个,平移x旋转x缩放矩阵
  • Shader基础语法
  • 矩阵相乘后再乘以法线矢量
  • 矢量归一化

等同于文章最开始的截图(调转)

“”_19“”法线的世界坐标的dir = nomalize(mul(法线, objectToWorld矩阵));
//objectToWorld矩阵也可以是float4x4的,但是最后一列前面解释了,没什么数学含义
//所以,也就是Unity官方的写法
worldDir = normalize(mul((float3x3)unity_ObjectToWorld, dir));

所以, 你掌握了官方的这个函数方法,就能准确应用 unity_ObjectToWorld ,当你会用了自然就明白了,只是unity 本身写的太绕(太基础了,谁都不想解释)

那么现在,你知道unity_ObjectToWorld矩阵,每行每列是什么意思了吧?

参考:

(2 条消息) unity_ObjectToWorld里的每一列分别代表什么意思? - 知乎 (zhihu.com)

UnityCG.cginc源码之UnityObjectToWorldNormal之模型非等比缩放导致的法线不垂直问题解决分析_shader法向量非等比缩放-CSDN博客

猜你喜欢

转载自blog.csdn.net/avi9111/article/details/134023870
今日推荐