2012-06-07 17:10:10| 分类: RealFlow探索 | 标签: |举报 |字号大中小 订阅
现在我们有两个不同的值来影响创建的泡沫和水:Pressure 和Age.其次我们想改变这些值时,我们必须要打开Events Script 窗口,然后输入新的参数。有没有一个好方法完成这个任务呢?一个好的想法是通过用Null对像来直接控制Pressure 和Age。用种方法,就像你在使用滑块来调节脚本值。
你需要为这个函数准备什么呢?首先,我们要添加两个Null,命名为Control_Pressure 和Control_Age:
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
你能在这里看到完整的脚本:
#########################################################
# #
# 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.当然你可以添加另外的物体,但不要忘记不能让发射器对它们起作用。
图22:物体控制阈值直到现在,我们只关心发射器,没有其它元素加入场景。加入流体与物体的刚体交互会使模拟更加真实。意思是我们不得不基于碰撞创建粒子。幸运的是RealFlow提供了几个碰撞工具,可以减轻我们的工作。我们感兴趣的是这个函数:
getParticlesColliding( )
从名字就能知道这个表达式收集有碰撞的粒子。这个结果是一个List,包含了这些粒子。要读取这个list,适合使用fon...in 循环语句。(基础小节)。得到想要的粒子的基本指令块是这样写的:
emitter = scene.getEmitter("Water")
collided_particles = emitter.getParticlesColliding()
for single_particle in collided_particles:
执行检查和计算...
同样,我们正一步步开发泡沫脚本。首先让我们用一个很简单的场景检测结果。只添加两个发射器,水,泡沫和选择一个碰撞物体。
正如你看到的,列在这里的脚本与我们第一个脚本并没有太大的区别。它实际只是通过遍历发射器粒子,别的功能都没有改变。通过Python调用碰撞的粒子是一种简单有效的方法,与现有脚本可以快速适应。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)
最后一个方法是基于Pressure,但当然也是有碰撞的脚本,用粒子Velocity.也许两个参数的组合会产生更真实的效果。另一个问题是泡沫是比水轻的。这就会使泡沫浮在水面上。你能从图23看到这个结果。泡沫甚至都贴在容器壁上。这真的是创建的泡沫,但一会,泡沫就会从这消失。我们已经介绍过基于年龄的。这种方法也能在这儿使用,连同一些随机值。
图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()
接着,我们用Null为Pressure,Velocity,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发射器,再次像流体。不同的密度在一起会使泡沫消失更真实。
正如你从上面看到的图像序列,第一次碰撞的粒子是泡沫(白色的).一会过后,大部分循环转换成水(红色的)。
不同的密度值使泡沫漂到水面。他们也能再转换成水。蓝色表明原始粒子从发射器出来没有任何状态改变。
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())
最后一个功能是非常容易的:仅仅是发射器类型Liquid转Dumb的开关。这会节省和很多时间。
当然,有很多方法优化泡沫脚本,但其基本目的是达到了,你已经可以实现复杂和令人惊叹的的效果了。只是应用一些简单的方法。你可以下决心写一个脚本了,但这没什么不同。通过准备和一点耐心再加上一点时间优化,就能达到你的需求了。
这个值控制我们场景泡沫的数量。可能要花一点时间去调节它,但会增长经验,当你设置一个特殊的场景时就会变的很快。调节通过Null物体,不是必须要的。这个方法只是为了介绍给你和方便制作用的。
阈值通常都必须单独设置在每一个新的场景中。这也是你来产生新的值和不同的参数结果。
Random是非常重要的,因为有它能看起更自然。调节这个参数也需要一点测试,经验。
泡沫和spray的创建得到了广泛的讨论,在整个论坛和脚本资源站。
感谢Beatriz Lorenzo, Robb Flynn, Richard Sutherland,和其它所有为这个脚本做过贡献的人。
也感谢一下本人的翻译吧,嘿嘿。
评论