《一起玩陶藝》的模型形變_簡單實現_基本原理解釋

一、.基本知識


  1.模型構成原理

  這部分知識爲方便部分人羣理解我從Unity中解釋。在Unity中的每一模型都有一個必要組件 < MeshFilter >,這個組件爲模型的顯示提供了基本數據。

一般包括了模型 所必需的:頂點、法線、UV座標...(更多自行搜索3D模型文件的構成信息)
    public sealed class MeshFilter : Component
    {
        //與下面的mesh信息相同,不同的是直接訪問的數據源爲你導入的模型數據
        public Mesh sharedMesh { get; set; }
        
        //可訪問已經在場景中實例化對象的模型(即網格)信息
        public Mesh mesh { get; set; }
    }

  好像或多或少的提到模型的渲染知識,我就稍微說一下拋開復雜的渲染流程,模型由基本的“點”來構成形體結構,而現代的3D模型存儲爲了節省空間,只將所有用的位置點記錄一次,而要將其轉化爲面片信息時則會,利用模型中存儲的頂點索引數據(記錄着每個面片用到的哪個頂點)。
  所以如果只是單純改變模型形狀就只需要對模型的頂點數據下手就行,尤其是像《一起玩陶藝》的那種只需同比拉伸的簡單形變那就相當簡單了。

二、實現策略

  模型數據中存儲的頂點數據是以模型原點爲中心的,其座標空間爲模型空間,當需要將模型變胖時就只需要將該模型的模型頂點值以乘以倍數就行,而我們需要的是變胖瘦時其高度不變,那麼就保持其Y/頂座標的數據不變即可。而要將其變高是則只需要單獨的將Y/頂座標的數據以乘以倍數。

所以在這裏將必要的形變數據分爲兩個部分:

a.模型頂點值在x&z方向的放大倍數,需要爲每個同z座標的頂點數據保存一份。這裏就用<AnimationCurve>來表示,下圖的x座標從左到右表示模型從底部到頂部的頂點的在x&y方向的放大倍數

b.模型形變的高度形變就只需一個浮點數來表示即可

如下實現直接看代碼,很簡單。

三、實現代碼

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading.Tasks;

public class VertexShape : MonoBehaviour
{

    public MeshFilter meshFilter;
    public AnimationCurve animationCurve;
    float max = float.MinValue, min = float.MaxValue,length;

    List<Vector3> vertexs = new List<Vector3>();
    List<Vector3> vertexs2 = new List<Vector3>();

    public enum Cood { X,Y,Z};
    public Cood cood = Cood.Y;
    public float height = 1;

    private void Start()
    {

        Mesh mesh = meshFilter.mesh;
        mesh.GetVertices(vertexs);

        switch (cood)
        {
            case Cood.X:
                break;
            case Cood.Y:
                for (int i = 0; i < vertexs.Count; i++)
                {
                    vertexs2.Add(vertexs[i]);
                    max = Mathf.Max(vertexs[i].y, max);
                    min = Mathf.Min(vertexs[i].y, min);
                }
                break;
            case Cood.Z:
                break;
        }
        length = max - min;
    }

    private void LateUpdate()
    {
        Change();
    }

    void Change() {

        Mesh mesh = meshFilter.mesh;
        switch (cood)
        {
            case Cood.X:
                break;
            case Cood.Y:
                for (int i = 0; i < vertexs.Count; i++)
                {
                    Vector3 temp = vertexs[i];
                    float y = temp.y;
                    temp.y = 0;
                    temp *= animationCurve.Evaluate((y - min ) / length);
                    temp.y = y * height + max * (height - 1);
                    vertexs2[i] = temp;
                }
                break;
            case Cood.Z:
                break;
        }
        mesh.SetVertices(vertexs2);
    }
    public void OnGUI()
    {
        if (GUI.Button(new Rect(50, 50, 100, 50), "Change")) {
            Change();
        }
    }

}

四、實現效果

 

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