废话:
通常顶点动画可以用ABC或者点缓存动画插件来做,但是本人在工作当中遇到了一个需求就是将一个球体平滑过度成一个平面,我尝试过ABC插件去做,的确可以做,效果很好但是,当我打包的时候发现,ABC插件不支持在安卓设备上运行,而 MegaFiers这个插件制作这个效果又非常复杂,所以想,😔唉~自己写一个吧!
1.效果
Unity在安卓设备上播放顶点动画
2.原理:
改变Mesh的顶点位置实现变形,基本表达式:vertex[n]=V3(v3 1,v3 2,lerp);(这是个表达式,不是实际的代码!)
3.实现步骤:
1.在三维建模软件中制作模型顶点动画,导出ABC文件;
2.在Unity中安装ABC插件,读取ABC文件;
3.制作顶点数据采集工具,保存ABC文件每个Time帧的顶点数据信息;
4.保存ABC模型的Mesh,为了保证UV和顶点数量等信息统一;
5.unity在pg包中导入jobs,编写代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Jobs;
using Unity.Jobs;
using System.IO;
using Unity.Burst;
using Unity.Collections;
public class VertexAnimation : MonoBehaviour
{
public MeshFilter filter;
public MeshFilter meshFilter;
public Vector3[] starVertices;
public Vector3[] endVertices;
[Range(0,1)]
public float lerp;
public bool open;
public string[] starpoinmt ;
public string[] endpoint;
private JobHandle jobHandle;
public void ReadData()
{
starpoinmt = File.ReadAllLines(Application.streamingAssetsPath + "/starVertices.txt");
endpoint = File.ReadAllLines(Application.streamingAssetsPath + "/endVertices.txt");
starVertices = new Vector3[meshFilter.mesh.vertices.Length];
endVertices = new Vector3[meshFilter.mesh.vertices.Length];
for (int i = 0; i < meshFilter.mesh.vertices.Length; i++)
{
starVertices[i] = StringToV3(starpoinmt[i]);
endVertices[i] = StringToV3(endpoint[i]);
}
}
private void Update()
{
if (lerp != 0 || lerp != 1)
{
DataJobUpdate();
}
#region
//if (Input.GetKeyDown(KeyCode.S))
//{
// starVertices = filter.meshFilter.vertices;
// string[] point = new string[starVertices.Length];
// for (int i = 0; i < starVertices.Length; i++)
// {
// point[i] = starVertices[i].x.ToString()+"&" + starVertices[i].y.ToString()+"&" + starVertices[i].z.ToString();
// }
// File.WriteAllLines(Application.streamingAssetsPath + "/starVertices.txt", point);
//}
//if (Input.GetKeyDown(KeyCode.E))
//{
// endVertices = filter.meshFilter.vertices;
// string[] point = new string[endVertices.Length];
// for (int i = 0; i < endVertices.Length; i++)
// {
// point[i] = endVertices[i].x.ToString() + "&" + endVertices[i].y.ToString() + "&" + endVertices[i].z.ToString();
// }
// File.WriteAllLines(Application.streamingAssetsPath + "/endVertices.txt", point);
//}
// DataUpdate();
//if (Input.GetKeyDown(KeyCode.Space))
//{
// Debug.Log(Application.streamingAssetsPath);
// AssetDatabase.CreateAsset(meshFilter.meshFilter, "Assets/" + name + ".asset");
// AssetDatabase.SaveAssets();
//}
#endregion
}
//public void DataUpdate()
//{
// if (open)
// {
// Vector3[] vertices = new Vector3[meshFilter.meshFilter.vertices.Length];
// for (int i = 0; i < meshFilter.meshFilter.vertices.Length; i++)
// {
// // vertices[i] = Vector3.Lerp(StringToV3(starpoinmt[i]), StringToV3(endpoint[i]), lerp);
// vertices[i] = Vector3.Lerp(starVertices[i], endVertices[i], lerp);
// }
// meshFilter.meshFilter.vertices = vertices;
// meshFilter.meshFilter.RecalculateBounds();
// meshFilter.meshFilter.RecalculateNormals();
// }
//}
meshFilterUpdateJobParallel jobParallel;
NativeArray<Vector3> ver;
NativeArray<Vector3> starVerticesNative;
NativeArray<Vector3> endVerticesNative;
public void DataJobUpdate()
{
if (open)
{
ver = new NativeArray<Vector3>(meshFilter.mesh.vertices, Allocator.TempJob);
starVerticesNative = new NativeArray<Vector3>(starVertices, Allocator.TempJob);
endVerticesNative = new NativeArray<Vector3>(endVertices, Allocator.TempJob);
jobParallel = new meshFilterUpdateJobParallel
{
vertices = ver,
starVertices = starVerticesNative,
endVertices = endVerticesNative,
lerp = lerp
};
jobHandle = jobParallel.Schedule(ver.Length, 64);
}
}
public Vector3 StringToV3(string v3s)
{
string[] v3p = v3s.Split("&");
return new Vector3(float.Parse(v3p[0]),float.Parse(v3p[1]),float.Parse(v3p[2]));
}
void LateUpdate()
{
jobHandle.Complete();
meshFilter.mesh.vertices = jobParallel.vertices.ToArray();
meshFilter.mesh.RecalculateBounds();
meshFilter.mesh.RecalculateNormals();
jobParallel.vertices.Dispose();
starVerticesNative.Dispose();
endVerticesNative.Dispose();
}
[BurstCompile]
struct meshFilterUpdateJobParallel : IJobParallelFor
{
public NativeArray<Vector3> vertices;
[ReadOnly] public NativeArray<Vector3> starVertices;
[ReadOnly] public NativeArray<Vector3> endVertices;
[ReadOnly] public float lerp;
public void Execute(int index)
{
vertices[index] = Vector3.Lerp(starVertices[index], endVertices[index], lerp);
}
}
}
如果各位大佬有新的思路和解决办法,欢迎留言!