Houdini JoyOfVex 教程02

02

還是01中的話,本文有很多內容來自PB_zz翻譯的文檔,我有相當一部分其實屬於二次創作。
我們在第一節教程裏瞭解了變量,屬性,賦值,很顯然,第二節就需要運用他們了,而對於編程語言來說,將他們包裝爲函數,就是最好的運用,這一節我們來講講函數。
首先,貼出vex可用的函數列表,版本16.5:
https://www.sidefx.com/docs/houdini/vex/functions/index.html
如需其他版本可到http://www.sidefx.com/docs/自行查找
其實這些直接在houdini幫助文檔中查看是一樣的,而且幫助文檔還能下載案例文件
並且把光標放在函數名上,按F1就能直接調出該函數的幫助文檔
我在後期也許也會發掘一些好用的函數並寫成教程

length

那麼正文開始,第一個函數是length
官方給出的len函數定義爲To get the length of a string, or number of items in an array, use len.、
並且返回的是一個float
當我們創建了一個平面一個物體,我們如果需要知道它在x軸在y軸甚至在z軸的距離呢?這個時候就要用到length,我們知道三維物體儲存的位置信息其實是一個vector,可以連接transform節點並查看,而在代碼中,我們就可以這麼利用length

float d = length(@P);
@Cd = d;

這裏將物體的位置信息(x,y,z)三個值的長度賦予一個變量d,然後將儲存了這三個值的變量d賦值給顏色屬性Cd。似乎邏輯沒啥毛病?但我們其實會問兩個問題,第一,一個vector類型的向量怎麼變成了float類型?第二,這麼寫代碼寫成了兩行,爲什麼不直接寫@Cd=@P;?問題的答案就在下面
我們開篇說過,length函數返回的是float值,和Cd類型不一致,當然不可以直接賦值,而至於爲什麼一個verctor變成了float,那就是length自己內部的轉化啦,它其實返回的是向量的歐拉距離,用官方的栗子來說就是這樣:

length({1.0, 0, 0}) == 1.0;
length({1.0, 1.0, 0}) == 1.41421;

那麼我們就能理解length函數了。我們來像文檔中一樣寫些代碼把:

float d = length(@P);
d *= ch('scale'); 
@Cd = sin(d);

提醒一下,d = ch(‘scale’)等同於d = dch(‘scale’),也就是d乘上scale的數值後重新賦予自身,C/C++的同學想必不會對此感到陌生,而有些語言沒有這樣的操作方法顯得有一些可惜,幸好vex支持。不僅如此,vex還支持前置自增和後置自增,不過想想它是基於c語言的,支持也是很正常的事情。對於前置自增和後置,我們可以用以下代碼進行對比,會發現效果不一樣:

float x=length(@P);
@Cd= ++x;

float x=length(@P);
@Cd= x++;

最後是length函數的一個演示:
在這裏插入圖片描述
不過還有一點要注意,Cd的屬性值在0-1之間,而sin的值在-1~1之間,所以我們如果在sin(d)後面加一個1,會避免Cd獲取負值的情況,然後我們再讓賦值式右側除以2,就能夠統一取值了。不過出於一些編程上的原因,建議將除法改爲乘法,也就是/2改爲*0.5,而d在定義後乘以scale的這一步,也可以直接在定義時就完成。所以我們的代碼變爲:

float d = length(@P) * ch('scale');
@Cd = (sin(d)+1)*0.5;
或者
@Cd = (sin(length(@P) * ch('scale'))+1)*0.5;

//我這裏的代碼最終結果與文檔不同,有時間會回來思考原因並修改

distance

和長度相關的還有距離。當你使用length(@P)的時候,你實際上實在測量當前點到{0, 0, 0}原點的距離。而distance函數允許你測量任何兩個數據間的距離。比如我們把grid連上pointWrangle,然後寫上代碼:

 float d = distance(@P, {1,0,3} );
d *= ch('scale'); 
@Cd = (sin(d)+1)*0.5;

你會發現,視窗中grid上的黑白圓環圖像中心點從原點{0, 0, 0}跑到了{1, 0, 3}這個點。

接下來我們介紹一個新的UI參數創建函數,chv(ch是chanel的縮寫,v是vector的縮寫),用它來在界面上創建一個向量參數center:

vector center = chv('center');
float d = distance(@P, center );
d *= ch('scale'); 
@Cd = (sin(d)+1)*0.5;

這樣你就能使用參數隨時手動調整黑白圓環的中心點位置了。也就是調整向量值了。
提示一下,將@P乘以{0.5, 1, 1},你就能讓@P.x的值縮小一半。
我們來整理一下代碼:

vector pos = @P * chv('fancyscale');//模型上的點位置值縮放後的結果
vector center = chv('center');//中心點位置
float d = distance(pos, center );//計算兩點距離
d *= ch('scale');//將距離縮放
@Cd = (sin(d)+1)*0.5;//距離作爲sin函數自變量,整個式子把結果值映射到0~1之間

敲黑板!注意了!你的UI創建函數ch和chv裏使用的名稱不能是相同的,否則只會生成一個UI參數,例如已經寫了chv(‘scale’),下面又寫ch(‘scale’),這樣houdini會根據優先級只生成一個參數,同樣的,變量名也不要定義相同的,而且最好這些名稱看起來是有意義的,比如是一些單詞或者該單詞的縮寫,而不是隨便取個名叫a,b,c,x之類的。

另外你會發現對代碼進行修改,但UI界面卻不會實時更新,或者說舊的參數它不會自動消失,這時你可以右鍵點擊該參數,選擇More-Delete Spare Parameter,這樣該參數就被你刪除了。或者有一種一刀切的懶方法,你可以點擊wrangle節點菜單欄上那個齒輪按鈕,在下拉菜單中選擇Delete All Spare Parameter,這樣所有生成的UI參數就都消失了,然後你再點擊代碼編輯器右側的那個創建參數按鈕(圖標是滑竿和一個加號的那個,上節課講過),重新生成代碼裏的參數,當然,圖方便的代價就是你之前調好的數值都沒啦,全變成了默認值。
接下來我們介紹一個新函數fit,這個函數是專門來做值範圍映射的。之前我們是手動將sin的值通過計算映射到0~1之間( @Cd = (sin(d)+1)*0.5;),現在有了fit函數,我們就不用每次都想算法來計算了,這個函數會自動幫你搞定。用法如下:

vector pos = @P * chv('fancyscale');
vector center = chv('center');
float d = distance(pos, center );
d *= ch('scale'); 
@Cd = fit(sin(d),-1,1,0,1);
 /* fit(value, omin, omax, nmin, nmax)  同樣可在幫助文檔查詢,簡單來說fit括號裏填的就是要修改的數	據,以及舊範圍的最小最大,新範圍的最小最大。*/

一般來說,三角函數都伴隨時間使用的,sin(wt)。houdini裏時間的屬性是@time,我們把它作爲sin的變量的話,點擊時間軸的播放按鈕,你會發現,sin的數值隨時間變化而變化,我們的圖像也有了自動交替的黑白變化動畫。

vector pos = @P * chv('fancyscale');
vector center = chv('center');
float d = distance(pos, center );
d *= ch('scale'); 
@Cd = fit(sin(d+@Time),-1,1,0,1);

@Time也可以寫成@Frame,time是秒的記錄,frame是幀的記錄。

最後的提示:
如果你要將一個變量乘以5,你可以這樣寫:
foo = foo * 5;
也可以使用運算符(又譯操作符,英文operator)*=:
foo *= 5;
同樣的,類似的有+=, -=, /=。另外你可以在一行代碼上進行非常多的運算:

foo = (foo * 3 +1) / @Cd.x + @N.y;

不過不建議寫太長,分開一步步寫更容易理解:

foo *=3; // set range
foo +=1; // make sure values never get below 0
foo /= @Cd.x; // reduce range to within red value
foo += @N.y; // addition normal on y

第二節就這麼多,有時候懶得總結或者添加一些東西我就會嘩啦啦把文檔的翻譯複製粘貼,不過我想等我有時間了一定會重新改進原創一遍的,嗯,以我blender寶典更了一章就太監的經驗來看,應該是會回來改的
本節寫於2020-1-9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章