Unity中Skinned Mesh Renderer Blend Shapes小試

2021-05-25 06:00:01

 

第一個應用:如何使用網格渲染器Blend Shapes Unity製作木棍剝皮

1、 Intro

test222.gif

2、Modeling (Blender)

開啟Blender 軟體

調整視角

image.png

然後快捷鍵: Shift+A

新增Mesh : Cylinder

頂點數改為:

image.png

 

Rotate Around X Axis : 快捷鍵 R+X+90

image.png

 

Scale :Y Axis   : 快捷鍵  S+Y

image.png

進入Edit Mode  :   快捷鍵  Tab

 

Add more Loops :  快捷鍵   Ctrl + R   然後改變滑鼠的滾輪: image.png    就會看到橫向線的變化。

下圖中橫向線都是新增的 。

image.png    -> image.png

 

Right click to undo movements

image.png

 

Exit Edit  Mode  :   快捷鍵  Tab

 

 

增加Shape Keys

image.png

image.png

 

 

image.png

進入Edit Mode然後      ,Alt + 橫線選中, 然後快捷鍵 S + 0    , 一個關鍵幀就完成了。

image.png

重複n次把所有橫線都增加key

image.png

 

 

然後點選File 匯出 FBX 檔案 。

然後匯入Unity工程中。

3、 Setup scene

建立空物件掛點, Wood Holder, Wood   , 然後拖拽模型掛上

image.png

然後調整模型的旋轉,也可以看到在Blender中新增的 Shape keys 在Unity中有資料, 可以在Inspector中改變key的值檢視scene中模型的變化。

image.png

 

替換成更像木頭的材質:  wood  

image.png

 

場景中需要放另外的物體: 刻刀 Knife , 有碰撞體跟剛體(限制運動方向等引數設定),與控制指令碼Knife.cs

image.png

 

4、Wood Rotation (DoTween)

新增第一個指令碼 Wood.cs  讓木頭先旋轉

 

image.png

using UnityEngine ;
using DG.Tweening ;

public class Wood : MonoBehaviour {
   [SerializeField] private SkinnedMeshRenderer skinnedMeshRenderer ;
   [SerializeField] private Transform woodTransform ;
   [SerializeField] private Vector3 rotationVector ;
   [SerializeField] private float rotationDuration ;

   private void Start () {
      woodTransform
         .DOLocalRotate (rotationVector, rotationDuration, RotateMode.FastBeyond360)
         .SetLoops (-1, LoopType.Restart)
         .SetEase (Ease.Linear) ;
   }

   public void Hit (int keyIndex, float damage) {
      float colliderHeight = 2.39705f ;
      //Skinned mesh renderer key's value is clamped between 0 & 100
      float newWeight = skinnedMeshRenderer.GetBlendShapeWeight (keyIndex) + damage * (100f / colliderHeight) ;
      skinnedMeshRenderer.SetBlendShapeWeight (keyIndex, newWeight) ;
   }
}

執行時就會旋轉了。

 

5、 Knife Movement

新增指令碼 Knife.cs   移動刀片

using UnityEngine ;

public class Knife : MonoBehaviour {
   [SerializeField] private float movementSpeed ;
   [SerializeField] private float hitDamage ;
   [SerializeField] private Wood wood ;

   [SerializeField] private ParticleSystem woodFx ;

   private ParticleSystem.EmissionModule woodFxEmission ;

   private Rigidbody knifeRb ;
   private Vector3 movementVector ;
   private bool isMoving = false ;

   private void Start () {
      knifeRb = GetComponent<Rigidbody> () ;

      woodFxEmission = woodFx.emission ;
   }

   private void Update () {
      isMoving = Input.GetMouseButton (0) ;

      if (isMoving)
         movementVector = new Vector3 (Input.GetAxis ("Mouse X"), Input.GetAxis ("Mouse Y"), 0f) * movementSpeed * Time.deltaTime ;
   }

   private void FixedUpdate () {
      if (isMoving)
         knifeRb.position += movementVector ;
   }

   private void OnCollisionExit (Collision collision) {
      woodFxEmission.enabled = false ;
   }

   private void OnCollisionStay (Collision collision) {
      Coll coll = collision.collider.GetComponent <Coll> () ;
      if (coll != null) {
         // hit Collider:
         woodFxEmission.enabled = true ;
         woodFx.transform.position = collision.contacts [ 0 ].point ;

         coll.HitCollider (hitDamage) ;
         wood.Hit (coll.index, hitDamage) ;
      }
   }
}

 

6、Colliders

 

新增碰撞體:

image.png

先調整引數,這樣可以確定每個key的位置

image.png

image.png

為每個碰撞體新增指令碼 Coll.cs  

using UnityEngine ;

public class Coll : MonoBehaviour {
   public int index ;

   BoxCollider boxCollider ;

   private void Awake () {
      boxCollider = GetComponent<BoxCollider> () ;
      index = transform.GetSiblingIndex () ;
   }

   public void HitCollider (float damage) {
      // Resize the collider's height(Y) depends on "damage" 
      if (boxCollider.size.y - damage > 0.0f)
         boxCollider.size = new Vector3 (boxCollider.size.x, boxCollider.size.y - damage, boxCollider.size.z) ;
      else
         Destroy (this) ; // Remove Coll Component from this gameobject
   }
}

 

7、Wood Deformation (Skinned Mesh Renderer)

Wood.cs  中     更改指定key的權重來達到木頭的削皮

   public void Hit (int keyIndex, float damage) {
      float colliderHeight = 2.39705f ;  // 編輯器時碰撞體的size的y值
      //Skinned mesh renderer key's value is clamped between 0 & 100
      float newWeight = skinnedMeshRenderer.GetBlendShapeWeight (keyIndex) + damage * (100f / colliderHeight) ;
      skinnedMeshRenderer.SetBlendShapeWeight (keyIndex, newWeight) ;
   }

Knife.cs 中   削刀跟key碰撞體 碰撞就改變指定的key的權重

   private void OnCollisionExit (Collision collision) {
      woodFxEmission.enabled = false ;
   }

   private void OnCollisionStay (Collision collision) {
      Coll coll = collision.collider.GetComponent <Coll> () ;
      if (coll != null) {
         // hit Collider:
         woodFxEmission.enabled = true ;
         woodFx.transform.position = collision.contacts [ 0 ].point ;

         coll.HitCollider (hitDamage) ;
         wood.Hit (coll.index, hitDamage) ;
      }
   }

 

 

8、Wood Fx (Particle System)

這個就沒什麼可說的,特效一直都在,只是在碰撞的時候開啟particle system,同時改變特效的位置。脫離碰撞就關閉。

 

 

 

第二個應用:樹的出現動畫

image.png

test222.gif

 

image.png

新增一個cube:

image.png

然後新增水平跟垂直的邊緣迴圈。

image.png

 

然後增加  Shape Keys  : Base ,  key 1   把Cube 調整成樹的形狀。

 

image.png

編輯完  可以通過改變 Value 條來看效果,也有Misc引數可以調整。

就是從cube   key成這樣:

image.png

然後退出編輯模式,  為Cube 新增簡單的紋理

image.png

 

然後將檔案從Blender中匯出 .fbx檔案, 匯入到Unity中

託轉到場景中可是改變值看看效果:

image.png

image.png

新增如下控制指令碼 ,作為數目的出生動畫 :

image.png