Maya粒子替代实现射箭效果由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“maya粒子替代脚本”。
Maya粒子替代实现射箭效果
粒子替换实现射箭的效果的最大问题在于,如果用粒子的速度velocity作为instancer的Aim Direction,那么一旦粒子与地面产生碰撞(这里我们碰撞属性中的摩擦力Friciton设置为1,弹力Resilience设置为0),势必导致速度瞬时变为0,使得箭无法插在地面上,而是一碰到地面就倒下。
于是网上找了一下相关教程特别是G_no_mon的在线教程给了我很多提示。国内大部分相关教程也是翻译的那个版本,该教程提供的解决方案是使用了一个JMS的脚本,先是通过记录粒子的运动轨迹生成若干条曲线,然后将曲线上的的末端的一些点给删除了(也就是粒子碰撞地面后生成的轨迹点),最后让剑沿着这些曲线做“路径动画”。从而实现乱箭射在地面上(或是其他物体)的效果。
研究过程中觉得用JMS脚本来一遍一遍的计算生成曲线有些浪费时间,而且对于我们这些maya初学者来说。既然我们不能直接用velocity作为instancer的Aim Direction,那么我们可以自定义一个变量用来存储粒子在碰撞前一帧,速度还没变为0的那个速度值,用该矢量速度值作为箭插在物体上的方向。
1.先制作一只简单的箭
2.制作一个地面,和一个用来发射箭的面
3.选择用来发射箭的那个面,通过Particles > Emit form object,从该面上发射
粒子
4.打开粒子发射器属性: Emitter Type :Surface Rate(particles/Sec): 5
Speed : 20 Speed Random: 4
5.给粒子加个重力场
6.选中粒子和地面,打开菜单命令Particles > Make Collide 后面的属性对话框,将弹力resilience设置为0,摩擦力friction设置为1,点击Create生成碰撞事件
7.执行Play场景,看到粒子与地面产生正确的碰撞,并停止在地面上(如果地面凹凸不平,会有滑动,不妨,这个我们稍后解决)
8.先选弓箭再选粒子,打开菜单命令Particles > Instancer
9.打开粒子属性中的Instancer一栏,勾启Allow All Data Types,AimDirection设置velocity,此时播放我们就会发现剑一射中就立马“爬”下了
10.解决这一问题需要添加一个自定义属性,在粒子属性窗口中Add Dynamic Attributes一栏中,点击General,添加一个名为DirPP的每粒子属性,类型为Vector
矢量(此处一点要注意)
11.右击DirPP属性,添加Runtime before dynamics表达式:
float $Speed = mag(arrow_particleShape.velocity);
if($Speed!= 0)
{ arrow_particleShape.DirPP = arrow_particleShape.velocity;
} 这里详细解释一下,我用$Speed来存储粒子的速率(速度是个矢量,是三维的,速率是个标量,是一维的,函数mag()正是将三维的矢量计算得到一个相应的一维标量),只要粒子在运动,速率不为零,那么我自定义的DirPP将不停的更新为粒子的速率,而一旦碰撞产生,速度为零,那么我的DirPP就不会更新,所存储的是粒子停止之前一帧的那个速率,并且之后也将一直存储这个值,这样我们就可以用这个DirPP作为
Instancer的AimDirection了
12.修改粒子属性面板中Instancer一栏中Aim Direction 为 DirPP,在播放一下看
看,箭就不会射中倒下了
13.接下来要解决的问题就是,即便摩擦力为1,弹力为0了,箭还是会在地面上滑
动
这里我们为粒子添加个runtime after aynamics的表达式: float $Speed = mag(arrow_particleShape.velocity);
if($Speed
{ arrow_particleShape.velocity = >;
} 这样,当粒子在碰撞时速度小于一定值后我们将其速率强行限制为>,注意,你也可以试试其他的数值不一定用4,但数值不宜过小,否则箭在射出的一瞬间会有
个抖动。
14.这是我们发现即使箭的速率为零了,但还是会在地面上滑动,我想到的解决方法还是和上面的差不多,用一个自定义的PosPP来存储碰撞产生前一帧的position,以
此来作为箭插入地面后的永久坐标
选中粒子,添加自定义的每粒子属性PosPP,类型还是Vector(矢量)
15.右击PosPP添加runtime before daynamics的表达式,这里我直接在原先的表达
式的做些添加就可以了,修改后如下
float $Speed = mag(arrow_particleShape.velocity);
if($Speed!= 0)
{ arrow_particleShape.DirPP = arrow_particleShape.velocity;arrow_particleShape.PosPP = arrow_particleShape.position;
} else { arrow_particleShape.position = arrow_particleShape.PosPP;
} 后果有朋友看不懂,我再解释一下其意思:每过一帧,只要粒子速度不为零,我就将粒子的坐标值position赋给PosPP,一旦产生碰撞,速度为零了,那么也就停止了position赋值给PosPP这一操作,我的PosPP存储的值是粒子停止前一帧所处的位置,接下来,我们反过来将这一固定了的值赋给position,以防止例子因为重力场的作用会出现position不停地在一个范围内抖动的结果。
16.至此,整个过程也就差不多完成了,你也可以再为粒子添加一些扰乱场,不用担心
箭射到地面出现抖动情况了
17.多亏一位朋友的提醒,以上的射箭效果有个问题就是箭在射出的一瞬间是水平的,修正这一点需要在creation下添加一个表达式:
arrow_particleShape.DirPP = arrow_particleShape.velocity;