一.unity3d中加载模型时,网格顶点发生变化的解决办法。
unity3d中mesh网格为三角网格,目前unity3d直接导入模型时,会使得模型的顶定点数发生改变。解决的办法:在project中点击已经加载的模型,在Import Setting中将Normals设为None,点击Apply。然后再将Normals设为Import,重新加载,再点击Apply。
二.unity3d中BlendShape混合动画编程
主要参考了http://forum.unity3d.com/threads/15424-Morph-Target-Script。
在unity3d中使用Mesh.vertices获得顶点位置,使用Mesh.normal获得顶点法线。当BS模型的权重时,需要重新计算Mesh.vertices和Mesh.normal,再使用RecalculateBounds重新计算BS模型边界。
定义BS类,记录每个BS模型的顶点位置,顶点法线
internal class BlendShapeVertex { public int originalIndex; public Vector3 position; public Vector3 normal; } internal class BlendShape { public BlendShapeVertex[] vertices;// = new Array(); }
其中定义originalIndex是为了记录某个顶点的索引值。因为在BS模型中,很多顶点位置都与对应的基础表情顶点位置一致,所以在重新计算新的混合表情时,就不需要再计算这些点,提高运算速率。
建立BS模型数据
void BuildBlendShapes() { blendShapes = new BlendShape[attributeMeshes.Length]; for (int i = 0; i < attributeMeshes.Length; i++) { blendShapes[i] = new BlendShape(); int blendShapeCounter = 0; for (int j = 0; j < workingMesh.vertexCount; j++) { if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j]) { blendShapeCounter++; } } blendShapes[i].vertices = new BlendShapeVertex[blendShapeCounter]; blendShapeCounter = 0; for (int j = 0; j < workingMesh.vertexCount; j++) { if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j]) { BlendShapeVertex blendShapeVertex = new BlendShapeVertex(); blendShapeVertex.originalIndex = j; blendShapeVertex.position = attributeMeshes[i].vertices[j] - workingMesh.vertices[j]; blendShapeVertex.normal = attributeMeshes[i].normals[j] - workingMesh.normals[j]; blendShapes[i].vertices[blendShapeCounter]=blendShapeVertex; blendShapeCounter++; } } } }
BS融合
public void SetMorph() { Vector3[] morphedVertices = sourceMesh.vertices; Vector3[] morphedNormals = sourceMesh.normals; for (int j = 0; j < attributeMeshes.Length; j++) { if (!Mathf.Approximately(attributeProgress[j], 0)) { for (int i = 0; i < blendShapes[j].vertices.Length; i++) { int a = blendShapes[j].vertices[i].originalIndex; if(a!=i) { int aa = 0; } morphedVertices[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].position * attributeProgress[j]; morphedNormals[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].normal * attributeProgress[j]; } } } workingMesh.vertices = morphedVertices; workingMesh.normals = morphedNormals; workingMesh.RecalculateBounds(); }
using UnityEngine; using System.Collections; public class MorphTargets : MonoBehaviour { internal class BlendShapeVertex { public int originalIndex; public Vector3 position; public Vector3 normal; } internal class BlendShape { public BlendShapeVertex[] vertices; } public Mesh sourceMesh; //The original mesh public Mesh[] attributeMeshes; //The destination meshes for each attribute. public float[] attributeProgress; private BlendShape[] blendShapes; private Mesh workingMesh; void Awake() { attributeProgress = new float[attributeMeshes.Length]; for (int i = 0; i < attributeMeshes.Length; i++) { if (attributeMeshes[i] == null) { Debug.Log("Attribute " + i + " has not been assigned."); return; } } MeshFilter filter = gameObject.GetComponent(typeof(MeshFilter)) as MeshFilter; filter.sharedMesh = sourceMesh; workingMesh = filter.mesh; int vertexCount = sourceMesh.vertexCount; for (int i = 0; i < attributeMeshes.Length; i++) { if (attributeMeshes[i].vertexCount != vertexCount) { Debug.Log("Mesh " + i + " doesn't have the same number of vertices as the first mesh"); return; } } BuildBlendShapes(); } void BuildBlendShapes() { blendShapes = new BlendShape[attributeMeshes.Length]; for (int i = 0; i < attributeMeshes.Length; i++) { blendShapes[i] = new BlendShape(); int blendShapeCounter = 0; for (int j = 0; j < workingMesh.vertexCount; j++) { if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j]) { blendShapeCounter++; } } blendShapes[i].vertices = new BlendShapeVertex[blendShapeCounter]; blendShapeCounter = 0; for (int j = 0; j < workingMesh.vertexCount; j++) { if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j]) { BlendShapeVertex blendShapeVertex = new BlendShapeVertex(); blendShapeVertex.originalIndex = j; blendShapeVertex.position = attributeMeshes[i].vertices[j] - workingMesh.vertices[j]; blendShapeVertex.normal = attributeMeshes[i].normals[j] - workingMesh.normals[j]; blendShapes[i].vertices[blendShapeCounter]=blendShapeVertex; blendShapeCounter++; } } } } public void SetMorph() { Vector3[] morphedVertices = sourceMesh.vertices; Vector3[] morphedNormals = sourceMesh.normals; for (int j = 0; j < attributeMeshes.Length; j++) { if (!Mathf.Approximately(attributeProgress[j], 0)) { for (int i = 0; i < blendShapes[j].vertices.Length; i++) { int a = blendShapes[j].vertices[i].originalIndex; if(a!=i) { int aa = 0; } morphedVertices[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].position * attributeProgress[j]; morphedNormals[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].normal * attributeProgress[j]; } } } workingMesh.vertices = morphedVertices; workingMesh.normals = morphedNormals; workingMesh.RecalculateBounds(); } }