2012-08-20 18:24:22| 分类: RealFlow探索 | 标签: |举报 |字号大中小 订阅
写在前面:
这是一个《终结者2》金属人融化的效果脚本。不适合当博文。现在只是草稿,暂时给提问我的人看一下,后面会修改成,适合大众阅读的。
感谢提问者。还有“小Paul”同学的讨论
阅读需知:
1. 解答问题的效果更多在于你本人思考的时间
2. 参考网址可能比我写的更有价值
3. 本人不是高手,可能有致命错误。请用孩子的单纯去执行,用松鼠的怀疑来思考。找到错误赶紧告诉我。
第一节:知识预备:
1.len:
buitin(内置)函数.
作用 : 计算字符串中的字符数,还可以计算list的成员数,tuple.简单说就是计算“列表”的长度。
用法:
aa = [1,2,3,4,5]
print 'length of aa is ',len(aa) #result:length of aa is 5
#可以使用这个值遍历列表的变量,这就意味着,即使列表的长度改变了,我们
也不用对程序的循环次数做出修改
参考:
a.http://hi.baidu.com/liuhelishuang/item/db4e2c0fc9f1d5cd74cd3c88
b.http://talkincode.org/news/post/view/cccf52dfceea476eac940bd10129581
c.http://www.cnblogs.com/zhengyuxin/articles/1932659.html
2. Sorted
此函数也是Python的内建函数。
作用:给列表排序,生成新的列表
用法:
sorted(...)
sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted
list
iterable:待排序的可迭代类型的容器;
cmp:用于比较的函数,比较什么由key决定,有默认值,迭代集合中的一项;
key:用列表元素的某个已命名的属性或函数(只有一个参数并且返回一个用于
排序的值)作为关键字,有默认值,迭代集合中的一项;
reverse:排序规则. reverse = True 或者 reverse = False,有默认值。
返回值:是一个经过排序的可迭代类型,与iterable一样。
参考:
1.http://gaopenghigh.iteye.com/blog/1483864
2.http://hi.baidu.com/mecfan/blog/item/87a1eac5044b5ca58226acb0.html
3.http://www.cnblogs.com/linyawen/archive/2012/03/15/2398292.html
3. lambda
python lambda是在python中使用lambda来创建匿名函数。它是一个表达式,不是语句,因此可以嵌套。
用法:
g = lambda x : x*2
print g(3)
结果是6
效果与def一样。
def g(x)
return x*2
f(3)
但这样就不简洁了。
a.http://www.cnblogs.com/wanpython/archive/2010/11/01/1865919.html
b.http://hi.baidu.com/pythonhome/blog/item/cdd68eb0a4de30b2d8335afe.html
c.http://www.cnblogs.com/linyawen/archive/2012/03/15/2398292.html
第一节看完请不要着急向下看,自己思考一下,在有了这些关键知识的储备后,是不是能理顺,甚至是想通你想问的问题了。
如果是在思考了三十分钟后,没能解决再往下看。
第二节:正面回答一下你的两个问题:
Q1:操作至“配对数据重新排列”后又进行了怎样的逻辑计算?
A1:只是把获取到的邻居总数,按照一定的顺序重新排列了一下。(不能确定是从大到小还是从小到大,根据案例,应该是从小到大)。
Q2:红色的这几句话是什么意思,是我这种初学者应该在这个阶段掌握的吗?
A2:这个问题不精确。我无法直接回答,得批评一下。具体这几句话意思,请看后面内容。
知识是平等的,没有先后,碰到的就应该掌握。跟你初学晚学,没有一毛钱关系。
PS:以后提问,请一定要明确你的问题,如果不是我对这个感兴趣,如果不是你第一次问我,我是不会像猜谜一样,写出后面那么多内容。
第三节:详细的回答:
你用两个“信息”表示同一对像的属性的说法不准确。“连体”的说法,是可以的。
在一个dictionary中,key是不可重复的,value可以重复。也就是说,只能通过key
来找value不能反过来。如果像你说的,是一个对像的两个属性,那应该是可以
互相查找,所以你这样说不准确。“并且dictionary 中还允许一个key对应多个值,key- value1,value2,…
我建议你跟list一样,还把这个key当成一个唯一的索引号,只是没有排序而已。
“连体”,也就是一个“key-value对”,这是准确的。但记住,无论是key后面有多少value,它都是一个元素。
我们通过获取其中一个数的排列(例如本例中的粒子ID)来得到另一个数的排列(本例中粒子的邻居数),再将另一个数(粒 子的邻居数)按照由少到多的顺序重新排列,这个粒子ID也会跟着重新排列,最后我们将这组重新排列过的数据按照新的顺序逐一拾取并一一执行 unfreeze的命令。不知理解的对不对?
这段理解就不能说不准确,而是严重错误了。
唯一跟id相关的,就是一开始,遍历一次particle,然后得出每个粒子的Neighbors总数。再把这个总数排次序。放到一个新的列表。Id只跟遍历有关,后面无论生成新列表,还是重新排序,都跟它没有关点关系。最后unfreeze时,执行的对像是 getNeighbors(0.2)得出的列表。(没错,getNeighbors()输出的是一个列表)这个列表并没有进行任何排序操作。
为了形像一点,我制作了一个图。
请注意这是一个我头脑中的图,我并不会让你眼睛直接看到。请闭上眼,跟我开始想像。
1. 青青草原上有一群白白羊,假设有100头。
2. 每只小羊都是有唯一身份证的,你想抢走它,它能跟你拼命。
3. 有个倒霉孩子,就是你自己了。你想把这群羊涂上不同颜色。
4. 你坐在小凳子上,报数:10号小羊过来,你涂一个;7号小羊过来,再涂一个。你数字是随便报的,涂过的你也不可能再涂一次。并且你只记得你图了 红的3只,绿的20只,剩下67只蓝色。
5. 小羊们喜欢相同颜色的站在一起。你会看到草原上,一会就自动分成红绿蓝三组。同一种颜色离的很近。
6. 你突然高兴的大叫:红,绿,蓝,从少到多诶。
(然后小羊集体,回头鄙视你一下)
好的,现在你应该明白了吧。
类比一下
Particles(一群羊)
ID(羊的身份证)
Neighbors (相同颜色的一组)
ID,起的作用相当于,你只报数给小羊涂颜色 (到底有没有按照ID某一种顺序,这无法得知,也不需要,但没有这数字,你又不知道从哪个开始,又从哪个结束)就像你不知道getFirstParticle到底是哪一个一样。
排序的过程,就是小羊自动相同颜色靠近到一起的过程。一直到最后它们身上的身份证数字也没变。你得到只是不同颜色也就是不同Neighbors总数的顺序,从少到多。
单独利用“粒子的邻居数的重新排列
还用上面小羊的例子说明。如果你不用羊的身份号来叫,你怎么办?难道说,诶,那只大脑袋的,那个小尾巴的这些来叫小 羊过来吧。它们不撂蹄子踢你才怪。
再回到案例上来。如果你想单独利用粒子邻居数,当然不一定非得动用ID。你可以用其它属性。比如速度,压力,位置。但那些属性又不具备唯一性,并且还一直在变。只有ID是最方便的,又是恒定的。故要借助ID进行后面的操作。
在有了上面那幅画后,你能理解了没。
如果没有,再给自己三十分钟,实在不行,就往下看更具体的吧。
第四节:代码回归
在有了上面铺垫,和你近一个小时的思考后。我就能放心的解释红色的代码了:
PS:如果你没有自己理解,还没有思考到一个小时,那么,请你去面壁,自首,自残,自宫。。。。。。
n[id]= len(emp.getNeighbors(0.2))
整体理解:emp发射器中某一粒子数0.2范围内(nighbors)粒子总数值,赋予到n{} dictionary中。
n{}:是上面定义的dictionary
id :是上面定义的粒子id(emp.getID)
len:统一Neighbors列表的总数
i = 0
for a,b in sorted(n.items(), key=lambda x:x[1]):
if scene.getCurrentFrame()*100 > i :
par = em.getParticle(a)
整体理解:看代码先看结构。这段是一个循环嵌套着选择的结构。相信你肯定很清楚的。我就不细说。
最难理解的应该是for那一句。为了清楚我把改写一下。
01 i= 0
02 AA = sorted(n.items(),key=lambda x:x[1])
03 For a,b in AA:
没错就是把排序单独提出来。
最容易让人迷惑的就是,a,b这两个变量。到底什么来头。特别是b,既没有定义,也看不到哪条语句引用。
要理解还得回到 n{}上来,也就是配对列表。
引用时得一对一对的引用,a代表key,b,代表value这样清楚了吧。
如果这样比较一下,就更清楚了。
Key-value
A - b
Storted()固定格式就是
sorted(iterable, cmp=None, key=None, reverse=False)
上面案例中的
n.items() = iterable (准备比较的数据表)
key = lambda x:x[1] (比较参数)
Lambda在知识预备里,你应该也清楚了,它就是一个简单的表达式。
if scene.getCurrentFrame()*100 > i :
这句,更简单,就是获取当前帧乘以100,跟i作比较,如果成立,就执行下面。
罗嗦一点:
让你引起“ID会变”误解的可能是变量名。
你可以把 id = emp.getID() 改成 iq = emp.getID()
看到没,这步只是获取到ID值,只是得到一个数字,无关其它
我在这把你心中想的"id",说成是这里改写后的iq。这个iq是会重新排序的,用
的是sorted内置函数。那它到底如何运作的呢。目前我只探索到这个函数的用法(请看上面的知识准备部分)你是想问它的排序算法吗?这个我不得而知,不知道它是用的冒泡法还是插入法,或是二叉树排序法什么的。(如果你真想知道,你得去研究一下Python的源代码,它本身是开源的。如果你找到,应该告诉我一下。)
这个案例unfreeze,就是按照sorted得出的“组的”顺序。我们眼睛看到的就是,从最外围开始,逐渐到中心 (因为边界粒子周围的neighbors粒子数,肯定没有中心粒子数多。)
补充一点,这个脚本还是比较“笨”的。现在只是通过”I”跟当前帧(CurrentFrame)比较而控制掉落速度的,给人一种从少到多融化的感觉,其实并不是真正连锁反应式的掉落
.如果你想做到真正从少到多连锁式反应的掉落,请深入研究下,本博客中的泡泡案例。
罗嗦二点:
如果自己懂了,请分享出去。把你所学到的教给另外一个人。(检验方式是,把
你教的那个人反馈发给我)如果你做不到,将得不到,本人后续技术支持。不要欺骗
我,请诚实的进行。不然你还会变红名,受到所有分享过我经验人的追杀,切记。
罗嗦三点:
这个脚本是很经典的融化案例,在RealFlow4时代就有了,现在官方网站还有,有相关的教程。你们教材完成把人家漂亮的写法变味了。效率也低了不少。
你们教材案例,犯下忌讳:
1, 无意义的命名,导致出现a,b这些玩意(请你不要向教材学习,对比一下,我附录的原始脚本)
2, 你们教材案例,在开始时漏了关键一句。
particle.setVelocity(Vector.new(0,0,0))
在执行unfreeze操作时,如果不把速度重置为0很容易崩溃。
最后给你提出两点我的问题
1. 如果我要真正的连锁反应样的落下粒子。该怎么修改?
(http://qqww2334.blog.163.com/blog/static/120365822011102503910699/ 参考我的泡泡案例)
2. 为什么下面脚本比上面的效率高一点,高在哪?(这个问题不太好回答,可能要你深入理解Python与RealFlow后才能回答好,但这是一目标,相信你会达到的)
3.
权当你的思考题目,根据你的兴趣,与课余时间来判断到底要不要回答我。
给你附上原始脚本,注意这是写在Script里的,跟你教材写的地方不一样:
#--------------------------------------------------
# Function: onSimulationBegin
# This function is called by the simulation engine
# when the simulation begins.
#--------------------------------------------------
def onSimulationBegin():
emitter = scene.getEmitter("melt")
particle = emitter.getFirstParticle ()
while (particle):
particle.setVelocity(Vector.new(0,0,0))
particle.freeze()
particle = particle.getNextParticle()
#--------------------------------------------------
# Function: onSimulationFrame
# This function is called by the simulation engine
# when the simulation starts the computation of the.
# next frame.
#--------------------------------------------------
def onSimulationFrame(frame):
numNeighbors = {}
emitter = scene.getEmitter("melt")
particle = emitter.getFirstParticle()
while (particle):
numNeighbors[int(particle.id)]=len(particle.getNeighbors(0.1))
particle = particle.getNextParticle()
i=0
for id,n, in sorted(numNeighbors.items(),key = lambda x:x [1],reverse = True):
if i<frame*10 or frame>500:
emitter.getParticle(id).unfreeze()
i+=5
评论