Maya教学-实例 星球大战能量盾
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
[教程] Maya教学-实例星球大战能量盾
Mel与Particle的使用)
大概内容是:红色的激光击中蓝色的圆形能量盾,然后在能量盾的表面激起一圈能量涟漪,沿着表面扩散并逐渐消失。
下面是几张参考图,在文章的末尾有avi视频(1.68M),建模DWF 文件(52k)和mb源文件(11k)的下载连接。
要求:
1. 涟漪在激光与能量盾的碰撞点开始扩散(捕捉particle在碰撞物体上的UV坐标)
2. 涟漪应该沿着球体表面扩散。
思路:
激光和涟漪我都用到了particle。
首先让激光(粒子)与nurbs球体碰撞,并产生碰撞事件,同时捕捉碰撞粒子在nurbs球体表面的UV坐标。
然后碰撞事件为每一颗碰撞粒子产生新的粒子(大约600颗),让这些粒子与nurbs球体产生goal,然后拿这些粒子利用goalU、goalV 随机分布在碰撞点周围十分小的半径内,并强迫它们形成圆环的形状,最后让这个涟漪沿着表面扩散开来。
制作:
1. 在建立好nurbs球体和粒子发射器后,确定粒子与球体发生碰撞,在碰撞事件中,钩选All Collisions和Emit,设定Num particles为600,并将Spread和Inherit Velocity设为0。
我们现在就来获取碰撞点在nurbs球体表面的UV坐标。
打开激光粒子(施加碰撞的粒子)的属性编辑器,展开Add Dynamic Attributes箭头,点击General按钮,在弹出的Add Attribute窗口中点击Particle标签,你会发现粒子本身就有两个属性:collisionU、collisionV。
增添了这两个属性,就能轻易的获取碰撞点的UV了。
好,添加进来让我们试试吧。
2. 保险起见,让我们把粒子的寿命延长到无限,然后在碰撞后不要让它弹起(把resilience、friction分别设为0、1),这样粒子就会在碰撞到nurbs球体的表面后待在原地不动了,现在趁机获取它的UV坐标! 你可以通过这样的方式得到数据,在script editor窗口输入: particle -at collisionU -id 12 -q particle1 这句命令的意思是:返回第12颗粒子的collisionU属性的值。
结果是-1。
你可以再试试其他的粒子......结果都是-1,无论碰撞前后它的值都是-1! maya的帮
助文档里有提到:
U and V positions of the NURBS surface where a particle collided in the current frame. For polygonal surfaces, the values are always 0. The values are reset to -1 at the start of each frame. Values change only in frames where collision occurs. These are read-only attributes.
那意思是说,只有碰撞的一瞬间,collisionU和V才获得有效的值,之后它的值被maya改回为-1。
所以你不能让maya停下来再去获取collisionUV的值,你只能在碰撞的瞬间获取它。
你可以这样做:
假设激光的粒子叫particle1,涟漪的粒子叫particle2。
先给particle2两个自定义属性:hitU、hitV(记得是float型数据,per particle型属性)那么你在particle2的creation expression下面这样写:
particleShape2.hitU = particleShape1.collisionU;
particleShape2.hitV = particleShape1.collisionV;
不过你在测试的时候会发现问题,虽然有时这会返回有用的collisionUV值,不过有些particle1如果没有与nurbs球体发生碰撞的话,就会返回-1。
而且当粒子数量大的时候,maya 会很慢,因为每产生一颗粒子,maya就会检索一遍particle1的所有粒子的碰撞UV值,你应该只去抓取发生碰撞的粒子。
所以应该这样写:
float $colli_U[] = `particle -at collisiontU -id ? -q particleShape1`;
particleShape2.hitU = $colli_U[0];
float $colli_V[] = `particle -at collisiontV -id ? -q particleShape1`;
particleShape2.hitV = $colli_V[0];
-id后面的那个问号代表查询particle1的哪一颗粒子,可惜我也不知道!至少我不知道简单的方法。
希望chinavfx的朋友们看后告诉我。
3. 不过别着急。
让我们在碰撞event(事件)那里看看,还记得这个属性吗?(如图:)
点击help按钮看看都说些什么:
你可以自定义一个程序,它只在碰撞发生的瞬间才去执行。
但必须是这样的格式:global proc myEventProc(string $particleName, int $particleId, string $objectName)
所以在这个程序里将$particleId导出就可以了,因为它一定是发生碰撞的粒子才会传递到这个程序里。
4. 程序如下:
global proc myEventProc(string $particleName, int $particleId, string $objectName)
{
global int $myEventProcGlobalId;
$myEventProcGlobalId = $particleId;
particle -e -at lifespanPP -id $particleId -fv 0.001 $particleName;
}
把这段程序存成单独的文件,取名myEventProc.mel ,然后再scripte editor里键入这句命令:internalVar -userScriptDir,你会看到返回一个目录,就把myEventProc.mel放在那里,最后记得在碰撞事件里填入这个程序的名字。
在这段程序里你会注意到我使用了全局变量:$myEventProcGlobalId。
名字有点长了。
不过它的作用很简单,就是让particle2知道该获取哪个粒子的id号。
下面会讲到为什么是全局变量。
6. 在particle2的属性里添加goalU、goalV、hitU、hitV,然后再creation expression里建立如下命令:
global int $myEventProcGlobalId; //myEventProc.mel里的那个全局变量,由于程序被置于
maya的外部,因此你就应该在这里重新申明一下。
全局变量(global variables)使用的是同一个地址,所以当myEventProc中的全局变量改变时,这里的全局变量也会立即作相同的变化,所以particle2就知道该获取哪一刻粒子的碰撞UV了。
particleShape2.lifespanPP = 2.5; //涟漪的生命周期为2.5秒
float $collisionU[] = `particle -at collisionU -id $myEventProcGlobalId -q particle1`; //从particle1那里收取id号为$myEventProcGlobalId的粒子的collisionU的值
float $collisionV[] = `particle -at collisionV -id $myEventProcGlobalId -q particle1`; particleShape2.hitU = $collisionU[0];
particleShape2.hitV = $collisionV[0];
vector $goalUV = unit(`sphrand <<1,0,1>>`)*0.0001 + <<particleShape2.hitU,0,particleShape2.hitV>>; //在碰撞点周围随机分布成圆环状particleShape2.goalU = $goalUV.x;
particleShape2.goalV = $goalUV.z;
这段程序是将新粒子随机分布在碰撞点周围0.0001的半径范围内,并且成圆环形状。
然后在particle2的runtime expression里输入如下命令:
float $length;
vector $center_position = <<particleShape2.hitU,0,particleShape2.hitV>>;
vector $current_position = <<particleShape2.goalU,0,particleShape2.goalV>>;
vector $spread_direction = $current_position - $center_position;
$length = mag($spread_direction);
$spread_direction = unit($spread_direction) * ($length + 0.006) + <<particleShape2.hitU,0,particleShape2.hitV>>; //让particle2的半径越来越大。
particleShape2.goalU = $spread_direction.x;
particleShape2.goalV = $spread_direction.z;
它会驱动圆环半径越来越大,并且始终贴着nurbs表面,因为goal的缘故。
7. 到这里就基本完成了。