unity3d中的BlendShape混合动画

一.unity3d中加载模型时,网格顶点发生变化的解决办法。

unity3d中mesh网格为三角网格,目前unity3d直接导入模型时,会使得模型的顶定点数发生改变。解决的办法:在project中点击已经加载的模型,在Import Setting中将Normals设为None,点击Apply。然后再将Normals设为Import,重新加载,再点击Apply。

unity3d中的BlendShape混合动画_第1张图片

二.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();
    }
}




你可能感兴趣的:(unity3d,mesh,混合动画)