Maya用particle的instancer模拟爆破墙效果
- 2022-03-02
- 来源/作者: PS.ONEGREEN.ORG / 佚名
- 3 次浏览
初始化位置
首先打开2_1_instance_brickwall_base.mb文件,在这个文件里可以由一组砖组成的一面墙。这面墙是由一些砖块组成,稍后我们将用一些破砖代替它们,来让我们看看这个场景是怎么样设置的.
设置如图。
1、所有的砖都需要freeze transform。
2、我们需要建粒子去发射它。可以运行这个命
令://create particle node particle -n wall_front_PTL;3、创建一个属性,当开始播放场景的时候我们将用这个属性旋转砖块。打开粒子的属性栏,增加一个per-particle的属性,名称为rotationPP。
4、粒子将从每一块砖的位置发射。我们首先从所有的节点中捕获一个列表,然后循环每一个节点,用emit命令从每个节点的位置发射粒子。老外用了这样一段脚本来完成这个操作。
emit_brick_particles.mel:// 获取前墙砖的名称列表string $nodeList[] = `ls -dag -type transform "o_frontWall_LOC|*PLY" "i_frontWall_LOC|*PLY" "side_frontWall_LOC|*PLY"`;
// 用循环语句让每一块砖发射一个粒子for( $node in $nodeList ) { // 得到每一块砖的位置 float $p
os[] = `xform -q -ws -t $node`; // 确定每一块砖的大致体积 // 当我们破碎砖块的时候就会用到: float $bb[] = `xform -q -ws -bb $node`;
float $x = abs( $bb[3] - $bb[0] );
float $y = abs( $bb[4] - $bb[1] );
float $z = abs( $bb[5] - $bb[2] );
vector $v = <<$x, $y, $z>>;
// 得到砖的长度float $vol = mag( $v );
//发射一个粒子 emit -o wall_front_PTL
-pos $pos[0] $pos[1] $pos[2]
-at mass -fv $vol;
} // for $node in $nodeList
// 将
此时的粒子保存为初始状态saveInitialState wall_front_PTL;
[NextPage]
5.记录粒子产生的次序。因为砖和粒子之间没有真正的关联,我们不得不依靠maya的物体列表清单。按字母顺序获取$nodelist变量里的列表,这是非常重要的一点,这将帮助我们正确的对砖块进行instance。
6.我们现在为每个粒子建立instance.我们将像前面发射粒子一样定义这个列表。
//选择砖块
select -r `ls -dag -type transform "o_frontWall_LOC|*
PLY" "i_frontWall_LOC|*PLY""side_frontWall_LOC|*PLY"`;
7.选择菜单particles>instancer(Replacement)>optionBox.在instanced objects列表里,你将会看到你所选择的按字母顺序排列的所有砖块。单击create 按钮,你会看到instance物体已经出现了。
你会注意到有些砖的位置不正确。当你使用默认值创建instance时,instance会使用列表中的第一个物体。我们将指定instance使每个粒子使用它相同位置的砖。因为在前面我们已经正确的设置了我们的粒子和instance,所以现在就可以简单的将粒子的ID作为砖的列表索引。
8.选择粒子wall_front_PTL打开属性编辑器找到instancer一栏。
9.打开objectindex下拉菜单,设置为particleID,我们将看到砖块已经恢复到了正确的位置。
>10.先添加一个per-particle属性,名称为rotationPP,打开rotation下拉菜单,设置为rotationPP。
当这些砖移动的时候,我们将用这个属性使砖产生翻滚的效果。
[NextPage]
开始模拟
有趣的事马上就要发生了,我们会从内部炸毁这面墙。我们遇到的第一个问题是重力,怎样使砖块受到重力影响呢,在它们被推出去之前不让它们发生移动。有许多方法:
味 1)在粒子的runtime expression里创建一个重力,当粒子的速度不为零的时候它将受到重力影响,如果粒子已经接触到了地面,将它所受的重力设置为0。
//获取位置vector $pos=position;
//如果粒子已经移动,并且没有掉到地面上,受重力影响。
if(mag(velocity)>0&&$pos.y>0.01)
velocity+=<<0,-32.17,0>>;
2)创建一个真正的重力场,将它的volume shape设置为cube。将它的位置放在墙的前面,当粒子被推出去以后它就会受到重力的影响。
第二种方法比较实用,如果你的场景物体不是很规则,那可能需要建立很多个重力场,并确保他们互相不交迭。
现在我们打开2_2_instance_brickwall_s
im_base.mb,前面砖墙已经设置好了instance,一些场和碰撞物体将在适当的时间将砖墙碰出去。如果现在播放,会看到砖被推了出去掉在了地上。这是因为有许多的场和碰撞物体来模拟这个爆炸动画。可以看到在砖飞出去的时候并没有旋转,现在我们来加这个效果,让砖旋转着飞出去。我们将根据一些因素来旋转这些砖:
a.砖的速度。
b.砖的质量(大的砖相对重一些,因此它们转的会慢一些)。
c.上面的砖朝一个方向旋转,下面的砖会朝另一个方向旋转,距离爆炸中心的会旋转的快一些。
[NextPage]
d.用一个随机数值去乘以旋转值,让它们的速度有些变化。
现在我们要为粒子增加一些属性。因为我们是使用emit命令来发射的粒子,所以它们的创建表达式将被忽略。我发现可以在运行表达式中创建一个“假的”创建表达式。这个创建表达式将出现在第二帧,是在爆炸前运行。
我们也可以用epicentre_LOC
这个locator的位置来决定爆炸什么时候发生。1.首先,我们给wall_front_PTL的粒子增加几个per-particle的属性。3个per-particle float属性的,名称为rotXPP,rotYPP和rotZPP,1个per-particle float属性的,名称为magVelPP。
2.接下来,我们创建这个“假的”创建表达式。它将运行在模拟之前,在runtime expression中输入下列表达式:
//假的创建表达式if(frame==`playbackOptions -q -min`+1){
//获取位置
vector $pos = position;
//获取质量,并且取它的倒数
float $mass=1/(mass);
//获取爆炸中心的位置
float $epicentreF[]=`xform -q -ws -t epicentre_LOC`;
vector $epicentre=<<$epicentreF[0],$epicentreF[1],$epicentreF[2]>>;//确定粒子和爆炸中心的距离
float $distToCentre=mag($pos-$epicentre);
//定义旋转值
float $rx=deg_to_rad(deg_to_rad(rand(-10)));
float $ry=deg_to_rad(deg_to_rad(rand(5)));
float $rz=deg_to_rad(deg_to_rad(rand(2)));
//根据粒子与爆炸中心的关系修改旋转值
if($pos.y<$epicentre.y)$rx*=-1;
if($pos.x<$epicentre.x)$ry*=-1;
//根据粒子与爆炸中心的距离关系修改旋转速度
float $distNorm=1-smoothstep(0,10,$distToCentre);
//最后为粒子指定旋转值
rotXPP=$rx*$distNorm*$mass;
rotXPP=$ry*$distNorm*$mass;
rotXPP=$rz*$distNorm*$mass;
}//假的创建表达式结束
[NextPage]
3.现在我们继续给增加运行表达式
//获取旋转值
vector $rot=rotationPP;
//获取速度
//确保当粒子没有移动的时候不旋转。
magVelPP=smoothstep(1,30,mag(velocity));
//加上现有的旋转值
float $rx=$rot.x+rotXPP*magVelPP;
floa << 上一页 [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] ... 下一页 >>