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

豆芽兵的生存探索

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

 
 
 
 
 

日志

 
 

第四节_你的第一步  

2012-05-29 08:36:57|  分类: RealFlow探索 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

第四节_你的第一步 - 豆芽兵 - 豆芽兵的生存探索
 

4.1调用 发射器(Emitters) 和 对像(Objects

现在你的毅力和耐心终于得到回报,因为你将使用RealFlowPython做出第一步了!

 首先创建一个 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")

4.2存取粒子Accessing Particles

关于发射器待会再讲。你肯定知道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语句才会被执行。这意味着脚本会44个的跳过粒子,因为只有粒子数为5时条件才成立(会忽略掉80%粒子,因为粒子ID5的倍数时条件才成立)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三个坐标来描述。从一个场景的坐标系原点开始,这些坐标值像一个地址,你可以根据它找到对像。可以从原点到对像坐标点画一个箭头。这个箭头就是向量的图形表现形式。但不仅是位置可写作向量。也可以用来表达力或速度。

第四节_你的第一步 - 豆芽兵 - 豆芽兵的生存探索
 

11RealFlow中的速度向量。

 Vector的数学表示是:

 a= (x, y, z)

 RealFlow中也可以箭头的把向量看作一个变量的三个值。

 初始化一个新向量Python表达式是:

 my_first_vector = Vector.new(x, y, z)

 RealFlow中往往需要提取x,y,z值做进一步的计算。有时候你可能仅仅需要向量中的yz分量。向量中的分量元素是标量:

 position = (1.0, 3.3, 2.7)

 现在我想计算单独一个粒子新的y,z位移。那要怎样去实现呢?这里有一种分离向量元素的方法。

 事实上是RealFlow里自带的方法:

position_x = position.getX()

position_y = position.getY()

position_z = position.getZ()

在大部分的案例中,你要解构向量,执行计算,然后建立新的向量使用更新后的值。最终执行这种方法的过程总是相同的。就像循环方法,你只需要记住几个固定的步骤:

第四节_你的第一步 - 豆芽兵 - 豆芽兵的生存探索Events Script: ParticleNewPos.rfs

 


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三个分量。

脚本目标是只改变yz的值,x值不受影响。新的位移值必须要单独计算,它们都要基于旧的pos_ypos_z值。

 新的位移new_pos_y,new_pos_z和没有改变过的pos_x做为新的全局位置向量值。Vector.new声明将上面那些合到一起。当然向量要再一次存入到变量(new_pos_g)以备下一次使用。

 最后一个步骤new_pos_g矢量用setPosition指令设置粒子。在后面你会学到更多关于getset函数。在这里只是用这些指令获得和设置位置。

 

最后一句是脚本获取下一个粒子。正如你看到的,脚本影响了一个又一个粒子。较高的发射器分辨率(resolution)会使计算时间变长。由于RealFlow内的Python 脚本 默认使用单核计算。你可能要模拟更长的时间。特别是时间紧迫时,要考虑在内。

第四节_你的第一步 - 豆芽兵 - 豆芽兵的生存探索
 12,事件脚本ParticleNewPos.rfs模拟的结果

 这个脚本表现不是非常壮观,但足可以显示出脚本原理。

 4.4 If&Else

 当你写脚本时,经常需要确定某些条件或二选一一种方法。用Ifelse语句是可以区分的。此语法是相当简单的,在日常生活中经常会碰到的:我敢肯定你喜欢又新又快的电脑,但钱总是不够你买最新的终极机器。你要算算自己有多少可用的预算。这个例子非常适合理解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_pricemin_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直接由买家地址决定。


(本第四节完)

  评论这张
 
阅读(2949)| 评论(7)

历史上的今天

评论

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

页脚

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