# **通過AnimationNode制作小蘑菇**
* * * * *
## **零、需求分析**
**H子**:**AOI**老師,我現在做完了石頭,準備開始做點別的東西了,想要先做其他的比較通用的小道具。
**AOI**:那么你打算做些什么。小草之類的?
**H子**:先做小蘑菇。而且模型已經做好了一個。

**H子**:因為查了一下文檔,看起來要靠程序化生成還挺費功夫的,所以我設想是干脆做出一個基本的形態,然后讓他有所變化,變出別的形態,讓它看起來是同一類但是卻不是同一個東西。
**AOI**:這算是你對于這種情況的解決方案給出的解答吧。不管是對還是錯,總之先去嘗試。
確實對于技術不需要糾結于某一種,只要能最快達成目的就是好的。
那么你希望外觀有什么地方不一樣呢。
**H子**:首先的話,高度,傘部的大小肥瘦,還有一定程度的彎曲。
那么就在現在這個情況下進行一下需求分析吧:
1. 已經有基礎對象
2. 高度有變化
3. 傘部的大小和肥瘦有變化
4. 蘑菇要有彎曲
那么就在這個基礎上進行對原始模型的改造和添加隨機的變化吧。
## **壹、給蘑菇的形變添加修改器吧【Blender修改器 Hook的運用】**
**H子**:首先的話,我的蘑菇是分成兩個部分來做的,傘蓋和蘑菇柄。

頂點組也根據這部分的結構分成了兩個組。

**AOI**:這次要進行的操作的話,本身其實是沒太有預先區分的必要的。不過已經拆分好也沒問題。
**AOI**:首先,要讓蘑菇有大小變化,傘蓋形狀能獨自控制形態變化,你能想到哪個修改器嗎?
**H子**:骨骼綁定?通過骨骼對上下部分分別控制。
**AOI**:用骨骼并非不行,這也是一種方法,不過其實還有更簡單的做法就是了,那就是Hook修改器。
**H子**:這個我知道!做貝塞爾曲線的時候用過,給曲線的控制點加上Hook就可以簡單的拖著走了。
**AOI**:確實就是那個東西,但是事實上鉤子不僅僅可以用在貝塞爾曲線的控制點上,也可以用在模型對象的頂點上。
操作方法也是一樣的。比如這個蘑菇,要對他的傘蓋進行操作。
那么,選中傘蓋的模型,并按下Ctrl+H,選擇【掛鉤到一個新物體】

場景上就會出現一個新的空物體,這樣就完成了對傘蓋部分的掛鉤操作,也可以看到修改器面板上增添了一個Hook修改器。


記得給空物體改名字,方便后面操作,也方便自己辨別對象。
**H子**:做好了。我看到上面有一個叫衰減類型的參數,上面還有半徑和強度兩個參數,是表示類似于軟選擇一樣的作用嗎。
**AOI**:對的,這地方確實是軟選擇那種功能。這里指的是鉤子作用范圍的衰減,選中的頂點會百分百的受到影響,而沒被選中的定點,就會根據頂點和選中區域的半徑以及衰減類型進行影響。
**H子**:也就是說,如果我的菇柄部分想要上半部分受到鉤子的影響,但是下半部分不受到影響。中間有一個平滑的過渡。我只要對菇柄的上端的頂點添加鉤子,然后設置好衰減參數就可以了?
**AOI**:你可以試試看。
**H子**:先選中空對象,再選中模型,切換到編輯模式,掛鉤到選中的物體......

做好了!確實實現了我要的效果。


**AOI**:這樣的話,傘蓋跟菇柄就關聯起來了。操作空物體的移動,旋轉跟縮放都產生了相應的影響。
到這里第一步就完成了。
## **貳、讓蘑菇傘蓋更自然的起伏吧【Nosie紋理和Displace修改器的運用】**
**H子**:接下來老師先別說,讓我自己來試試看吧。
**AOI**:好,那么接下來你打算做什么呢。
**H子**:我打算讓傘蓋有一定的形變,所以決定用Noise紋理和Displace修改器進行隨機的形變。
首先,給蘑菇添加一個Displace修改器。

然后再在場景上添加個空物體,用于控制Displace,命名為NoiseTag。

給Displace新增一個控制形變的紋理,并設置好紋理參數


選中蘑菇的傘蓋部分,并將其設置為一個頂點組,用于限制Displance形變的范圍。


回到修改器設置界面
把方向設置成【Z】,貼圖坐標系設置為【物體】,并選擇剛創建用于控制Nosie的空對象用作空物體,并且根據需要調整強度。

這個時候,改變空對象的位置就已經可以見到傘蓋有適當的變化了。
## **叁、通過AnimationNode讓蘑菇變化起來【AnimationNode節點RandomVector和ObjectTransfromsOutput的運用】**
**H子**:做到這里的話,接下來就是要對兩個空對象產生隨機位置,然后使得蘑菇有所變化嗎?
**AOI**:對的,做隨機石頭的時候,已經做過類似的操作了,所以,這次你可以自己試試看嗎。
**H子**:好的。
那就先操作Displace修改器的空物體用于產生隨機的傘蓋變化吧。
先創建一個新的節點樹。并且添加**TimeInfo**節點

再添加**RandomVector**節點和**ObjectTransfromsOutput**節點


在選中NoiseTag對象作為ObjectTransfromsOutput節點的操作對象,勾上Loc的XYZ三個復選框,使得對對象的空間位置生效
然后把節點連起來

這樣就設置好了控制隨機傘蓋隨機形變的節點組了。
**AOI**:這一步做的很好。效果確實的出來了,根據需要可以調整RandomVector的Scale值控制幅度。
**H子**:那接下來就該做控制傘蓋的形狀變化了。
首先和控制Displace一樣的做法,首先創建用于控制傘蓋位置Hook控制器的控制節點。目標對象是BaseTaget。

接下來了就該做隨機大小了。為了不讓傘蓋脫離圓形這個狀態,所以果然XY軸要公用一個隨機數吧。但是Z軸要分開。
**AOI**:這個時候就要考慮自己組合一個Vector值了,會用到一個叫**CombineVector**的節點

只要用**Random Number**節點產生目標范圍的數據,再合并成Vector就可以了
**H子**:我試試看。
創建好隨機數節點,然后合并成一個Vector。XY公用一個數據,Z再用一個數據,設置好數據范圍。
考慮到想要以我建模的時候制作的大小作為默認的1單位,那么再設置隨機數范圍的時候,就使用包含負值的數,使得最后的形變能一定程度的變大或者縮小。
所以把合并之后的Vectro和(1,1,1)值相加,得到最后的隨機形變向量。

好了!可以隨意變化了。
**AOI**:做的不錯。那么接下來就是做旋轉吧。
**H子**:搜了一下Combine,發現果然有Combine Euler這類節點阿。那么我直接隨機一個范圍的值用這個節點來合并旋轉就好了吧

然后再合并到Object Tranforms Output上面

## **肆、應用模型變換【Sculpt腳本的再次運用】**
**AOI**:在做石頭的使用,已經嘗試使用命令面板獲取操作過程的命令,以及使用腳本節點進行腳本的調用,這里也是一樣的做法,只不過這次并不是使用Sverchok進行模型的BAKE,而是把基礎的蘑菇模型復制一份,并應用所有的修改器。
**H子**:首先選中基礎的模型,然后按Shift+D復制一個
然后再按Ctrl+A呼出應用變換菜單,選擇Apply All Modifiers

這樣就可以得到這一段的命令了,復制下來,再進行后續的操作

先創建一個Script節點。

并且根據需要添加好足夠的入口節點。
~~~
#如果當前時間>0幀并小于最大計算幀
if((TimeInput > 0) and (TimeInput <= MaxFrame)):
#如果等于BakeFrame的整數倍幀數的時候
if(TimeInput % BaekFrame == 0):
#選中名為ObjecrName的對象
bpy.data.objects[ObjecrName].select = True
#復制選中的對象
bpy.ops.object.duplicate_move(OBJECT_OT_duplicate={"linked":False, "mode":'TRANSLATION'}, TRANSFORM_OT_translate={"value":(0, 0, 0), "constraint_axis":(False, False, False), "constraint_orientation":'GLOBAL', "mirror":False, "proportional":'DISABLED', "proportional_edit_falloff":'SMOOTH', "proportional_size":1, "snap":False, "snap_target":'CLOSEST', "snap_point":(0, 0, 0), "snap_align":False, "snap_normal":(0, 0, 0), "gpencil_strokes":False, "texture_space":False, "remove_on_cancel":False, "release_confirm":False})
#應用修改器
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Hook-空物體")
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Hook-空物體.002")
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Displace")
bpy.ops.object.apply_all_modifiers()
#把復制出來的對象隨機放在PosX和PosY的范圍內。
bpy.ops.transform.translate(value=(PosX, PosY, 0), constraint_axis=(False, False, False), constraint_orientation='GLOBAL', mirror=False, proportional='DISABLED', proportional_edit_falloff='SMOOTH', proportional_size=1)
#取消模型的選擇
bpy.ops.object.select_all(action='DESELECT')
~~~
**H子**:好的,播放一下,確實的能復制出來了!
## **伍、H子的努力【并沒有更多的努力了】**
最終的效果看起來是這樣的

小蘑菇的生成已經沒有什么問題了,H子一時間也沒想到有什么可以繼續補充和優化的地方,所以這次便先到此為止了。
最終的節點圖:

最終代碼和正文中并沒有什么改變,因此不再贅述。