RealFlow 學習筆記 005 – 使用 Python 撰寫 RealFlow 的 Scripts
前言
RealFlow 內的 Scripts 使用 Python 來架構(RealFlow 2013 的是 Python 2.4),此篇為學習筆記,因此並沒有特地編排順序也沒有特別由淺到深的安排。
因此可能有些資料只是寫出片段或是不完整,如發現錯誤或有其他疑義,歡迎留言討論! : )
1. 物件.屬性 或者說 物件.方法
例如、 scene.getCurrentFrame() ,取得現在的 frame
而有哪些物件呢? 請到 Realflow 的說明書內,找 Script Reference 即可看到眾多的可用物件,請參考下圖一:
圖一、說明書裡頭關於 Scripts 的部份
有一點一定要講清楚,注意啊! RealFlow 裡面的 Object ,並不是指物件程式設計上所謂的物件(也叫 object ),而是指有實體的幾何模型喔!
為求清楚,下文中,凡是要講 RealFlow 內的幾何模型(Object) 時,我會稱為「物體」。而討論 Python 跟程設的 object 時候,我會說「物件」。
2. 物件程式設計
記住,Python 風格來說,任何變數都是物件對於一個物件,只要有可用的方法(成員函數),就可以作業,要擺脫結構化程式語言的單純資料型態與變數的思維。
註,對不起,最後一句是寫給我自己看的 ^o^ 各位不必在意
3. 對照 Script Reference 玩操作
找到各個 Class 列表,例如 Scene 這個 Class,則下面的 member function 都是可以使用的,例如 、
scene.addVase(參數)
我們可以把結果回傳給一個新的物件,例如、
ResultObj=scene.addVase(參數) # 把結果存到 ResultObj 這個物件裡
然後可以對這個新物件繼續進行方法的操作,例如
MyObj.setParameter(屬性名稱, 值) okOBJ=MyObj.freezeTransform
注意,若數值是純量那麼它當然是一個值,可向量會有三個值,所以必須使用 Vector 來處理,例如新增向量請用 Vector.new(a,b,c) 來新增。
4. Script editor 跟 Edit 選單可以新增自訂程式稿
5 GUIFormDialog
這就是一個非常簡單的選單 class,它提供一個表單給你輸入自定數值 (它的顯示排序方法,預設用字母,想要有自訂排序,可以自己加數字)
表格物件 = GUIFormDialog.new() 表格物件.addIntFiled("欄位名稱", 預設值) 表格物件.addBoolFiled("欄位名稱", 預設值)
user 填好了表單,如何取得某欄位的值?
表格物件.getFieldValue("欄位名稱")
上圖的範例,是由 RealFlow 2013 說明書內提供的範例程式碼:
#------------------------------------------------------------------------------ # Show the basic mechanism for setting up the form and getting values. #------------------------------------------------------------------------------ form = GUIFormDialog.new() form.setTitle("User input") form.addStringField( "Name", "Grijaldo More" ) form.addIntField( "Age", 35 ) form.addFloatField( "Height", 1.78 ) form.addVectorField( "Position", 11.2, 2.1, 31.0111 ) form.addBoolField( "Filled", True ) options = [ "fluid", "dumb", "elastics" ] form.addListField( "Type", options, 1 ) form.addObjectField("select object", TYPE_DAEMON | TYPE_OBJECT, SELECTION_UNIQUE) if ( form.show() == GUI_DIALOG_ACCEPTED ): scene.message( str( form.getFieldValue( "Name") ) ) scene.message( str( form.getFieldValue( "Age") ) ) scene.message( str( form.getFieldValue( "Height") ) ) scene.message( str( form.getFieldValue( "Filled") ) ) scene.message( options[form.getFieldValue( "Type")] ) pos = form.getFieldValue( "Position"); scene.message( str( pos.x ) ) scene.message( str( pos.y ) ) scene.message( str( pos.z ) )
7. 送出 ok 時,下述敘述會成立
表格物件.show() == GUI_DIALOG_ACCEPTED
所以你可以看到 if 內的敘述,就是按下 ok 後要做的事情。
8. Event & Batch Script
Event Script裡面已經準備好五個函式,Event Script 在 RealFlow 5 以後,改名 Simulation Events 。
( 對於 Next Limit 一直亂改按鈕或名稱感到很不爽 )
事件編輯器可以自定模擬過程中,隨時間變化的一些東西,例如下圖,簡單的計算兩個發射器的粒子互撞時,發射器 L 的粒子會自殺,然後原地產生一個發射器F 的粒子:
9. 互撞程式設計邏輯隨記
# 新增與取得該物體 新增物件 = scene.AddVase 物件1 = scene.getObject("物體1名稱") 物件2 = scene.getObject("物體2名稱") # 互撞 posList = 物件1.getCollision(物件2) # 上面的碰撞回傳為碰撞座標,資料結構是 list
10. 發射器程式隨記
物件3 = 取得發射器 物件3.addParticle(座標,速度)
11. 亂數
random.random random.uniform
12 其他
scene.setRootPath # 取得工作目錄 shutil.copytree # 複製 … scene.loadEventScript("檔案路徑") # 執行即可在事件編輯器內,呼叫出該事件程式碼
13. 時間模組
impot time string = time.strftime("%d-%m-%Y", time.localtime())
14. 操作幾何模型隨記
scene.getGlobalValue("名稱") scene.setGlobalValue("名稱",值) 表格物件.getFieldValue("欄位名稱")
15. pass
事件編輯器內,你可以看到所有 def 函式: 下面都有個 pass 字樣,那是叫直譯器別理會這段的意思。所以如果你有程式要撰寫在這部份,請你把pass去掉,謝謝。
16. script deamon
使用 Script 來撰寫屬於自己的作用力場,例如 3.5 次方反比的重力 XDDD
按下 Edit 按鈕後,會彈出編輯器,可看到內有定好的預設函數與 pass,依照需要自訂整個作用力場。可以使用這樣的簡單方式給每一顆粒子單獨而特定的作用力。
使用隨記:
def applyForceToEmitter(emitter): 粒子物件 = emitter.getFirstParticle() while 粒子物件: 粒子物件.setExternalForce(來個向量吧) 粒子物件 = 粒子物件.getNextParticle()
17.
applyForceToEmitter 函數作用在發射器
applyForceToBody 函數作用在 Body 上
記住是「力」,所以物理因次是 ma 喲!(F=ma啦!)
removeParticle 可以處理粒子的後續或這集體行為
18. 編寫海浪
在 Realwave 裡,添加 script wave 即可自行編寫海浪模式。 (編寫的動作每個frame都會跑一次)
19. 在編輯器內可以引入序列圖擋
先取得這一個frame的編號(記得要+1-1去符合序列檔名),並製作好路徑參數給一個路徑物件
圖物件 = Image.new() 圖物件.open( 路徑物件) imageSIZE = 圖物件.size[0] # 嗯 0 1 都可以啦 反正是正方形圖片 for ( 跑 0~所有錨點 ): pixelX = ( imageSIZE -1 )*vertice[i].uwz.x # 後面是0~1的uv座標,前半是圖片大小,可是畢竟可用座標是 0~ SIZE-1,而不是 1~ SIZE,所以要減一 pixelY = ( imageSIZE -1 )*vertice[i].uwz.z # pixelY 如法炮製 newY值 = 圖物件.getPixel(pixelX,pixelY)[0] /255.0 # 除一下比較好啦^_^你不會想看到高度255的海浪吧 # 最後把 newY 值塞進一個向量後, # 送入vertice[i]即可,vertice[i]本身也是個向量。
- 對於Vetex 的 uwz ,是個變數,可以 return 這一個錨點的材質座標,看起來應該是 UV 座標,因此範圍應該是0~1
- 如果大小不對,要在 RW 內找到 fit texture,而要 fit texture 之前,請先打開 calculate texture
20. 對於發射器,除了液體、 dumb以外,有個 custum ,可以二按下下面的EDIT來編輯自訂的發射與行為屬性
computeInternalForces 函式(發射器) 粒子物件 = emitter.getFirstParticle 粒子物件.setInternalForce(力的大小) 力是向量
就可以針對每一粒子去作用囉!
21. 抓面、錨點,然後送到 addObject 去生成跟複製
面物件.getIndices 可以抓一個面的三個錨點的index;而 Face.new(0,1,2) 可以生成新的面,說明書有個很不錯的生成一個單一新面的範例如下:
#------------------------------------------------------------------------------ # Add a new object to the scene which is just a triangle. #------------------------------------------------------------------------------ vertices = [] position = Vector.new( 0, 0, 0 ) velocity = Vector.new( 0, 0, 0 ) vertices.append( Vertex.new( position ) ) position = Vector.new( 1, 0, 0 ) velocity = Vector.new( 0, 0, 0 ) vertices.append( Vertex.new( position ) ) position = Vector.new( 1, 1, 0 ) velocity = Vector.new( 0, 0, 0 ) vertices.append( Vertex.new( position ) ) faces = [] face = Face.new( 0, 1, 2 ) faces.append( face ) scene.addObject( "triangle", vertices, faces )
22.
可以新增發射器,讓發射器的粒子透過 Magic 去追逐吸附 import 進來的 OBJ Mesh
23.
新發射器可以少量的 dumb 粒子,然後透過 script 抓這些粒子的位置跟速度
然後在同一個位置,進行 發射器物件.addParticles ,這樣就是「以粒子當新的發射器」 。
Leave a Reply