一.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();
}
unity3d中BlendShape融合
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();
}
}