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

豆芽兵的生存探索

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

 
 
 
 
 

日志

 
 

第七节:泡沫案例(2)  

2012-06-07 17:10:10|  分类: RealFlow探索 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
 
7.4通过物体控制值

现在我们有两个不同的值来影响创建的泡沫和水:Pressure Age.其次我们想改变这些值时,我们必须要打开Events Script 窗口,然后输入新的参数。有没有一个好方法完成这个任务呢?一个好的想法是通过用Null对像来直接控制Pressure Age。用种方法,就像你在使用滑块来调节脚本值。

 你需要为这个函数准备什么呢?首先,我们要添加两个Null,命名为Control_Pressure Control_Age:

 

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索> Null

Edit  > Add > Objects > Null

 要直接通过这个物体控制值,我们需要得到Null的高度或叫y位移。这位移要被存储在一个变量中,用来定义阈值。脚本不会管你,是否是移动物体或在节点参数窗口输入值。

cp  = scene.getObject("Control_Pressure")

ca  = scene.getObject("Control_Age")

 

pos_g_cp = cp.getParameter("Position")

pos_y_cp = pos_g_cp.getY()

pos_g_ca = ca.getParameter("Position")

pos_y_ca = pos_g_ca.getY()

 

threshold_pres = pos_y_cp * 2000

[ ... ]

 

if (pos_y_ca < 0):

 threshold_age = -1 * (pos_y_ca / 2.0) + random_age

else:

 threshold_age = (pos_y_ca / 2.0) + random_age

 这是一个很有效的方法,也容易实现。

让我们快速看一下Python代码:

 a.获取Null对像。

 b.设置变量存储y位移(高度)。

 c.用当前位移成为threshold_pres的值。Pressure可以为负数,所以负位移是可以接受的

 d.年龄不能是负数,我们要再乘上一个-1,使之变为正数,如果成立的话。

 e.执行一个简单的计算,来获取一个较小的值,例如pos_y_ca = 1.0 threshold_age 值将变为 0.5+random_age

 你能在这里看到完整的脚本:

 

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索The_Foam_Project > Scripts > Foam_006.rfs

#########################################################
# #
# Script name : Foam_006.rfs #
# Copyright : RF_magazine, Thomas Schlick 2007 #
#Translater : Dominic,2012/6/7 #
#########################################################

def onSimulationStep():

import random

cp = scene.getObject("Control_Pressure")
ca = scene.getObject("Control_Age")

pos_g_cp = cp.getParameter("Position")
pos_y_cp = pos_g_cp.getY()
pos_g_ca = ca.getParameter("Position")
pos_y_ca = pos_g_ca.getY()

threshold_pres = pos_y_cp * 2000
water = scene.getEmitter("Water")
foam = scene.getEmitter("Foam")
rewater = scene.getEmitter("ReWater")

# Go through water particles

particle_water = water.getFirstParticle()
while (particle_water):

pres_water = particle_water.getPressure()
vel_water = particle_water.getVelocity()
pos_water = particle_water.getPosition()
id_water = particle_water.getId()

if (pres_water > threshold_pres):

foam.addParticle(pos_water,vel_water)
water.removeParticle(id_water)

particle_water = particle_water.getNextParticle()

# Go through foam particles, check age and pressure

particle_foam = foam.getFirstParticle()

while (particle_foam):

current_age = particle_foam.getAge()
random_age = random.uniform(-0.1,0.1)

if (pos_y_ca < 0):
threshold_age = -1 * (pos_y_ca / 2.0) + random_age
else:
threshold_age = (pos_y_ca / 2.0) + random_age

if (current_age >= threshold_age):

pres_foam = particle_foam.getPressure()
vel_foam = particle_foam.getVelocity()
pos_foam = particle_foam.getPosition()
id_foam = particle_foam.getId()

if (pres_foam < threshold_pres):

rewater.addParticle(pos_foam,vel_foam)
foam.removeParticle(id_foam)

particle_foam = particle_foam.getNextParticle()

为了形像化位移滑块,我用了一个小盒子代替Null.当然你可以添加另外的物体,但不要忘记不能让发射器对它们起作用。

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
  22:物体控制阈值

7.5基于碰撞创建的泡沫

 直到现在,我们只关心发射器,没有其它元素加入场景。加入流体与物体的刚体交互会使模拟更加真实。意思是我们不得不基于碰撞创建粒子。幸运的是RealFlow提供了几个碰撞工具,可以减轻我们的工作。我们感兴趣的是这个函数:

 getParticlesColliding( )

 从名字就能知道这个表达式收集有碰撞的粒子。这个结果是一个List,包含了这些粒子。要读取这个list,适合使用fon...in 循环语句。(基础小节)。得到想要的粒子的基本指令块是这样写的:

emitter = scene.getEmitter("Water")

collided_particles = emitter.getParticlesColliding()

 

for single_particle in collided_particles:

 执行检查和计算...

 同样,我们正一步步开发泡沫脚本。首先让我们用一个很简单的场景检测结果。只添加两个发射器,水,泡沫和选择一个碰撞物体。

 

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
 
第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索EventScript: CollisionFoam_001.rfs

def onSimulationStep():

threshold_pres = 5000
water = scene.getEmitter("Water")
foam = scene.getEmitter("Foam")

# Go through water particles
collided_particles = water.getParticlesColliding()
for single_particle in collided_particles:
pres_water = single_particle.getPressure()
vel_water = single_particle.getVelocity()
pos_water = single_particle.getPosition()
id_water = single_particle.getId()
if (pres_water > threshold_pres):

foam.addParticle(pos_water,vel_water)
water.removeParticle(id_water)

正如你看到的,列在这里的脚本与我们第一个脚本并没有太大的区别。它实际只是通过遍历发射器粒子,别的功能都没有改变。通过Python调用碰撞的粒子是一种简单有效的方法,与现有脚本可以快速适应。
第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
 

 

最后一个方法是基于Pressure,但当然也是有碰撞的脚本,用粒子Velocity.也许两个参数的组合会产生更真实的效果。另一个问题是泡沫是比水轻的。这就会使泡沫浮在水面上。你能从图23看到这个结果。泡沫甚至都贴在容器壁上。这真的是创建的泡沫,但一会,泡沫就会从这消失。我们已经介绍过基于年龄的。这种方法也能在这儿使用,连同一些随机值。

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
 

23:泡沫粒子贴在容器壁上

 我们下一个脚本需要什么呢?

a.速度(Velocity)检查(Magnitude)

b.高度检查

c.年龄(Age)检查

d.压力(Pressure)检查

水面上的粒子应比水面下的粒子消失慢。我们确信需要if语句,但有更多的效果我们要考虑,这样才会有更好的结果。当然也有一个效率的问题,有些方法不适合紧张的生产期.

直到现在,所有的发射器需要同一个参数。在这个脚本,我们开始时不同的Density值,给水,泡沫和rewater(重新变成水)。所有这些操作将有助于达到更好的泡沫和水混合,并维持泡沫粒子远离碗的底部。

 脚本可以在这看到:

 

The_Foam_Project > Scripts > CollisionFoam_002.rfs

 

#########################################################
# #
# Script name : CollisionFoam_002.rfs #
# Copyright : RF_magazine, Thomas Schlick 2007 #
#Translater :           Dominic,2012/6/7   #
#########################################################

def onSimulationStep():

import random

cp = scene.getObject("Control_Pressure")
ca = scene.getObject("Control_Age")
ch = scene.getObject("Control_Height")
cv = scene.getObject("Control_Velocity")

pos_g_cp = cp.getParameter("Position")
pos_y_cp = pos_g_cp.getY()
pos_g_ca = ca.getParameter("Position")
pos_y_ca = pos_g_ca.getY()
pos_g_ch = ch.getParameter("Position")
pos_y_ch = pos_g_ch.getY()
pos_g_cv = cv.getParameter("Position")
pos_y_cv = pos_g_cv.getY()

threshold_pres = pos_y_cp * 2000
threshold_vel = pos_y_cv * 2.0
threshold_height = pos_y_ch
water = scene.getEmitter("Water")
foam = scene.getEmitter("Foam")
rewater = scene.getEmitter("ReWater")

# Go through water particles

collided_particles = water.getParticlesColliding()
for single_particle in collided_particles:

pres_water = single_particle.getPressure()
vel_water = single_particle.getVelocity()
vel_mod = vel_water.module()
pos_water = single_particle.getPosition()
id_water = single_particle.getId()
random_vel = random.uniform(-0.15,0.15)

if ((pres_water > threshold_pres) or (vel_mod > threshold_vel + random_vel)):
foam.addParticle(pos_water,vel_water)
water.removeParticle(id_water)

# Go through foam particles

particle_foam = foam.getFirstParticle()

while (particle_foam):

random_value = random.uniform(-0.1,0.1)
current_age = particle_foam.getAge()
vel_foam = particle_foam.getVelocity()
pos_foam_g = particle_foam.getPosition()
pos_foam_y = pos_foam_g.getY()

# Avoid negative age values

if (pos_y_ca < 0):
threshold_age = -1 * pos_y_ca / 2.0
else:
threshold_age = pos_y_ca / 2.0

# Define height dependent life span of single particle

if(pos_foam_y >= threshold_height):
threshold_age = (threshold_age + 0.5) + random_value
else:
threshold_age = (threshold_age + random_value) / 2.0

# Transform particles back to water

if (current_age >= threshold_age):
rewater.addParticle(pos_foam_g,vel_foam)
foam.removeParticle(id_foam)

particle_foam = particle_foam.getNextParticle()

接着,我们用NullPressureVelocity,Age,Height调节值。总而言之,我们现在有一个完全自定义的和可控的泡沫的脚本。另一个优点是执行计算会非常快。

 在这里你可以找到控制泡沫粒子数量的主例程:

 # Define height dependent life span of a particle

 

 if (pos_foam_y >= threshold_height):

   threshold_age = (threshold_age + 0.85) + rand_value

 else:

   threshold_age = (threshold_age + rand_value) / 2.0

 

# Transform particles back to water

 

if (current_age >= threshold_age):

 id_foam = particle_foam.getId()

 rewater.addParticle(pos_foam_g,vel_foam) 

 foam.removeParticle(id_foam)

第一个if语句,我们用当前高度(pos_foam_y)定义生命(threshold_age)。粒子在一个特定的高度(threshold_height)比较快的转变成水,另的保持比较长时间是泡沫。接近Age值结果,粒子转换为Rewater发射器,再次像流体。不同的密度在一起会使泡沫消失更真实。

 


第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索
  24.CollissionFoam_002.rfs生成的图像序列

 正如你从上面看到的图像序列,第一次碰撞的粒子是泡沫(白色的).一会过后,大部分循环转换成水(红色的)。

不同的密度值使泡沫漂到水面。他们也能再转换成水。蓝色表明原始粒子从发射器出来没有任何状态改变。

 

7.6优化脚本

最后一步是优化代码和函数使计算更快。正如我提过的,这是一本初学者值指南,我乐意说出这些方法。脚本里也有一些语句是可以缩减的。我不想深入到Python程序,但可能有一些改进。如果你有兴趣改进这些,只需要打开CollisionFoam_002.rfs CollisionFoam_003.rfs 比较一下源代码。你会看到,一些语句之前定义的变量,已经消失了。

 另一个改进是,特别是模拟测试跳过了一些粒子。是不是听着有些耳熟啊?那是肯定啊,因为我在之前讲过这个问题了啊(基础小节)。这个符号是:写成百分号%,是关键。这是一种有效控制粒子量的方法。我们开始:

首先,我们需要Counter计数,要是Integer,定义多少粒子需要跳过。这个变量要定义在最前面。

def onSimulationStep():

 

 import random

  counter    = 0

 skip_value = 5

 [ ... ]

 

连同第一个循环产生的泡沫,我们引入了取模的操作。取模是,当整除时是否有余数。(Float数也是可以的,但会产生奇怪的结果)如果余数正好是0,条件就成立,粒子可以转换成泡沫。对于其它counter值,条件不满足,转换成成泡沫的动作就不会执行。

# Go through water particles

collided_particles = water.getParticlesColliding()

 

for single_particle in collided_particles:

  counter  += 1

 

 if (counter % skip_value == 0):

  pres_water = single_particle.getPressure()

  vel_water  = single_particle.getVelocity()

  pos_water  = single_particle.getPosition()

  random_vel = random.uniform(-0.15,0.15)

 

 if ((pres_water > threshold_pres) or

  (vel_water.module() > threshold_vel + random_vel)):

 

   foam.addParticle(pos_water,vel_water)

   water.removeParticle(single_particle.getId())

 

最后一个功能是非常容易的:仅仅是发射器类型LiquidDumb的开关。这会节省和很多时间。

 

当然,有很多方法优化泡沫脚本,但其基本目的是达到了,你已经可以实现复杂和令人惊叹的的效果了。只是应用一些简单的方法。你可以下决心写一个脚本了,但这没什么不同。通过准备和一点耐心再加上一点时间优化,就能达到你的需求了。

7.6.1 阈值

 

这个值控制我们场景泡沫的数量。可能要花一点时间去调节它,但会增长经验,当你设置一个特殊的场景时就会变的很快。调节通过Null物体,不是必须要的。这个方法只是为了介绍给你和方便制作用的。

 

阈值通常都必须单独设置在每一个新的场景中。这也是你来产生新的值和不同的参数结果。

 

Random是非常重要的,因为有它能看起更自然。调节这个参数也需要一点测试,经验。

7.7 反响

 

泡沫和spray的创建得到了广泛的讨论,在整个论坛和脚本资源站。

感谢Beatriz Lorenzo, Robb Flynn, Richard Sutherland,和其它所有为这个脚本做过贡献的人。

也感谢一下本人的翻译吧,嘿嘿。第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索

第七节:泡沫案例(2) - 豆芽兵 - 豆芽兵的生存探索

  评论这张
 
阅读(3148)| 评论(3)

历史上的今天

评论

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

页脚

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