Houdini學(xué)習(xí)筆記024_VEX曲面編織
學(xué)習(xí)筆記和教程最大的區(qū)別在于,會記錄一些我在操作中試錯的過程。包括遇到問題后嘗試解決的思路和方法。特別是在寫VEX腳本時,warning時不時就會冒出來探望我一下。然后我會想方設(shè)法拒絕它的拜訪,哪兒涼快哪兒待著去。
上一篇當(dāng)中講解了平面編織結(jié)構(gòu)的VEX做法,這次我們稍加拓展,將平面換成曲面。當(dāng)然,還是做縱橫交錯的簡單編織圖案。
對于曲面而言,由于各局部朝向都不一樣,所以不能直接用簡單的移動來定義坐標(biāo)點的位置。很顯然,要和法線方向結(jié)合起來。這里我給grid(15×15)添加mountain節(jié)點,調(diào)節(jié)參數(shù)得到隨機(jī)起伏狀。

首先我們應(yīng)確認(rèn)uv方向的點數(shù)。平面的分段是設(shè)置好的,但如果是一個外部導(dǎo)入的曲面,怎么獲取兩個方向的點數(shù)呢?比較簡單的是直接顯示點序號查看:很容易看出u方向有0~14共15個點,v方向為225/15=15個點。

能不能直接用導(dǎo)入的曲面生成這兩個數(shù)值呢?因為這里我們設(shè)定曲面是四邊形網(wǎng)格狀的,假設(shè)uv方向各有x和y個點,可以根據(jù)總的點數(shù)和面數(shù)來解如下所示的方程組。

計算結(jié)果可以用Attribute Wrangle節(jié)點設(shè)為Detail屬性,如下圖所示(x和y)——

?比如我將初始grid的分段設(shè)為16和18,在wrangle節(jié)點的detail屬性中可以看到x和y的值分別為18和16。由于上面方程組的解x和y的值是可以互換的,對應(yīng)的網(wǎng)格面長寬比可能大于1,也可能小于1。應(yīng)該有辦法確認(rèn),這里我就不再拓展了。后面如果結(jié)果有問題,把這兩個值對調(diào)一下應(yīng)該就OK了。

接下來我們沿用上一篇的思路,先畫出一條波浪折線。方法是在原有的點基礎(chǔ)上讓其沿法線方向偏移一定高度得到新的點。使用Point Wrangle節(jié)點,Run Over方式改為Detail (only once)。將屬性@x和@y分別賦值給numu和numv。

參照之前的教程,定義一個points數(shù)組用于接收addpoint函數(shù)的返回值,后面畫線用。resize函數(shù)設(shè)置其長度為numu。for循環(huán)中用point函數(shù)分別獲取第i個點的坐標(biāo)和法線。

現(xiàn)在需要定義一個偏移值,可以寫為:
float offset = chf("height");
并讓原來的點坐標(biāo)沿法線方向發(fā)生偏移:
pos += normal * offset;

接下來的VEX腳本和之前一樣:
int ptid = addpoint(0, pos);
points[i] = ptid;

寫完之后調(diào)整height的數(shù)值,發(fā)現(xiàn)點的位置并沒有發(fā)生偏移。因為默認(rèn)的平面是沒有法線屬性的。只需要添加normal節(jié)點,將其指定給point就可以了。

讓其發(fā)生交錯也很容易,在pos +=一句后面乘上系數(shù)pow(-1, i)即可。最后用addprim函數(shù)畫線,上一篇中講過,不再贅述。

下面寫for循環(huán)嵌套從一條線得到多條線,有兩個地方要注意,一個是pow(-1, i+j)得到每行交錯的波浪線,另一個是循環(huán)內(nèi)獲取點編號為i+j*numu。

另外一個方向也是很容易實現(xiàn)的,只需要將上述代碼稍加修改即可(主要是點的編號獲?。?br>

最后代碼整理優(yōu)化如下(如果有問題,將初始的numu和numv對調(diào)一下)——
int numu = int(@x);
int numv = int(@y);
int ptu [];
resize(ptu, numu);
float offset = chf("height");
for(int j = 0; j < numv; j++){
? ? for(int i = 0; i < numu; i++){
? ? ? ? vector pos = point(0,"P",i+j*numu);
? ? ? ? vector normal = point(0,"N",i+j*numu);
? ? ? ? pos += normal * offset * pow(-1, i+j);
? ? ? ? int ptid = addpoint(0, pos);
? ? ? ? ptu[i] = ptid;
? ? }
? ? addprim(0, "polyline", ptu);
}
int ptv [];
resize(ptv, numv);
for(int j = 0; j < numu; j++){
? ? for(int i = 0; i < numv; i++){
? ? ? ? vector pos = point(0,"P",j+i*numu);
? ? ? ? vector normal = point(0,"N",j+i*numu);
? ? ? ? pos += normal * offset * pow(-1, i+j+1);
? ? ? ? int ptid = addpoint(0, pos);
? ? ? ? ptv[i] = ptid;
? ? }
? ? addprim(0, "polyline", ptv);
}
后面的步驟比較簡單,這里就簡單介紹下。由于最后我們要得到的是線,可以用delete節(jié)點刪除原來的面。Entity選擇Primitives,Operation選擇Delete by Range。刪除的范圍從0~254。254也就是(x-1)(y-1)-1的值??梢杂胐etail函數(shù)獲取,寫法為:
(detail("../calculate_x_y", "x", 0) - 1) * (detail("../calculate_x_y", "x", 0) - 1) - 1
注意這里末尾就不要加分號了,calculate_x_y是我前面定義的節(jié)點名稱,你也可以定義為別的。

怎么刪除邊緣的四條波浪線不用我再講一遍了吧,包括接下來的操作請參考上一篇。

最后的最后,用null節(jié)點設(shè)定兩個參數(shù)進(jìn)行最終的調(diào)節(jié)(編織纖維的起伏高度height和半徑radius)。設(shè)置方法參考筆記10。

今天的分享就這多了,感謝閱讀,下回見~