# **通过AnimationNode制作小蘑菇**
* * * * *
## **零、需求分析**
**H子**:**AOI**老师,我现在做完了石头,准备开始做点别的东西了,想要先做其他的比较通用的小道具。
**AOI**:那么你打算做些什么。小草之类的?
**H子**:先做小蘑菇。而且模型已经做好了一个。
![](https://box.kancloud.cn/e5d835a86724180c0116764636edffc0_224x255.png)
**H子**:因为查了一下文档,看起来要靠程序化生成还挺费功夫的,所以我设想是干脆做出一个基本的形态,然后让他有所变化,变出别的形态,让它看起来是同一类但是却不是同一个东西。
**AOI**:这算是你对于这种情况的解决方案给出的解答吧。不管是对还是错,总之先去尝试。
确实对于技术不需要纠结于某一种,只要能最快达成目的就是好的。
那么你希望外观有什么地方不一样呢。
**H子**:首先的话,高度,伞部的大小肥瘦,还有一定程度的弯曲。
那么就在现在这个情况下进行一下需求分析吧:
1. 已经有基础对象
2. 高度有变化
3. 伞部的大小和肥瘦有变化
4. 蘑菇要有弯曲
那么就在这个基础上进行对原始模型的改造和添加随机的变化吧。
## **壹、给蘑菇的形变添加修改器吧【Blender修改器 Hook的运用】**
**H子**:首先的话,我的蘑菇是分成两个部分来做的,伞盖和蘑菇柄。
![](https://box.kancloud.cn/47b76e9f7767fd0c60bbaeb0871240ea_285x231.png)
顶点组也根据这部分的结构分成了两个组。
![](https://box.kancloud.cn/ea3fa50c8cf8f2f7fc74fe7a0f2f7538_221x84.png)
**AOI**:这次要进行的操作的话,本身其实是没太有预先区分的必要的。不过已经拆分好也没问题。
**AOI**:首先,要让蘑菇有大小变化,伞盖形状能独自控制形态变化,你能想到哪个修改器吗?
**H子**:骨骼绑定?通过骨骼对上下部分分别控制。
**AOI**:用骨骼并非不行,这也是一种方法,不过其实还有更简单的做法就是了,那就是Hook修改器。
**H子**:这个我知道!做贝塞尔曲线的时候用过,给曲线的控制点加上Hook就可以简单的拖着走了。
**AOI**:确实就是那个东西,但是事实上钩子不仅仅可以用在贝塞尔曲线的控制点上,也可以用在模型对象的顶点上。
操作方法也是一样的。比如这个蘑菇,要对他的伞盖进行操作。
那么,选中伞盖的模型,并按下Ctrl+H,选择【挂钩到一个新物体】
![](https://box.kancloud.cn/c847f2762ee51a4f6b98881c6bac4da5_212x129.png)
场景上就会出现一个新的空物体,这样就完成了对伞盖部分的挂钩操作,也可以看到修改器面板上增添了一个Hook修改器。
![](https://box.kancloud.cn/9c7877df5ca98c4832fd45bad7d13bd7_257x200.png)
![](https://box.kancloud.cn/d0aa2a0a727382f1f9941535e9097624_229x206.png)
记得给空物体改名字,方便后面操作,也方便自己辨别对象。
**H子**:做好了。我看到上面有一个叫衰减类型的参数,上面还有半径和强度两个参数,是表示类似于软选择一样的作用吗。
**AOI**:对的,这地方确实是软选择那种功能。这里指的是钩子作用范围的衰减,选中的顶点会百分百的受到影响,而没被选中的定点,就会根据顶点和选中区域的半径以及衰减类型进行影响。
**H子**:也就是说,如果我的菇柄部分想要上半部分受到钩子的影响,但是下半部分不受到影响。中间有一个平滑的过渡。我只要对菇柄的上端的顶点添加钩子,然后设置好衰减参数就可以了?
**AOI**:你可以试试看。
**H子**:先选中空对象,再选中模型,切换到编辑模式,挂钩到选中的物体......
![](https://box.kancloud.cn/12836a28ef58b73584e4b9de1f8202b4_452x353.png)
做好了!确实实现了我要的效果。
![](https://box.kancloud.cn/a4bdc523eb0a2979e3d3a511e1c15dc3_222x380.png)
![](https://box.kancloud.cn/f4b6a0e9bc341b215bfef35f7cca0653_511x356.png)
**AOI**:这样的话,伞盖跟菇柄就关联起来了。操作空物体的移动,旋转跟缩放都产生了相应的影响。
到这里第一步就完成了。
## **贰、让蘑菇伞盖更自然的起伏吧【Nosie纹理和Displace修改器的运用】**
**H子**:接下来老师先别说,让我自己来试试看吧。
**AOI**:好,那么接下来你打算做什么呢。
**H子**:我打算让伞盖有一定的形变,所以决定用Noise纹理和Displace修改器进行随机的形变。
首先,给蘑菇添加一个Displace修改器。
![](https://box.kancloud.cn/eedf851ee309c2403b3adc42ab42b378_608x432.png)
然后再在场景上添加个空物体,用于控制Displace,命名为NoiseTag。
![](https://box.kancloud.cn/814a7ff4ccc932752ae987239b0a81ae_310x241.png)
给Displace新增一个控制形变的纹理,并设置好纹理参数
![](https://box.kancloud.cn/01d5f9ab9df147c94c88dcd44639b3c7_223x134.png)
![](https://box.kancloud.cn/31f06fb8b520f68d261683ba7ee2e2c6_240x586.png)
选中蘑菇的伞盖部分,并将其设置为一个顶点组,用于限制Displance形变的范围。
![](https://box.kancloud.cn/a1beb8d9e7aa49b14c58611212978816_377x255.png)
![](https://box.kancloud.cn/18994bc97c3f9dfd37b098abeea66cb8_239x225.png)
回到修改器设置界面
把方向设置成【Z】,贴图坐标系设置为【物体】,并选择刚创建用于控制Nosie的空对象用作空物体,并且根据需要调整强度。
![](https://box.kancloud.cn/a7c07ec4da53facd6d14b01245dafffd_226x253.png)
这个时候,改变空对象的位置就已经可以见到伞盖有适当的变化了。
## **叁、通过AnimationNode让蘑菇变化起来【AnimationNode节点RandomVector和ObjectTransfromsOutput的运用】**
**H子**:做到这里的话,接下来就是要对两个空对象产生随机位置,然后使得蘑菇有所变化吗?
**AOI**:对的,做随机石头的时候,已经做过类似的操作了,所以,这次你可以自己试试看吗。
**H子**:好的。
那就先操作Displace修改器的空物体用于产生随机的伞盖变化吧。
先创建一个新的节点树。并且添加**TimeInfo**节点
![](https://box.kancloud.cn/52d46114d8de6fba1f6a5466e8c9f6c3_118x54.png)
再添加**RandomVector**节点和**ObjectTransfromsOutput**节点
![](https://box.kancloud.cn/969f1f73c57ffca9ae03c0a890da40f4_116x100.png)
![](https://box.kancloud.cn/cd50c09f94af331094fa217fe39418ed_124x136.png)
在选中NoiseTag对象作为ObjectTransfromsOutput节点的操作对象,勾上Loc的XYZ三个复选框,使得对对象的空间位置生效
然后把节点连起来
![](https://box.kancloud.cn/4dc548d695c423d54f6ab6dc52693e82_671x160.png)
这样就设置好了控制随机伞盖随机形变的节点组了。
**AOI**:这一步做的很好。效果确实的出来了,根据需要可以调整RandomVector的Scale值控制幅度。
**H子**:那接下来就该做控制伞盖的形状变化了。
首先和控制Displace一样的做法,首先创建用于控制伞盖位置Hook控制器的控制节点。目标对象是BaseTaget。
![](https://box.kancloud.cn/e0e9c5736628aa9d9d0b08ceecffd70a_828x190.png)
接下来了就该做随机大小了。为了不让伞盖脱离圆形这个状态,所以果然XY轴要公用一个随机数吧。但是Z轴要分开。
**AOI**:这个时候就要考虑自己组合一个Vector值了,会用到一个叫**CombineVector**的节点
![](https://box.kancloud.cn/6dd3b76fbfdc5778994437353efc0cea_150x131.png)
只要用**Random Number**节点产生目标范围的数据,再合并成Vector就可以了
**H子**:我试试看。
创建好随机数节点,然后合并成一个Vector。XY公用一个数据,Z再用一个数据,设置好数据范围。
考虑到想要以我建模的时候制作的大小作为默认的1单位,那么再设置随机数范围的时候,就使用包含负值的数,使得最后的形变能一定程度的变大或者缩小。
所以把合并之后的Vectro和(1,1,1)值相加,得到最后的随机形变向量。
![](https://box.kancloud.cn/a926232a34eb847025ddd06155e77880_1200x479.png)
好了!可以随意变化了。
**AOI**:做的不错。那么接下来就是做旋转吧。
**H子**:搜了一下Combine,发现果然有Combine Euler这类节点阿。那么我直接随机一个范围的值用这个节点来合并旋转就好了吧
![](https://box.kancloud.cn/90a26aef1bdb2b3e445dcfab68a21828_793x309.png)
然后再合并到Object Tranforms Output上面
![](https://box.kancloud.cn/36eb5604ff76c4e7ace8ff09655895d4_888x509.png)
## **肆、应用模型变换【Sculpt脚本的再次运用】**
**AOI**:在做石头的使用,已经尝试使用命令面板获取操作过程的命令,以及使用脚本节点进行脚本的调用,这里也是一样的做法,只不过这次并不是使用Sverchok进行模型的BAKE,而是把基础的蘑菇模型复制一份,并应用所有的修改器。
**H子**:首先选中基础的模型,然后按Shift+D复制一个
然后再按Ctrl+A呼出应用变换菜单,选择Apply All Modifiers
![](https://box.kancloud.cn/a3fcc6237d40e328bf86019fbdaaa62e_229x326.png)
这样就可以得到这一段的命令了,复制下来,再进行后续的操作
![](https://box.kancloud.cn/2be6d8df902d1d2ff819930e5c476525_1908x86.png)
先创建一个Script节点。
![](https://box.kancloud.cn/0faf5607886ce3057b1afce229ffed9d_231x308.png)
并且根据需要添加好足够的入口节点。
~~~
#如果当前时间>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子的努力【并没有更多的努力了】**
最终的效果看起来是这样的
![](https://box.kancloud.cn/0537adcf80068147566377b4eaeb665e_919x317.png)
小蘑菇的生成已经没有什么问题了,H子一时间也没想到有什么可以继续补充和优化的地方,所以这次便先到此为止了。
最终的节点图:
![](https://box.kancloud.cn/fbbccbf121c4a3bc966f6ebd69dd5c47_1444x945.png)
最终代码和正文中并没有什么改变,因此不再赘述。