首页 > Unity3D频道 > 【Unity3D拓展编辑器】 > Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四)
2019
08-17

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四)

合并mesh的功能比较常见,可以运行时合也可以编辑模式下提前合并,但是至少需要注意两点。

1.考虑lightmap,合并mesh以后会将lightmap的信息写入uv2,如果有多张lightmap需要传入正确的index,所以参与合批的mesh需要保证处于同一index的lightmap中。

2.如果地图需要切块,那么合并mesh需要考虑中心点的问题。

如下图所示,美术做场景可能是很随意的,完全可能让父节点和子节点相离的十分远,那么合并完以后中心点如果离的过远,是无法判断出当前所处的地图块的,所以合并完以后我们要让中心点居中。

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 1

脚本的使用

1.在Hierarchy视图中选择需要合并的多个游戏对象

2.Tools/CombineMesh开始合并,生成prefab并且生成mesh

3.我是用unity2019.2写的例子,所以代码中用了些c#7的语法。

4.注意UV3

如图选择GameObject根节点然后点击菜单栏Tools/CombineMesh就会自动生成prefab,以及mesh都保存在Project视图中,最重要的是中心点已经归于正中心了。

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 2
需要注意的这句代码

CombineInstance每个参与合批的都需要传入一个矩阵,这里的localToWorldMatrix就是把本地transform转成世界矩阵,对应unity还提供了WorldToLocalMatrix也就是世界转本地。本地和世界就好比localPosition和Position的关系一样。这里为什么要去修改 矩阵的m03 m13 m23呢?因为这三个值就代表着x、y、z。

我们先举个例子,如图所示,这样一个Transform

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 3

如下图所示,对应的矩阵信息如下。上面代码矩阵改的m03 m13 m23就对应着Position的x,y,z。我们还能看到缩放信息对应存在m00 m11 m22中,好像挺简单的。

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 4

但是旋转就比较麻烦了,先不管矩阵、四元数、欧拉角,完全放空。来我们先回味一下初中几何,如下图所示,在平面几何中,已知起始点A=(1,0) 半径r=1和旋转的角度a=45 求旋转到P点的坐标。

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 5

根据三角函数的原理,OM就是P点的X坐标, MP就是P点的Y坐标,它们现在都是未知的,已知半径r=1所以OP = 1

先算OM距离

cos a = 邻边/斜边

cos a =  OM/OP

推导出

OM = OP * cos a

P点X坐标 = 1 * cos a

在算MP距离

sin a = 对边/斜边

sin a = MP/OP

推导出

MP = OP * sin a

P点的Y坐标 = 1 * sin a

最终推到得出, P (x,y) = ( cos a , sin a) 通过平面我们就可以根据这个公式计算出任意轴向的旋转。还没完,我们旋转并不是都是像上图这样从A(1,0)点开始旋转的,完全有可能是从已有的旋转角旋转到另一个角。

如下图所示,假如我们不是从A(1,0)开始旋转,而是从P(x,y)点旋转到P1(x,y)旋转角度为B。那么按照上面的推到公式就不满足 P1 (x,y) = ( cos b , sin b) ,而应该加上原本的P(x,y)点。

 

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 6

所以最终P1的推到公式应该是:

P1.x = P.x * cosB – P.y * sinB
P1.y = P.x * sinB + P.y * cosB

尤其注意为什么P1.x为什么要在减去P.y * sinB和P1.y为什么还要加上cosB,这样平面图如果放入3D中其实P点是沿着Z轴在旋转。大家可以好好理解一下,X轴Y轴Z轴旋转其实都是按cos sin来算出来的。

回到unity中我们来做个具体的例子,如下图所示,我们将一个矩形沿着X轴旋转45°,注意观察此时矩形的8个顶点的Y方向和Z方向都发生了改变,但是X方向是没有变化。

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 7

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 8

所以如果旋转任意轴时在进行矩阵运算的时候,该轴的坐标是不发生变化的,另外两个轴发生变化。请大家在回忆一下矩阵乘法,如下图所示,有了这个公式我们就可以推导完整的localToWorldMatrix了。

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 9

如果3个角度都有变化那么3个矩阵需要相乘,但是由于矩阵不具备交换律所以必须按照Untiy的顺序来乘,也就是 Y*X*Z

如下图所示,我们设置XYZ对应的欧拉角,

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四) - 雨松MOMO程序研究院 - 10对应的矩阵内容如下

2.32001    -0.85134  0.46985    8.00000
1.81207    1.43969    -0.34202  9.00000
-0.57789  1.09659    0.81380    10.00000
0.00000    0.00000    0.00000    1.00000

我们来推导,如下代码所示,最终的推导完全一致,需要注意的是矩阵相乘的顺序不满足交换律。

最后在啰嗦一句,Mesh的合并也可以发生在运行时,如果是运行时进行的合并,一定要调用Mesh.UploadMeshData(true);表示将 mesh在.NET托管堆中的byte[]清空,不然内存就双份了。

最后编辑:
作者:雨松MOMO
专注移动互联网,Unity3D游戏开发
捐 赠写博客不易,如果您想请我喝一杯星巴克的话?就进来看吧!

Unity3D研究院编辑器之合并mesh引发的矩阵推导运算(三十四)》有 3 条评论

  1. Armin君 说:

    MeshFilter[] meshFilters = Selection.activeTransform.GetComponentsInChildren(true);
    这个数组获取的最大长度为什么只有19683?如果我子物体数量超过这个数字的话就获取不全了

  2. Armin君 说:

    自问自答了,自Unity 2019.2起,Unity添加了可以处理这种情况的新API ——TryGetComponent API。

  3. Armin君 说:

    TryGetComponent这个方法请问一下在哪定义的?

留下一个回复

你的email不会被公开。