一、.基本知识
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();
}
}
}
四、实现效果