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

豆芽兵的生存探索

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

 
 
 

日志

 
 

绘制动态利萨如图形(Lissajous Figures)  

2013-01-29 16:23:18|  分类: RealFlow探索 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
绘制动态利萨茹图形(Lissajous Figures) - 豆芽兵 - 豆芽兵的生存探索
 
绘制动态利萨茹图形(Lissajous Figures) - 豆芽兵 - 豆芽兵的生存探索
 

动态利萨如图形(Lissajous Figures

利萨如图形(Lissajous figures,也可以叫利萨如曲线)有一个相关物理的背景,就是用来理解交流电(alternating currents)。这个曲线是是两个沿着互相垂直方向的正弦振动的合成的轨迹。可以使用“点”在2D/3D空间绘制出利萨如图形。“点”的位置由时间控制,就是说需要进行解算,可以用批处理脚本(batch script)模拟这一过程。本文方法可以加速此图形生成,直到生成最终你需要的结果才会输出,而不是每一帧输出一个BIN文件。如果每帧生成可能会产生成百上千个文件。

维基百科定义:http://de.wikipedia.org/wiki/Lissajous-Figur  (有中文的简要词条,注意切换)

本教程提供的的脚本是完美的解决方案:基于时间生成,使用不同的设置,会产生有趣的效果。Lissajous Figures可探讨范围几乎是无限的,因为时间没有边界和极限的。Lissajous figure可以在示波器上看到,振荡曲线,钟摆曲线,甚至绘制圆柱体。

       如果提前想提前感受一下绘制利萨如图形的趣味,可以到这个网站:http://www.phy.hk/wiki/chinesehtm/Lissajous.htm

本教程,提供了一个如何以批处理方法创造很炫的效果。请注意这是为RealFlow5写的脚本,对于老版本只要进行一下小小改动就可以了。

绘制动态利萨茹图形(Lissajous Figures) - 豆芽兵 - 豆芽兵的生存探索

上图是动态的绘制过程

最重要的任务是找到创建Lissajous Figures的合适函数。你可以在网上随便搜索一下,会发现很多网页有这个公式。适当的表达式是这样的:

绘制动态利萨茹图形(Lissajous Figures) - 豆芽兵 - 豆芽兵的生存探索

上图为维基百科的参数方程截图

t -> Ax * sin( ω1 * t + ρ1 )

t -> Ay * sin( ω2 * t + ρ2 )

但写成上面这样,容易转换成脚本。可以从公式看出绘制出的图形与时间t紧密相关:每个时间步长 t,脚本计算公式 A * sin( ω * t + ρ ),这在每个轴都会计算。正如你看到的,这个公式只考虑xy轴方向。而我们目的是绘制三维图。解决方法是很简单的,因为只要把这个公式 加一项,就能求得 Z轴:

t -> Az * sin( ω3 * t + ρ3 )

决定最后图形尺寸大小的值是 AA越大结构就变得越大

下一步是找出 ω ρ 的意思。他们读作“Omegao`miga欧米伽)”和“Phi(佛爱φ,应该写成这样)”他们决定图的样子。ω 是频率,  ρ是相位(phase)。因为在这里要处理震荡(oscillation),这两个参数是必须的的。频率是指在一定时间内(=向上/向下运动)发生的数量。越高的频率,就会有更多的波峰和波谷。(这些就是简单的正弦曲线传达的概念http://qqww2334.blog.163.com/blog/static/12036582201252851854952/ 这篇文章有一段,详细介绍了频率相位这些概念)

绘制动态利萨茹图形(Lissajous Figures) - 豆芽兵 - 豆芽兵的生存探索
 

1.在二维空间不同的 Lissajous figure示例。

相位,ρ,不太容易解释。根据定义,它是振荡状态随时间变化与起始值的距离。简明的说来,就是Lissajous figure 整体外观的偏移。

 依据时间的批处理脚本(Batch Scripts

使用模拟事件(simulation),我们不会碰到任何关于时间(time)的问题,因为每个模拟步长或帧,可看作时间的流逝。在批处理脚本中不会这么自动,因为这个脚本类型不是基于任何模拟或事件。因此,时间可被考虑成一个无限的序列,在每一步添加一定值。在计算机模拟中,甚至可以用负的时间值。但关键是,使用负时间真的能产生一些新的结果或图形吗?

实际上可以创建一个循环,让计数器在每一步加1。粒子数也需要循环来定义,你最后就可以控制图片的“分辨率”了(一张图形,有运行时间越长,粒子数越就可能会越清晰。这是一种比拟)。

正如您所了解到,从ρ定义你需要一些初始值。这是必要的,因为新的时间步是基于之前那个的。这个思路来自于分形(fractals)(详细了解分形请参考文章:分形艺术http://qqww2334.blog.163.com/blog/static/12036582201301542931932/

)。你需要让时间初始值要大于或等于0,因为没有“负”的时间。

time = 0

step = 0.025

for i in range(0,2000,1):

  time = time + step

  #用这三个公式计算单个值

 #创建位移矢量

#添加粒子发射器

 

核心部分是:

for i in range(0,2000,1)

这个行命令意思是:“变量i要从1运行到2000,步长是1。”结果是一个整数序列:1234…2000。在这个循环每一个“i”常量值是0.025=step(步长 )),会添加到当前时间。最初时间是0,现在增加每一个步长 在这个循环中:0.025, 0.050, 0.075, ..., 50.

这基本上是Axyz,ω123,ρ123起始值。

在循环之前,要先引入这些变量。现在我们准备好了所有需要的批处理脚本。最初的参数代表最终图片外形。当成一种游戏来玩吧,你会惊讶的发现即使只是轻微的改变,就创建出完全不同的图形。

import math

scene.reset()

Ax = 2.0

Ay = 2.0

Az = 2.0

omega1 = 1.67

omega2 = 1.22

omega3 = 0.89

phi1 = 1.54

phi2 = 2.98

phi3 = 1.68

time = 0

step = 0.025

stop = 2000

nullVel = Vector.new(0, 0, 0)

emitter = scene.get_PB_Emitter("Container01")

emitter.setParameter("Type","Dumb")

for i in range(0,stop,1):

time = time + step

x = Ax * math.sin(omega1 * time + phi1)

y = Ay * math.sin(omega2 * time + phi2)

z = Az * math.sin(omega3 * time + phi3)

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

emitter.addParticle(particlePos, nullVel)

使用这个脚本步骤:

1.       建立一个Container粒子发射器(默认名称Container01

2.       Layout 菜单下,打开Batch Script窗口。

3.       粘贴入上面提供的脚本

4.       在这个窗口下的Script下点击Run

5.       会看RealFlow开始自动绘制曲线。成功!!!

注意这时你只能看到粒子,它是没有变成Bin文件导出的,你拨一下时间栏它就可能消失。可以点击一下Simulation,就会保存下来了

 

你可以导出这个粒子渲染出去,加一些后期修饰什么的。

本文章开始说,为了避免产生N多个粒子文件,所以在Batch Script下写这个脚本。

像如果想要动态序列粒子怎么办??自己小小思考下。再往下看吧。到时你可以比较一下,他的方法好还是你的方法好。

在开始使用这个脚本前插播一个关于Container小介绍

Tips :Container(容器)

这也是一种发射器类型,类似于binaryNBinary发射器类型。实际上它不是真的发射粒子,因为它本身只作为一种接受其实粒子源的容器,只接受,不产生。通常这种类型与Filter Daemon(这是一种过虑辅助器)结合使用。你可以指定特写条件下的粒子转移到这个Container发射器中。这就很容易制作泡沫(foam)或水花(spry),会单独输出来。尽管这个发射器不发射粒子,它具有所有其它发射器具有的功能。它的粒子可以与刚体(rigid body)或RealWave进行交互,你也可以控制所有相关的物理参数。

这个Container粒子容器自身的面板,不提供任何设置,因为它只能从其实粒子发射器接受粒子

当然,循环终止值可以小于或大于2000。另一个重要的事是要使用dumb 粒子。为避免麻烦,脚本执行这必须做的事。另外粒子velocity0.如果你想保存这图形,只要保存场景或创建初始状态。用高一点Resolution(译者注:经本人试验,这个值与最终粒子数无关,最终粒子数等于stop),用稠密的粒子拖尾,图形也可以mesh.最好用不同 ω ρ值进行试验创建Lissajous figures,这两值对最终影响很大。

绘制动态利萨茹图形(Lissajous Figures) - 豆芽兵 - 豆芽兵的生存探索
 

问题是,要在哪里使用到这个脚本呢?实际上它是个噱头,实际工作中流体或粒子模拟这些图片不会发挥非常重要的作用。这个示例告诉你怎样转变公式用到Python代码中,你还得到一个有趣的结果。并学习到关于物理和数学上的一些东西,物理和数学对我们CG工作者是非常重要的。

这个特殊的批处理脚本方法更多的优点是:你能轻松在三维软件中可视化物理过程和结构。你可以专注于研究脚本并不用太意于投射(projection),透视(perspective),材质(shading),粒子系统(particle system)等。

(这是一种很重要的认识,可以把工作试验当成一种很有趣的事来做,并不需要能得到什么了不起的结果,享受这种把物理或数学变成图形的过程吧。况且最终的它真的对工作没有帮助吗?这个答案由来你回答了。)

动态化利萨如图形( Lissajous Figures

上面介绍的是批处理脚本的一部分,粒子位置可以绘制出来了。你肯定注意到生成图形时的动画也是很有趣的。这代码与之前脚本几乎完全一样的,但需要一个函数创建每一帧的变化。可以使用参数是“omega”和“phi.

最好办法是组合一个基于帧的值。函数输出当前帧是:

frame = scene.getCurrentFrame()

再让“omega”和“phi”参数乘以当前帧。但仅这样处理图形会没有平滑过渡,因为越来越多帧,“omega”,“phi”的值将会越来越高。

为了获得更好的效果,首次测试值除以200

omega1-3 = initialValue * frame / 200

phi1-3   = initialValue * frame / 200

当然你也可以换成其它值,例如 100300。再给“omega”和“phi”设置不同的值。用更小的值最终过渡会更光滑。

这代码放在“StepsPost”事件部分。目前场景模拟不会有任何合理图形,因为每一帧新的粒子会添加到之前的粒子上,所有看起来很糟糕。现在需要什么方法更新这个场景给每一个新帧。RealFlow提供了“reset()”函数,但不能用在这儿,因为这只会跳回初始帧。

方法是放在"FramesPre"里写上第二个脚本。现在在"StepsPost"里的核心脚本生成新粒子之前

的粒子会被删除。这个程序只有几行,但非常有效:

emitter = scene.getEmitter("Container01")

particleList = emitter.getParticles()

for particle in particleList:

emitter.removeParticle(particle.getId())

 

这已经是整个脚本来刷新屏幕。利用RealFlow的拍屏功能你可以轻松看到模拟的动画效果。

 

这一部分是放在StepsPre下的脚本(Part1):

emitter = scene.getEmitter("Container01")

particleList = emitter.getParticles()

for particle in particleList:

emitter.removeParticle(particle.getId())

第二部分是放在StepsPost下面

import math

frame = scene.currentFrame

#scene.reset()

Ax = 2.0

Ay = 2.0

Az = 2.0

omega1 = 1.67 *frame/200

omega2 = 1.22*frame/200

omega3 = 0.89*frame/200

phi1 = 1.54*frame/200

phi2 = 2.98*frame/200

phi3 = 1.68*frame/200

time = 0

step = 0.025

stop = 2000

nullVel = Vector.new(0, 0, 0)

emitter = scene.get_PB_Emitter("Container01")

emitter.setParameter("Type","Dumb")

for i in range(0,stop,1):

time = time + step

x = Ax * math.sin(omega1 * time + phi1)

y = Ay * math.sin(omega2 * time + phi2)

z = Az * math.sin(omega3 * time + phi3)

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

emitter.addParticle(particlePos, nullVel)

看到我在上面把scene.reset屏蔽了,如果让它起作用的话,那么只会一直重置场景,无法正常模拟。

还看到我加了frame = scene.currentFrame因为RealFlowframe不是直接可调用的函数,需要使用currentFrame来获取当前帧的值。关于这些内置函数,都可以在RealFlow帮助文档看到。(小提示:RealFlow看帮助文档最好新开一个场景,因为不小心搜索一下,就会让RF崩溃)

  评论这张
 
阅读(2812)| 评论(0)
推荐

历史上的今天

评论

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

页脚

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