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

豆芽兵的生存探索

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

 
 
 

日志

 
 

第五节 用Get&Set改变属性  

2012-05-31 08:26:19|  分类: RealFlow探索 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索
 

5.1简介

现在你已经学会了RealFlowPython脚本基础知识。你可以遍历发射器所有粒子,也明白了向量和else-if语句。接下来的这节,是关于获取(Get)和设置(Set)RealFlow属性值的。这是RealFlow拓展的Python核心内容。通过getset语句,你能直接访问发射器,模型,辅助器等等所有的参数。

 各种getset语句似乎是无穷无尽的。所以要精炼地讲解这些。本节,我们讲解大部分通用的getset指令。RealFlow也提供了命令用来Get&Set点(vertices),几何面(polygon face),动画帧(animation keys),图片像素(image pixel)等等更多东西。

你已经学习过的一些语句:

 getEmitter( )

getPosition( )

getFirstParticle( )

getNextParticle( )

这些指令曾用来获得场景中发射器,访问单独粒子或得到粒子位置数据。用不同的get指令,得到不同的值和结果,例如,Integers,Vectors,Floats String.

在线帮助手册,有很多不同的getset指令。这些指令都写成一种特定的形式,像:

Emitter getEmitter( string )

Object getObject( string )

第一个单词描述了接受对像类型,像emitter,objectcamera,mesh等等。第二部分是特殊的get指令,能用于很多参数和RealFlow对像。

下一个单词决定了数据类型,你必须使用这个特定的指令。

数据类型指定了,什么样参数可以使用:

Particle getParticle( int )

这个操作被用来取粒子的值,是一个Integer。添加一个辅助器,string型,如用Gravity01,会导致出错。

有时手册给出更多提示:

Emitter [] getEmitters( )

方括号[ ],意思是数据类型是一个List。你还记得吗?标量只能存储一个值,而List可以携带两个或更多的值。

所有可用的命令只有一种工作方法,像例子中讲的。一条表达式,你能预测对像和数据类型,如果你不确定,就参考一下手册:

? Help > Contents... (opens a new application) > Index

? Help > Contents... > Contents > Scripting Reference

第二条检索方法更有条理,是按对像类型排列。

 (上面格式一定要记牢,这是进入帮助学习的钥匙。大部分时候我们写脚本,要不断的参考帮助,但如何看懂,就是这里说的)

5.2怎样去用 Get &Set

get set语句原理很简单,但非常好用,因为可以直接联系到RealFlow的用户界面。这两个命令完全共享同样的名称,你可以在节点(Nodes)和节点参数(Node Param)窗口看到。主要区别是getset命令需要的参数(number)和数据类型参数不同。这命令不仅可用于遍历粒子,它们可以用在任何地方。

 第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索

 在这个例子里,Cone(圆锥体)已经添加到场景。参数列表包含了所有你需要使用的对像参数。最有趣的参数都在Node 标签下。在这你能找到最基本属性,像位移(position),Rotation(旋转)或Scale(缩放).在线帮助文档介绍的相应的get参数如下:

any getParameter( any )

告诉我们getParameter命令可以使用任何对像或任何数据类型。操作不限于参数,发射器,或摄像机。数据类型也可以是Integer,Float,Vector等。

 你的数据类型可以使用getParameter命令,从Node标签下读出。当你看到三元值时,一定就是矢量:

Position  0.0  0.0  0.0

Rotation  0.0  0.0  0.0

Scale     1.0  1.0  1.0

Pivot     0.0  0.0  0.0

请注意:单个的矢量值(分量)是Float类型。甚至颜色也是用三个值,红,绿,蓝(RGB).SimulationDynamice数据类型是String(字符型).字段可以包含字句或表达式:

Simulation     Active

Dynamics      No

如果WetDry贴图设置为Yes,你可Integer值,像

 @ resolution 256

 @filter强度和@ageing值也是Float类型。

如前面所说,你要知道,get命令会输出什么数据类型,因为是setParameter的逆过程。你用确切的数据类型去改变合适的值。让我们看一个例子:

cone       = scene.getObject("Cone01")

pos_global = cone.getParameter("Position")

 结果是一个矢量,由三个Float组成。当计算完成后,你可以建立一个新的矢量。新的向量必须也要有三个Floatintegers也是可以的)。你不能用String去替换。不然会产生语法错误:

 pos_new   = Vector.new("left", "up", "right")

下一个例子是一个完整的脚本。在RealFlow里准备一下,脚本作用是给圆锥y轴每帧位移增加0.2

 第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索Events Script: ChangeConeYPos.rfs

def onSimulationFrame():

 

 cone  = scene.getObject("Cone01")

 

  # 1. Get global position data in Vector format

  pos_g = cone.getParameter("Position")

 

  # 2. Get components from the position Vector

  pos_x = pos_g.getX()

  pos_y = pos_g.getY()

  pos_z = pos_g.getZ()

 

  # 3. Add 0.2 to the y component

  new_pos_y = pos_y + 0.2

 

  # 4. Build a new Vector

  new_pos_g = Vector.new(pos_x, new_pos_y, pos_z)

 

  # 5. Use the new Vector for position change

 cone.setParameter("Position", new_pos_g)


这个脚本与第三节的事件脚本非常相似。那个脚本增加了yz方向 所有粒子位移。这里,我们只是针对单个对像。get语句过程的,分离和组合是和向量一样的。主要不同是最后一个语句:

 cone.setParameter("Position", new_pos_g)

对于粒子,是这样:

    particle.setPosition(new_pos_g)

注意粒子与别的对像是使用不一样的setget命令。对emittermesh,是可以直接在对应Node参数窗口看到值的。PositionVelocity值不是都显示出来的。他们在内部使用。为了更快的访问速度和更好的区别,粒子属性不使用Parameter关键字。

 还有另外一个不同点:getParameter命令只能取得一个参数,名称是“position".setParameter显示了”position"new_pos_g.

 因此用setParameter你必须要告诉RealFlow你想用哪种类型的数据改变(Position,pivot,roughness),然后新的值要用正确的数据类型。

 在模拟时,可以在节点参数窗口监视更改的值。只是试一试y分量的position值。

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索
 13.圆锥在Y方向有一个恒定运动。
第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索小提示: 不要从直接从本文章复制脚本到RealFlow。不一样的字体,字符设置和空格,都将导致错误。手动输入脚本是最好的,还能思考脚本到底是如何工作的。

getParametersetParameter能获得很多乐趣,因为你能更改,改变,打开关闭几乎所有东西。一些任务可以手动方便的解决,但脚本更精确一点。特别是碰撞,有时不能轻松的得到完全相同的碰撞。在两个模型,或粒子之间。使用Python脚本,解决起来只要短短几行代码。这是初始情况:

 第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索

  我们目的是让物体落下,碰撞到地板。所有物体都处于不同的位置。手动停止他们,可能很难。这个场景仅有三个模型,但假如有 2030,或60个模型呢。根据你现在为止看到的方法,我们一直调用单个对像,如果有更多的对像时,就变成一个麻烦的事。为了使这个任务轻松,Realflow 有强大的对像选择工具。操作是,我将要用这个命令,名称是:

 getSelectedNodes()

 使用这个命令,你可以在节点窗口里选择到你想起作用的对像。

RealFlow分辨出你选中的,再把所有对像存储到List对像中。正确的表达式是:

items = scene.getSelectedNodes()

相像一下:选中三个对像,圆锥体(Cone),方盒(Cube),圆柱体(Cylinder),内部元素就会是:

items = [Cone,Cube,Cylinder]

下一步就是搜集所有正在碰撞到地面的对像项目。RealFlow也有能达到这个目的的函数。用这个命令要再创建一个List数据类型,因为有不只一个对像碰撞到地面:

floor             = scene.getObject("Floor")

colliding_objects = floor.getCollidingObjects()

现在,我们要通过列表浏览碰撞对像并适当停用掉原始物体

if (colliding_objects != [ ]):

   for object in colliding_objects:

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

 if条件语句检查,List colliding_objects 是否空的。表达式是

if (colliding_objects != [ ]):

意思是:如果 列表 colliding_objects 不等于空的,不执行下下面。空的列表写作[ ].你一种方法是检查列表长度(len)

如果碰撞物体检测到就把存储到colliding_objects.并把Simulation参数设置为Inactive(不活动)。换句话说:当物体一完全碰撞到地面,就会被设置为不活动,并释放封闭的流体。下一页你将看到这个脚本的列表。

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索

Events Script: InactiveOnCollision.rfs

def onSimulationBegin():

 

 items = scene.getSelectedNodes()

 

 for object in items:

   object.setParameter("Simulation", "Active")

   object.setParameter("Dynamics", "Rigid body")

 

def onSimulationStep():

 

 items = scene.getSelectedNodes()

  floor = scene.getObject("Floor")

  colliding_objects = floor.getCollidingObjects()

 

 if ( colliding_objects != [] ):

  for object in colliding_objects:

   state = object.getParameter("Simulation")

  if (state == "Inactive"):

   pass

  else:     

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

    object.setParameter("Dynamics", "No")

第一步分是初使化选中的项目并设置为活动。这在初使有多个模拟传递的情况下很有用,因为你不用每次模拟这个场景都要切换到之前值(初使值)。

 程序能识别所有与地面进行碰撞的物体,并把它们存储到List变量中:

colliding_objects = floor.getCollidingObjects()

最后的if语句只是做很小的(建设)检查,Simulation状态是否改变了。所以如果Simulation状态设置成Inactive,脚本什么也不做。

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索
 

14.碰撞后溶解(散开)

 唯一的不足是,物体要与地面进行完全碰撞(后才能散开),之前他们都是失活(inactivate)状态。

第一次接触后就保持活动状态。一个繁琐的方法是利用模型的面或点进行检查。你可以把碰撞的面加入到一个列表。如果列表的长度大于0,物体就变为活动。

然后检查每个步骤或帧的对像状态是否活动,优化脚本。

5.3使用粒子

现在为止,你学习到很多关于物体getset属性知识。正如我之前提过的,粒子有一个属于自己的类(class),并提供直接访问特殊的值和特征。当你想使用粒子时,你必须要创建一个循环函数并要单独调用它们。为了这一目的,需要区分不同发射器和粒子基本属性。发射器属性是直接显示在结点参数窗口里的:

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索
 
 更改这些值可能会导致RealFlow不稳定甚至崩溃掉。你要小心的更改这些值。用脚本发射器是可以安全的改变这些值。但这里我只想讲解发射器发射出的粒子。

 同时通过遍历粒子,可以访问各种属性。最常用的值可能是这两个命令:

getVelocity( )

getPosition( )

直接执行计算后,通过创建一个新的Vector是可以改变速度(Velocity)和位置(Position)。另一个值对改变参数是不重要的,但可以控制结构。例如DensityPressure.基于流体的物理参数,你可以创建泡沫。这是非常有用的方法制作真实的水花。这里有几个很重要也经常使用的指令:

getMass( )

getDensity( )

getPressure( )

getNormal( )

getNeighbors( )

 这些属性不出现在RealFlow窗口,因为他们仅仅用作内部计算。在这告诉你怎么使用他们:

emitter = scene.getEmitter("emitter_name_here")

particle = emitter.getFirstParticle()

while (particle):

 particle.getVelocity()

 particle.getPosition()

 particle.getMass()

 particle.getPressure()

 ...

 particle = particle.getNextParticle()

 在很多情况下重要的是获得(合适的值)。是大是小,是Foat还是Integer? 特别是使用if语句,知道(magnitude)大小是很重要的.RealFlow有可以输出任何各类值的函数:

 scene.message(str(variable_name))

 这条语句直接给出提示信息在RealFlow信息窗口,但在有些情况你可能得到像这样的结果:

 RealFlow vector at <0xdee2>

这结果像前面的结果,是显示当你从List,VectorDictionary输出的值。只要有一个以上的值存储在变量中,RealFlow就会显示成十六进制的值(hexadecimal).只有这些复合变量的分量才能输出成可读的:

vec_z = vector.getZ()

entry = list[2]


scene.message(str(vec_z))

scene.message(str(entry))

str命令是Python中把值转换为字符串的功能。只有这种数据类型可以显示在信息窗口。当然str也能改变多个变量。只要是用户定义的字符串,就要写在引号里:

vec_z = 3.5

entry = Cube04

scene.message(str("Values: "+vec_z+" / "+entry))

Result: Values: 3.5 / Cube04

 有了这个小助手,你可以用来估计值,判断或限制力的值。值得注意的是,场景输出信息时会显著变慢。

 一个好的小程序是对发射器的大量基础函数(使用)。

下面的脚本只是读出每个粒子的质量值,并将它们添加进去。如果总重量大于给出的阈值,发射器就停止发射粒子。当然这个脚本也能基于PressureDensity.

 正如你看到的脚本不必很复杂,但是有效。即使最简单的手段只要达到好的结果。用辅助器来做将很难达到,像这。

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索Events Script: StopOnMass.rfs


def onSimulationStep():

 

  total_mass     = 0

  mass_threshold = 1000

 emitter        = scene.getEmitter("Circle01")

 speed          = emitter.getParameter("Speed")

 particle       = emitter.getFirstParticle()

 

 while (particle):

   mass       = particle.getMass()

   total_mass = total_mass + mass

  if (total_mass >= mass_threshold): 

   emitter.setParameter("Speed", 0.0)

 

  particle = particle.getNextParticle()


这脚本再一次说明了最基本的道理,例如收集场景和粒子数据,或创建循环结构。还用了if条件语句触发粒子事件。如果total_mass变量达到1000mass_threshold),发射器速度(speed)就设置为0.0. 也就是说:阻止了新粒子的产生。这个脚本的好处是粒子的质量(mass)取决于它的密度(density)。在节点参数窗口设置Density 100.0 ,大约会产生10倍的超过标准密度1000的粒子:

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索

 第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索

 
另一个可能应用到的是操纵粒子的,辅助器脚本(Scripted Daemons.) 用辅助器能给粒子施加外部力。接下来的例子是给粒子施加很高的吸引力。

 第一步是创建辅助器脚本(Scripted Daemon):

 Edit > Add > Daemons > Scripted

 第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索  > Scripted

 你可以用这个默认的名称Scripted01或者重新设置一个新名称。在这个例子里我决定重命名为Heightdaemon.

第五节 用GetSet改变属性 - 豆芽兵 - 豆芽兵的生存探索Scripted Daemon: HeightDaemon.rfs


def applyForceToEmitter(emitter):

 

  accel    = -9.81

  factor   = 7.0

 emitter  = scene.getEmitter("Square01")

 particle = emitter.getFirstParticle()

 

 while (particle):

  pos_g   = particle.getPosition()

  pos_y   = pos_g.getY()

   gravity = accel / ((pos_y * factor) + 0.001)

  force   = Vector.new(0.0, gravity, 0.0)

  particle.setExternalForce(force)

 

  particle = particle.getNextParticle()


OK,让我们遍历这个脚本。第一部分是初始代必须的变量,accel是重力加速度(acceleration of gravity),factor是用来防止粒子减慢太快。factor值越小,最终的力就越强。while循环遍历Square01发射器的粒子并永久检查高度。

在循环中,脚本计算高度依赖重力:

gravity = accel / ((pos_y * factor) + 0.001)

在这个公式中有所有初始的变量。如你所看到的,脚本要计算除法,你得注意到不能让被除数为0.可能会使粒子直接离开发射器。避免0做被除数,我简单的加了一个很小的值0.001.由于计算法则,括号不是必须要的,但有时候它能提高可读性。表达式:

 ((pos_y * factor) + 0.01)

 也能写作

 (pos_y * factor + 0.001)

 因为乘(*)和除(/)有较高的优先级。下一步是创建一个新的矢量表示力,在y轴负方向。用辅助器脚本(Scripted Daemon)特别的指令 setExternalforce(force),新的力就会被添加。

总结

RealFlowPython脚本的可能性几乎是无止境的。例子,技术,或方法,可以写10本或更多,在这里我只是给脚本做了一个简单入门介绍。以下案例什么都可能涉及到。他们范围是从初级到中级,也会包含到高级脚本。也就是说本节,是最后纯技术的一节,后面都是案例了。所以本节,一定要反复阅读。本人读了不下20次。可能我比较笨。本节还有一个最大知识点就是教你如何用Realflow帮助,这一定要重视,是非常重要的。


  评论这张
 
阅读(2214)| 评论(7)
推荐

历史上的今天

评论

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

页脚

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