RealFlow 學習筆記 005 – 使用 Python 撰寫 RealFlow 的 Scripts

前言

RealFlow 內的 Scripts 使用 Python 來架構(RealFlow 2013 的是 Python 2.4),此篇為學習筆記,因此並沒有特地編排順序也沒有特別由淺到深的安排。

因此可能有些資料只是寫出片段或是不完整,如發現錯誤或有其他疑義,歡迎留言討論! : )


1. 物件.屬性  或者說  物件.方法

例如、 scene.getCurrentFrame()   ,取得現在的 frame

而有哪些物件呢?  請到 Realflow 的說明書內,找  Script Reference 即可看到眾多的可用物件,請參考下圖一:

image

圖一、說明書裡頭關於 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("欄位名稱")

image

上圖的範例,是由 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 一直亂改按鈕或名稱感到很不爽 )

157

事件編輯器可以自定模擬過程中,隨時間變化的一些東西,例如下圖,簡單的計算兩個發射器的粒子互撞時,發射器 L 的粒子會自殺,然後原地產生一個發射器F 的粒子:

158

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去掉,謝謝。

image

 

16. script deamon

使用 Script 來撰寫屬於自己的作用力場,例如  3.5 次方反比的重力 XDDD

按下 Edit 按鈕後,會彈出編輯器,可看到內有定好的預設函數與 pass,依照需要自訂整個作用力場。可以使用這樣的簡單方式給每一顆粒子單獨而特定的作用力。

159

使用隨記:

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 ,這樣就是「以粒子當新的發射器」  。

24. 挑揀物體的視窗 GUINodesPickerDialog

71

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料