2012-05-29 08:36:57| 分类: RealFlow探索 | 标签: |举报 |字号大中小 订阅
4.1调用 发射器(Emitters) 和 对像(Objects)
现在你的毅力和耐心终于得到回报,因为你将使用RealFlow的Python做出第一步了!
首先创建一个 Circle 发射器:
Edit > Add > Emitters > Circle
> Square
现在结点窗口会出现一个新的叫 Circle01 的对像。要在脚本中使用这个发射器,你必须创建一个变量,把它存储在里面。我们在这声明一个标量:
emitter = scene.getEmitter("Circle01")
emitter是变量名,scene告诉Python在结点面板寻找叫 Circle01的发射器。在这句话中的基本关键字是getEmitter,是用来获取对像的。
现在增加一个Torus 对像。要达到这个目的,只是用了非常近似的表达式:
object = scene.getObject("Torus01")
在这个例子,变量是object,用 getObject关键字从基本scene中获取Torus01。
当然,有时候需要改变对像的名字。比如说你想把 Circle01名称换成Water.为了再次确定发射器,你也需要在脚本中改变一下:
emitter = scene.getEmitter("Water")
变量名称可以随时更改。在很多例子中你不可能只使用一个发射器,所以你要取一个有意义的名字。正如你所知道的,取一个容易辨别的名字总是对的。下面我们要一做一个泡沫脚本。这种类型的脚本要使用多个发射器,我们要区分好他们的名字:
water = scene.getEmitter("Water")
foam = scene.getEmitter("Foam")
请注意排放的名称必须与节点窗口中使用的名称相同。名称一定要写在引号之间,否则会产生语法错误。
另外可用发射器名称声明变量。water_emitter = "Water"
foam_emitter = "Foam"
water = scene.getEmitter(water_emitter)
foam = scene.getEmitter(foam_emitter)
在这个例子中,我们用变量替换掉结点窗口本来的名字。
若要使 Python知道,我们是想用是变量 getEmitter () 而不是字符串,那我们就不要写引号。(译者注:字符串与字符序列意思一样,通常译为字符串)
其它的,也是一样的过程:
collission_object = scene.getObject("Torus")
animated_daemon = scene.getDaemon("MainAttractor")
main_camera = scene.getCamera("Camer01")
rope_constraint = scene.getConstraint("Rope01")
fluid_mesh = scene.getMesh("Fluid")
wave_surface = scene.getRealwave("Wave")
关于发射器待会再讲。你肯定知道RealFlow是以粒子为基础的软件。每一种类型发射器产生粒子的数量,都是由 Resolution参数控制的。通过Python你可以直接访问每一个单独的粒子。但怎么做可以读出像 单个粒子的Veiocity 或Position属性值呢?
基本思路是,对所有存在的粒子循环遍历一下。
幸运的是 RealFlow 有多种方法来检测粒子的总数量,并提供直接访问。
常见的遍历方法是,找出第一个粒子,然后开始遍历到整个完成。只要是存在场景中的粒子都会被计算到:
fluid = scene.getEmitter("Circle01")
particle = fluid.getFirstParticle()
while (particle):
do something here
particle = particle.getNextParticle()
上面是什么意思?首先是确定发射器 Circle01. fluid.getFirstParticle()这句话意思是:在Circle01里的fluid里搜索第一个粒子。
现在脚本开始遍历所有存在的粒子。使用这种方法要获得所有场景中存在的每个粒子。 虽然执行循环时,你还能执行计算或检查和比较值大小。
获取下一个粒子,脚本用接下来的particle ID 变量来替换当前值。完成这一动作的关键字就是getNextParticle()
在某些情况下,建议跳过一些粒子。是为了加快模拟或测试速度。在前面我曾经讨论过取模 运算符 “%”。这恰好是你现在所需要的。在这个例子中我引进一种新的语句 if语句。你可以在 后面学到更多。
你必须要执行的操作如下:
skip = 5
counter = 0
fluid = scene.getEmitter("Circle01")
particle = fluid.getFirstParticle()
while (particle):
counter = counter + 1
if (counter % skip == 0):
do something here
particle = particle.getNextParticle()
在这个例子中,脚本统计出所有粒子的数量。随着每个粒子通过一次,Counter变量就会增加1.也可以写成缩写式。
counter +=1
作用是完全一样的,你可以看下面
Node Params > Statistics > Emitted Particles
取模符号作用是判断是否有余数。结果没有余数时(本例中结果是0),接下来的if语句才会被执行。这意味着脚本会4个4个的跳过粒子,因为只有粒子数为5时条件才成立(会忽略掉80%粒子,因为粒子ID为5的倍数时条件才成立)Skip值打的更高,将会忽略更多的粒子。如果 Skip值为1,那么条件一直是成立的,那粒子一个也不会跳过。
除了这个while方法,RealFlow也有 for...in和 for...in loop语句。第一个语句经常用于粒子,也用于有大量对像时。另外for...in也允许你在立即改变对像参数。
for...in loop循环语句经常被用来定义大量粒子。首先你要先收集数据,然后根据数据一个接一个的处理。特别是当它要收集泡沫产生的碰撞粒子,for...in 方法很有用的。
fluid = scene.getEmitter("Circle01")
collided_particles = fluid.getParticlesColliding()
for particle in collided_particles:
do something here
正如代码所表达的,你要把需要用的粒子存到变量 collided_particles.RealFlow识别出这些粒子用getParticlescolliding()关键字。粒子存入变量后,脚本可以从中读取出来,分别调用每个单独的(particle)粒子。当有大量粒子时,这种方法可能非常消耗内存,因为RealFlow要先把所有粒子拷贝一份,再设置它值。
这条语句也可以理解为:为每个在collided_particle 中的粒子执行计算设置。
for...in 执行原理类似于for...in loop.最主要的区别是,你可以定义循环终止值。比方说,你有一组六个球,但操作只影响到前三个物体(球)。
spheres = [S0,S1,S2,S3,S4,S5]
no_of_spheres = len(spheres)
stop = no_of_spheres / 2
start = 0
step = 1
for object in range(start, stop, step):
current_sphere = spheres[object]
do something here
喔喔,发生什么了?额,没什么特别的。我只是使用了另外一个数据类型。还记得列表(List)吗?如果不记得了话,那就再看一下第二节脚本基础知识吧。
不用担心,在这里都会再次解释到的。第一句,是一个变量名为spheres的列表(list)包含了六个项目。
变量在List里命名为S0-S5。因为列表都是从0开始的,这样命名更好,避免重复。spheres恰好在节点面板中也是这样的名字。
你想只需要影响前三个对像,你就要寻找一个终止值(stop).那就要知道列表(List)长度(len).这个值存到变量量no_of_spheres。列表一共有六个项目,而我们只需要三个物体。所以终止值就这样写了:
6/2=3
当然你只可以简单的写作stop = 3,但在这里我想说明如何处理名单和他们的元素(项目)。并在某些情况下可能很有用,在开始或停止直接用列表中的值。
若要读出current_sphere值,你要 使用包含在列表中的spheres循环数作为当前参数值。
current_sphere = spheres[object]
因为我们开始于start =0,在我们例子中就应该这样写表达式了(
其实我们看不到这个词,但这是它看起来像内部的方法):
current_sphere = spheres[0] ( S0 )
current_sphere = spheres[1] ( S1 )
current_sphere = spheres[2] ( S2 )
当你在变量里存入sphere了就能执行计算了。当 current_sphere = sphere[3],循环终止。我强烈要求你用这种方法做一个实验,这样才能理解更透彻。
step(步长)是一个增量。所以用步长给循环中的current_sphere变量增加1。步长不一定非要是1.还允许其他整数值,但使用不同的步长,你可能要更改stop(终止)值 !
List语句展示了所有对像名称。前面我说过名称要写在两个引号之间。在这个例子中,spheres作为列表(List)元素变量,在RealFlow节点窗口里名称来标志物体。在RealFlow中, 列表(List)中很少使用到引号。
spheres = [S0,S1,S2,S3,S4,S5]
这些符号会导致出错:
spheres = ["S0","S1","S2","S3","S4","S5"]
循环语句的使用是一项重要任务,几乎可用于任何事(Events)件或自定义脚本(Custom Script)(例如,辅助器(Daemon)或RealWave).甚至批处理脚本(Batch Script)也经常使用到循环语句,特别结合列表的使用。
4.3建立向量
向量是RealFlow中最重要的数据类型之一。这点已经在第二节有了详细介绍。在这,你将学习到怎样在脚本里使用向量,还有是到底如何提取出向量的分量。
RealFlow中的所有计算都是在三维空间中完成的。粒子,发射器或者模型的位置用x,y,z三个坐标来描述。从一个场景的坐标系原点开始,这些坐标值像一个地址,你可以根据它找到对像。可以从原点到对像坐标点画一个箭头。这个箭头就是向量的图形表现形式。但不仅是位置可写作向量。也可以用来表达力或速度。
图11,RealFlow中的速度向量。
Vector的数学表示是:
a= (x, y, z)
在RealFlow中也可以箭头的把向量看作一个变量的三个值。
初始化一个新向量Python表达式是:
my_first_vector = Vector.new(x, y, z)
在RealFlow中往往需要提取x,y,z值做进一步的计算。有时候你可能仅仅需要向量中的y或z分量。向量中的分量元素是标量:
position = (1.0, 3.3, 2.7)
现在我想计算单独一个粒子新的y,z位移。那要怎样去实现呢?这里有一种分离向量元素的方法。
事实上是RealFlow里自带的方法:
position_x = position.getX()
position_y = position.getY()
position_z = position.getZ()
在大部分的案例中,你要解构向量,执行计算,然后建立新的向量使用更新后的值。最终执行这种方法的过程总是相同的。就像循环方法,你只需要记住几个固定的步骤:
fluid = scene.getEmitter("Circle01")
particle = fluid.getFirstParticle()
while (particle):
# 1. Get global position data in Vector format
pos_g = particle.getPosition()
# 2. Get components from the position Vector
pos_x = pos_g.getX()
pos_y = pos_g.getY()
pos_z = pos_g.getZ()
# 3. Calculate the new coordinates individually
new_pos_y = pos_y + 0.01
new_pos_z = pos_z + 0.01
# 4. Build a new Vector
new_pos_g = Vector.new(pos_x, new_pos_y, new_pos_z)
# 5. Use the new Vector for position change
particle.setPosition(new_pos_g)
particle = particle.getNextParticle()
这是一个完整的脚本。你们看这里发生了什么,我想计算这小程序.(proggie,程序(program)另一种叫法)。第一部分用粒子发射器(Circle01)发射粒子。
第一步,获得向量值。在这个例子中的脚本,读出全局向量位移然后存在pos_g变量中。
第二步,脚本从pos_g向量中分离出x,y,和z三个分量。
脚本目标是只改变y和z的值,x值不受影响。新的位移值必须要单独计算,它们都要基于旧的pos_y和pos_z值。
新的位移new_pos_y,new_pos_z和没有改变过的pos_x做为新的全局位置向量值。Vector.new声明将上面那些合到一起。当然向量要再一次存入到变量(new_pos_g)以备下一次使用。
最后一个步骤new_pos_g矢量用setPosition指令设置粒子。在后面你会学到更多关于get和set函数。在这里只是用这些指令获得和设置位置。
最后一句是脚本获取下一个粒子。正如你看到的,脚本影响了一个又一个粒子。较高的发射器分辨率(resolution)会使计算时间变长。由于RealFlow内的Python 脚本 默认使用单核计算。你可能要模拟更长的时间。特别是时间紧迫时,要考虑在内。
图12,事件脚本ParticleNewPos.rfs模拟的结果。
这个脚本表现不是非常壮观,但足可以显示出脚本原理。
4.4 If&Else
当你写脚本时,经常需要确定某些条件或二选一一种方法。用If和else语句是可以区分的。此语法是相当简单的,在日常生活中经常会碰到的:我敢肯定你喜欢又新又快的电脑,但钱总是不够你买最新的终极机器。你要算算自己有多少可用的预算。这个例子非常适合理解if-else语句:
available_money = 2500
computer_price = 3200
if (available_money < computer_price):
can't buy computer
else:
go to computer store
在这个例子,available_money总数少于电脑价格。在案例中的条件是成立的,所以你不能买新电脑。但变量会随着时间改变,就会有产生新的结果:
available_money = 2500
computer_price = 3200
grannies_gift = 750
if (available_money + grannies_gift < computer_price):
can't buy computer
else:
go to computer store
啊哈,外婆拯救了你,因为2500+750 = 3250.
正如你看到的,比较不只限于一个变量,if语句也能执行计算。
另外等效的符号
total_money = availabe_money + grannies_gift
if (total_money < computer_price):
can't buy computer
else:
go to computer store
You could also reverse the comparison:
if (total_money >= computer_price):
go to computer store
else
can?t buy computer
你看到这个例子,if-else条件与其它大多数比较类似。
也能超过更多的值比较 。
ram = 200
my_money = 250
birthday_gift = 210
if (my_money >= ram or birthday_gift >= ram):
set max_particles to 50,000,000
else:
set_max_particles to 100,000
也可以用另一条语句。经常需要设置确切的极限:
ram = 200
gpu = 350
if (ram <= 250 and gpu <= 400):
buy both articles
else:
buy only graphics board
多个条件判断的另一个有用的方法是使用elif语句。elif表达式是else if的缩写,你可以使用elif语句做你大部分想到的任务:
if mandatory (强制) once
elif optional mutliple
else optiona l once
意思是,你想卖掉你的旧电脑,判断语句就写成这样:
offer = 475
retail_price = 500
min_price = 400
if (offer >= retail_price):
sell computer immediatly
elif (offer >= min_price and offer < retail_price)
contact customer for further negotation
else:
don't sell computer
在这个例子,将联系客户,因为 offer,处在retail_price和min_price之间。elif语句大都需要第二个条件去完成决定。
看下面这个例子:
offer = 520
retail_price = 500
min_price = 400
if (offer >= retail_price):
sell computer immediatly
elif (offer >= min_price):
contact customer for further negotiation
else:
don’t sell computer
这个例子结果是模糊不清的。第一个条件满足,因为520大于500,但第二个条件不满足,因为520也大于400.为了避免这种不一致性,需要设定第二个条件,像左边第一个例子那样。
在Python(其它所有语言都是)是允许建立多个if-else条件的。
offer = 540
retail_price = 500
zip = 90482
if (offer >= retail_price):
if (location == zip):
shipping_cost = 10
else:
shipping_cost = 25
else:
don?t sell computer
嵌套if-else 条件,可以设置相关值给变量。看看上面的例子,你会发现计算机可以被卖出了(报价(offer)大于实际价格(retail_price).第二个语句用来判断,买家是不是跟你在一个镇上。shipping_cost直接由买家地址决定。
(本第四节完)
评论