注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

豆芽兵的生存探索

因,记录。留下历史,看到未来...

 
 
 

日志

 
 

第八节:有趣的冻结  

2012-06-12 11:53:23|  分类: RealFlow探索 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索
 

8.1案例概览

 

冻结(freeze)函数是强大的能应用在很多方面的功能。文章第一部分介绍了基本的(Freeze)函数用法。稍后我们使用冻结(Freeze)函数制作粒子“融化”的效果。我们将用Null对像控制融化速度。我一直贯彻的目标是把思路和方法展示给你,鼓励你写出自己的脚本,或者拓展这些案例。

 

8.2冻结时间和粒子

 

子弹时间(Bullet Time),《黑客帝国》三部曲使用的非常多。简单说来子弹时间特效就是允许艺术家暂停运动的物体、人物或粒子,但摄像机还是保持移动。用RealFlow 3有几个很复杂的方法达到这种效果,但在RealFlow 4之后 Pyhton脚本,可以很轻松的做到。关键点就是当粒子停止运动时RealFlow还强制输出BIN文件。只要几行代码就行了:

    Events Script: BulletTime_001.rfs

def onSimulationStep():

 emitter  = scene.getEmitter("Circle01")

 frame    = scene.getCurrentFrame()

 particle = emitter.getFirstParticle()

 while (particle):

  if (frame == 25):

   particle.freeze()

  if (frame == 60):    

   particle.unfreeze()

  particle = particle.getNextParticle()

 

可能脚本只是简单了用了冻结(freeze)和不冻结(unfreeze),但结果是很炫的。这个脚本方便在,在时间冻结时发射器也停止发射粒子。

(译者注:经在RF2012试验,并没有像作者上面说的这样,冻结时发射器依然在发射。如果想要这样的效果。可给发射器速度key帧,或其它方法。)

让我们快速看一下脚本。主要部分是while 循环。这里,我们定义了frame(帧)区间,起始在25帧,结束在60.这个长度可以根据需要定义。在这个时间内,粒子不能运动。60帧时他们继续运动。另外也可以为了用户调节方便定制一个GUI

 

def onSimulationBegin():

 form    = GUIFormDialog.new()

 form.addIntField("Start Frame", 25)

 form.addIntField("Stop Frame", 60)

 # Transform user values into variables

 if (form.show() == GUI_DIALOG_ACCEPTED):

   start = form.getFieldValue("Start Frame

   stop  = form.getFieldValue("Stop Frame"

def onSimulationStep():

 emitter  = scene.getEmitter("Circle01")

  frame    = scene.getCurrentFrame()

 particle = emitter.getFirstParticle()

 while (particle):

  if (frame == start):

   particle.freeze()

  if (frame == stop):    

   particle.unfreeze()

  particle = particle.getNextParticle()

 

(上面这个脚本在运行时,start 变量总是报错。因为它是全局变量,没有声明。解决办法暂时没找到。关于全局变量,前面有介绍。)

请注意这里只是介绍了粒子的使用。要想让模型或其它从SD文件中的模型,有这种效果

我们需要用另外一种方法,在RF_magazine Cinema 4D Special Edition, page 30. 有介绍。在rf-magazine网站。(译者注:已经不存在了,现在是变成叫http://www.rf-toolfactory.com这个网站上相关教程都已经被译者在之前翻译了。作者介绍的这本书我也没下到,如果有心人有相关资料,希望共享一下

 

8.3粒子冻结循环

 

现在你知道怎么使用freeze 功能了。我们可以试试给这个效果加上动画了。下面场景创建了:一个发射器,一个Cube当地面,和一些碰撞物体。

 

我的想法是定义一个圈,向场景中心收缩。粒子在圈范围外面将会被冻结,里面的粒子保持流动。控制粒子速度和圈的半径来达到效果。建议用上替代物 Null,来调节脚本参数。(前面小结有介绍,你可以不用。只是为了把参数赋予到这些替代物体的某个轴上,方便调节)

 

我们只需要读出粒子的位移与当前替代物体X轴的值进行比较。若超过半径,外面的粒子就被冻结。要获取正确的粒子位移,我们再一次用到模长(Magnitude).

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 

 

这个例子场景用的Cinema 4D/Lightwave操作设置(检查自己的设置,不然结果会不一样)。Y轴是向上的(YXZMayaZ轴朝上).在我们的例子中,只需要检查粒子在平面上的扩散,对高度信息不关注。

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 图

25. 粒子在平面的位移

 

问题是,当前粒子位移pos怎么与虚拟的圈半径(r)进行比较。解决方法是用勾股定理计算向量的模长。在二维或三维空间计算矢量都一样。这是我们的公式:

c2 = a2 + b2

c = sqr (a2 + b2)

 

得到标量值C,然后可直接与半径r进行比较。在圆圈里,每一个点半径大体都会保持不变,所以我们不需要进行进一步的检查。

 

运用这些知识,我们可以写出这个小脚本,进行位移的检查。用辅助物体(Null,用cube也可以),用来定义边界。每一步(step,指的是RF内部时间机制,步长。)都会读出新的位置(position)。为了避免正负值的麻烦,我们要用上绝对值abs(radius),因为模长是正数。

 Events Script: CircularFreeze.rfs

def onSimulationBegin():

 

 emitter = scene.getEmitter("Circle01")

 emitter.setParameter("Speed", 2.0)

 

def onSimulationStep():

 

 import math

 

 emitter = scene.getEmitter("Circle01")

 helper  = scene.getObject("Helper")

 

 h_pos_g = helper.getParameter("Position")

  radius  = h_pos_g.getX()

 

 if (radius == 0.0):

  emitter.setParameter("Speed", 0.0)

 

 particle = emitter.getFirstParticle()

 

 while (particle):

 

  p_pos_g = particle.getPosition()

   p_pos_x = p_pos_g.getX()

   p_pos_z = p_pos_g.getZ()

   p_mag   = math.sqrt(p_pos_x ** 2 + p_pos_z ** 2

  if (p_mag >= abs(radius)):

   particle.freeze()

 

  particle = particle.getNextParticle()

(译者注:这里作者用的向轴是Y,如果你Realflow预设不是Cinema 4D/Lightwave操作设置,照此脚本写出来的结果会不一样哦。自己试试吧。

还有个小问题是,要做到下面图片上这样。不能直接慢慢让粒子发射,不然粒子是到不了圈外的。得在运行脚本前就发射,或给半径key帧,也就是上面的辅助物体的x轴。你可以给这个半径一个随机数。这样效果就更好玩了。)

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 图26.圈外的粒子被冻结了

 

def onSimulationBegin()块只是为我们提供方便,场景重设至其初始值。你应该从泡沫脚本案例学习了导入语句了(import statement)。在这里,我们导入的数学模块(math module),能提供Python的函数,像正弦(sine),余弦(cosine),平方根(square root)

 

为了加快模拟,前一个粒子已经被frozen。防止发射器在外面发射。当辅助物体靠近场景中心条件满足:

 

if (radius == 0.0):

 emitter.setParameter("Speed", 0.0)

 

 

这里使用了勾股定理:

 

p_pos_x = p_pos_g.getX()

p_pos_z = p_pos_g.getZ()

p_mag   = math.sqrt(p_pos_x ** 2 + p_pos_z ** 2)

 

正如你从图上看的,粒子行为很精确。圈边界粒子比较多,说明速度慢

 

当然脚本还能拓展,,如用椭圆形,长方形或其他形状。

8.4解除冻结粒子

 

你已经学习了许多关于freeze的语句。此时估计你会引发一个疑问,是否能使用freeze让粒子快速稳定下来?如你想要一个平静的液面时,你得等待好长时间才能让粒子稳定下来。freeze功能似乎是一个比目前,所有已知的方法都要好,但真是这样吗?

 

(译者注:之前有发过一个关于放松流体的教程,可以参照学习一下。)

 

我们得知道用freeze函数,只是简单的在某一个点停止粒子。粒子的能量还是会被保留下来。解除冻结(unfreeze)后,就像什么也没发生。(环境保持不变)因此,冻结功能,可视为当前运动的停止,而所有的参数和值保持不变。

(译者注:就像时间静止一样,这也是能用来做子弹时间的原因。还有一个很好玩的应用。延时运动,处理一些特别的问题。译者后面会有更多关于子弹时间的探讨)

 

已知放松粒子的方法是:真正的随着时间,等能量慢慢消散。原理是使“水分子”的之间空间变得越来越小。粒子能量逐步减少。再用初始状态做进一步实验,稳定粒子。

 

冻结功能仅仅适合:你想保持速度,能量,动能,或锁定粒子当前形态时。不能用来放松粒子,稳定粒子。

 

8.5解除冻结(unfreeze

 

到现在为止,我们是只用Python来锁定粒子,可这仅仅是一半的功能,因为RealFlow的也有解冻(unfreeze)方法。解冻功能很大部分用来做融化的物体或人(《终结者》看过没,就是这个参数来融化的)。如果你通过定义边界,你只能删除一部分,或用风场让其消失。还是用unfreeze来试试,为了快速做这些效果,加一个动画辅对像是必要的。这些小的辅助器用处可不小,可以让设置可视化。

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 

27.默认火箭模型消融

 

脚本本身可没有施魔法,我们只是用了学过的方法和技术。当设置的条件成立,主体部分释放的粒子位移与辅助物体高度进行比较。同时使用age了函数,让粒子在一定时间内消失。这里不需要Age辅助器,因为只是简单的静止,只要一小会,所有粒子都会消失,或是冻结。为了避免这些,我们要引入自己的age函数。释放的粒子(有一定的寿命age),将通过他们的ID,从发射器删除。你已经在泡沫案例脚本见过这一方法了。在那里,我们转移粒子到泡沫发射器,然后从water发射器(水的粒子发射器)删除。几乎一样的方法。

 

定义辅助物体的速度velocity,到底多快或多慢的粒子会被释放。确切的还需要做一些测试和调节,直到你满意。再加上一些辅助器,就能做很不错的效果和动画

 

 

第八节:有趣的冻结 - 豆芽兵 - 豆芽兵的生存探索

 Events Script: ObjectDissolve.rfs

def onSimulationBegin():

 

 emitter = scene.getEmitter("Fill_Object01")

 rocket  = scene.getObject("Rocket01")

 

 particle = emitter.getFirstParticle()

 while (particle):

  particle.freeze()

  particle = particle.getNextParticle()

 

 rocket.setParameter("Simulation", "Inactive")

 

def onSimulationStep():

 

 import random

 

  age_threshold = 0.5

 emitter       = scene.getEmitter("Fill_Object01")

 helper        = scene.getObject("Helper")

 h_pos_g       = helper.getParameter("Position")

  h_pos_y       = h_pos_g.getY()

 

 particle = emitter.getFirstParticle()

 

 while (particle):

  rand    =  random.uniform(-0.2, 0.2)

  p_pos_g = particle.getPosition()

   p_pos_y = p_pos_g.getY()

   age     = particle.getAge()

  

  if (p_pos_y > h_pos_y):

   particle.unfreeze()

 

   if (age >= age_threshold + rand):

     id = particle.getId()

emitter.removeParticle(id)

 

  particle = particle.getNextParticle()

 

(如果你试验有误,同样要检查向上轴。如果你不想改,就把脚本中的Y,都换成Z

 

onSimulationBegin函数初始化我们的场景,包括从Fill(对像)发射器冻结所有可用的粒子。第二步是使火箭模型失活(inactive),在代码里设置粒子对像。

 

unfreeze条件只是简单的if语句,试验辅助器Y轴(高度)是不是超过粒子。在这个释放的粒子组中进行粒子检查。改变age_threshold值你可以容易的增加/减少生命值(life span)。如果你不想让粒子消失,你只要简单的忽略掉年龄检查。

 

8.6 总结

 

本章后面内容,只是为了提高你的能力,你可以只用RealFlow的那两个功能。所有的脚本非常短,也只用了基础的数学知识。只要一点点努力就能做很炫的东西。前提是你要下定决心花一点时间开始动手写你的脚本。

 

请记住,总有不只一种方法去解决问题的。这里介绍的脚本都有不止一种方法来解决问题。可能你能发现一种更短更好或更快的方法,但在里没有写出来。没有必要写一个很复杂或花很长时间才能写出来的脚本。看具体情况罢。

 

译者注:本章还是挺有意思的,虽然只有两个函数freezeunfreeze.请你一定要动手写。我之前也是,只看,最后学的很慢。抛开复制粘贴,从手动输入开始。译者很愚钝,这些反复看了很多遍,大概数字在50遍,手动输入了也不下20多遍。一句一句看,一个一个查,不会就看帮助手册,和翻看上面基础部分,才慢慢理解。不要以为我是什么高手,我跟大家一样,都在学习。不断不断的练习。勤奋总没有错。以后我再多分享一下译者的学习习惯和方法,因为我发现这些东西比真正的技术重要的多。

Good Luck!

  评论这张
 
阅读(2693)| 评论(16)
推荐

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017