APP下载

三维动画模型的表面分布与应用

2021-01-22

科技创新与应用 2021年6期
关键词:坐标系向量物体

李 擘

引言

我们在制作三维动画的过程中,经常会用到软件提供的一些功能,比如毛发系统,粒子的表面发射。在开发游戏制作室外场景的时候,经常会在地面上制作植被,树、花草等覆盖地面,还有常见的地板铺装等。夏天饮料瓶上凝结的水珠,糖葫芦与汉堡上的芝麻等,这些可否不用模型一个个复制而用程序来实现呢?通过制作、分析这些效果不难看出这些效果的制作与模型表面网格相关,对于艺术生来说,基本思路是用程序将一个模型复制分布到另一个模型的表面上。

1 规矩分布

我先来看地板铺装,来研究表面分布基本的算法。先准备几个测试用的简单模型,一个平面的四边形模型作为地面,作为最大铺装外尺寸的限定,但是要注意最好是长宽都比地板模型大;一个地板模型,给出具体的长、宽、高三个尺寸,也可以把这个参数化、虚拟为代理模型,之后再替换。通常我们生活中铺的地板大都是木头条形板材,横向错半个长度来铺装的。按照这个模式我们写一个简单的循环来实现。

根据地面模型来计算铺装的最大范围,横向X,竖向Z,获得四个点的顺序和位置,得到起始点Pos0《x0,y0,z0》,再与其它点计算,竖向Z长度Depth Max和横向X宽度Width Max;指定一个地板的三维参数,Width宽12cm、Height高1.5cm、Depth长92cm;指定一个偏移值Offset这里为0-1的小数,也可以采用百分比或别的形式。这里我们可以用Width Max/Width算出横向X上能摆放的最大数量NumX0,和用Depth Max/Depth算出竖向Z上能摆放的最大数量NumZ0,也就是铺装的总个数,循环的个数,但是这个数往往是小数,所以需要使用NumZ1=ceil(NumZ0)和NumZ2=trunc(NumZ0)来取比它本身大和小的两个整数。

基础算法,横向重复的数列0,1,2,3,4,5...我们通过其中每一个i分别与2计算求余数来获得新的数列0,1,0,1,0,1...这样我们就可以根据这个奇偶信息,将地板在横向X排列的时候,每隔一个在竖向Z错位一个偏移值Offset。当i%2==1的时候错位,当i%2==0的时候不错位。编写脚本实现第一步错位铺装(图1)。

图1

那么问题来了,多出的部分怎么裁掉呢,可以直接设置模型长度、模型缩放变换信息、调整模型一端的所有点的位置来解决,我们使用缩放、移动变换信息来处理模型。竖向Z超出已知地面最大范围的地板只出现在上上两端,也就是铺装开始和结束的地方。

在处理的时候,我选择从左向右,从上到上的顺序。当i%2==0的时候(左边第一数列)判断,当j==0的时候不偏移,不裁剪,当j==1的时候不偏移,裁剪;当i%2==1的时候(左边第二数列)判断,当j==0的时候偏移,裁剪,当j==1的时候偏移,裁剪,而且还需要补漏,当偏移值大于需要裁剪的长度的时候就会漏出空隙。

(1)第一横排偶数列(注意我们数数是从1开始,编程计算循环内从0开始)根据输入的值来计算缩放倍率:

(i%2==1&&j==0)Remainder=Depth-(Depth*Offset);

Scale Rate=Depth/Remainder;

在运算的时候对符合条件的物体进行缩放。

(2)最后横排奇数列缩放倍率:

(i%2==0&&j==NumZ0)Extra=Depth*NumZ1-Depth Max;

Scale Rate=Depth/Extra;

(3)最后横排偶数列缩放倍率:

(i%2==1&&j==NumZ0)Extra2=Extra-Remainder;

Scale Rate=Depth/Extra2;

(注意:这一个漏的位置需要多复制一个模型并缩放、移动。)

最后实现的效果如图2。因为程序编写的时候,铺装的地板长、宽、高、偏移值都是变量,所以可以实时改变观看效果。因为一个循环上来,这个执行效率并不高。关于这个还有可以扩展的空间,比如:地砖,瓦片等的分布,旋转,更多的切割裁剪等。

演示效果见:https://www.bilibili.com/video/BV1Mf4y1z7 x9?p=2。

图2

2 随机分布

以模拟汉堡上的芝麻来做实验:在表面上分布、离散复制物体。我在MAYA中利用MEL语言编写脚本来实验并解密其基础计算和实现方法。

首先进行一个简单的测试,准备一个只有两个面的简单模型作为A目标物体,每个面四个点;和一个圆锥模型作为要复制到目标物体表面的B复制物体,B放置在坐标系的原点。在我选择的实验环境MAYA软件中,使用MEL语言获得A模型中每个子表面的点在空间中,也就是世界坐标系中的三维坐标值,并通过简单的数学计算,将所有点的位置转换成向量求和后除以其数量,得到一个平均值(向量),这个平均值很接近子表面的中心C,这个位置就是我将要复制模型的初始位置。

C点计算公式伪代码:Vector$average=$VerticePos[sum]/size($Vertices);

编写脚本针对选中的表面来批量计算,体复B物体并移动到A目标物体的每个子表面中心点C上,这样我们得到了初步的效果,即复制物体分布到目标物体上,我们发现复制后的B物体,模型变换信息与在坐标系原点的默认状态一致,需要根据A物体子表面调整B的朝向,也就是调整其变换信息。

分别获取A物体中每个子表面的法线信息,存储为向量V1(Z);获取B物体的变换信息跟向量<<0,1,0>>记作V2来进行比较(在MAYA中Y轴向上),使用Cross来计算V1和V2的切线,并且使用Unit规格化后得到向量V3(X)并使用Mag得到其长度,根据长度判断,0的话,该子表面与Y轴平行,那么它的V3(X)就是<<1,0,0>>,非0有夹角。使用Cross来计算V1和V3的切线并且使用Unit规格化后得到向量V4(Y)。这样我们就有了这个A物体中每一个子表面网格的中心坐标和朝向V1(Z)、V3(X)和V4(Y),用脚本循环复制B物体的时候需要对其进行旋转,使用Rot向量计算出来弧度,将弧度转换为角度后再来旋转它,使它与子表面网格朝向一致(图3)。

图3

V3(X)的计算公式伪代码:Vector V3(X)=unity(cross(V1(Z),V2));

V4(Y)的计算公式伪代码:Vector V4(Y)=unity(cross(V1(Z),V3(X)));

接上来将实验对象跟具体化,制作一个芝麻和一个汉堡的面包模型,尽量符合实际尺寸和比例,并且细分模型使模型网格数量足够多,这样可以得到更多的外观差异和多样性(图4)。

图4

增加分布的随机度,给位置、旋转和缩放的对应分量加上随机数,这样会看起来自然很多,也可以进一步形成一个基本的算法。随机度在位置上我们可以给得到的C点添加类似Rand或者Noise随机值,为了只在子表面上移动,所以只能在物体的局部坐标系上移动,同时还要考虑移动后不要离开子表面、超出边界;在旋转上我们只旋转Y轴(与网格法线平行),根据实际情况判断哪个轴可以旋转以及旋转的最大值和最小值极限,可以把属性对应的参数,编写到插件界面上,提供给用户来自定义变量的值;在缩放上我们采取跟位移和旋转类似的处理方法。

增加可分布的样本,将B复制物体多做几个不同外观的模型,编辑成为一个组或者资源库文件,放到数组中保存,用脚本循环从中随机选取。

做更多的测试,比如甜甜圈上的糖粒。

效果展示视频链接:https://www.bilibili.com/video/BV1Mf4y1z7x9/或B站搜索“体育场的老李”,稿件中搜索“表面分布”。

3 结论

需要解决的问题,当增加复制物体的数量和随机度的同时,也要考虑因分布的位置太近而导致的重叠,或者超出表面界限之外,接近表面边缘的不和其他表面的同种情况重叠。虽是随机的但也要判断其合理性。

当网格比要复制的物体小的话,如果从每个子表面去分布就会出现重叠,需要解决模型网格不均匀和过小所带来的问题。忽略小的子表面,或者合并计算。也可以增加更多的自由度,比如网格大的复制的数量多些,用面积缩放密度,或者用黑白图来控制密度,甚至是面的法线于世界坐标系的Y轴角度的不同来控制密度。可以通过重建模型网格来解决密度问题,也可以根据模型的UVs来计算分布状况,再转换到三维空间的表面上。也可以通过边界盒,约束等来进行辅助计算。

总体的分布数量控制,不根据表面的面数多少,同样不依赖面的大小。还可以分层控制,比如一个表面分两层去分布,A物体分布1%,B物体分布36%等;也可以不同物体在不同层上制作不同分布比例,来得到更多的随机性,看起来更自然。

通过上述实践,我实现了想要的基本效果,从中可以看出把复制物体可以换成复制曲线,来创建毛发;或者替换成别的模型来实现不同的分布、离散复制效果,比如花园;表面发射粒子、表面破碎效果等。通过对某个效果的基本算法的研究,我们不仅可以更好的利用已有的软件功能,还可以通过编程来实现自己的想法,编写出工具来提高制作效率,写出拥有自主知识产权的插件。

附录:早期相关研究,我在国外网站https://www.highend3d.com/上发布的插件“3D particlizer for Maya”(2013年),用户名“libo19780926”,利用模型边界盒,自己写算法,将模型表面像素画、元素化,用小方盒替代。

猜你喜欢

坐标系向量物体
向量的分解
独立坐标系椭球变换与坐标换算
聚焦“向量与三角”创新题
深刻理解物体的平衡
坐标系背后的故事
三角函数的坐标系模型
求坐标系内三角形的面积
向量垂直在解析几何中的应用
向量五种“变身” 玩转圆锥曲线
揭开物体沉浮的秘密