MorphTargets

From Unify Community Wiki
Jump to: navigation, search

C# - MorphTargets.cs

Here's trypho's MorphTarget script from the Unity Forum in a C# version. It is far more versatile than the MeshMorpher script.

/**
 * Just a 20min port of trypho's JS script to C# by skahlert
 * In my experience the performance improved significantly (about 57x the speed of the JavaScript).
 * Have fun with it!!
 * 
 * If you find a nicer way of compensating the lack of dynamic arrays (line 84 and following) it would be nice to hear!
 * 
 */
 
 
using System;
using UnityEngine;
 
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
 
class MorphTargets : MonoBehaviour
{
    internal class BlendShapeVertex
    {
        public int originalIndex;
        public Vector3 position;
        public Vector3 normal;
    }
 
    internal class BlendShape
    {
        public BlendShapeVertex[] vertices;// = new Array();
    }
 
    public String[] attributes; //Names for the attributes to be morphed
    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()
    {
        for (int i = 0; i < attributeMeshes.Length; i++)
        {
            if (attributeMeshes[i] == null)
            {
                Debug.Log("Attribute " + i + " has not been assigned.");
                return;
            }
        }
 
        //Populate the working mesh
        MeshFilter filter = gameObject.GetComponent(typeof(MeshFilter)) as MeshFilter;
        filter.sharedMesh = sourceMesh;
        workingMesh = filter.mesh;
 
        //Check attribute meshes to be sure vertex count is the same.
        int vertexCount = sourceMesh.vertexCount;
        //Debug.Log("Vertex Count Source:"+vertexCount);
        for (int i = 0; i < attributeMeshes.Length; i++)
        {
            //Debug.Log("Vertex Mesh "+i+":"+attributeMeshes[i].vertexCount); 
            if (attributeMeshes[i].vertexCount != vertexCount)
            {
 
                Debug.Log("Mesh " + i + " doesn't have the same number of vertices as the first mesh");
                return;
            }
        }
 
        //Build blend shapes
        BuildBlendShapes();
    }
 
    void BuildBlendShapes()
    {
 
        blendShapes = new BlendShape[attributes.Length];
 
        //For each attribute figure out which vertices are affected, then store their info in the blend shape object.
        for (int i = 0; i < attributes.Length; i++)
        {
            //Populate blendShapes array with new blend shapes
            blendShapes[i] = new BlendShape();
 
            /** TODO: Make this a little more stylish!
             *  UGLY hack to compensate the lack of dynamic arrays in C#. Feel free to improve!
             */
            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 the vertex is affected, populate a blend shape vertex with that info
                if (workingMesh.vertices[j] != attributeMeshes[i].vertices[j])
                {
                    //Create a blend shape vertex and populate its data.
 
                    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];
 
                    //Add new blend shape vertex to blendShape object.
                    blendShapes[i].vertices[blendShapeCounter]=blendShapeVertex;
                    blendShapeCounter++;
                }
            }
 
            //Convert blendShapes.vertices to builtin array
            //blendShapes[i].vertices = blendShapes[i].vertices.ToBuiltin(BlendShapeVertex);
        }
    }
 
 
    public void SetMorph()
    {
 
        //Set up working data to store mesh offset information.
        Vector3[] morphedVertices = sourceMesh.vertices;
        Vector3[] morphedNormals = sourceMesh.normals;
 
        //For each attribute...
        for (int j = 0; j < attributes.Length; j++)
        {
            //If the weight of this attribute isn't 0	
            if (!Mathf.Approximately(attributeProgress[j], 0))
            {
                //For each vertex in this attribute's blend shape...
                for (int i = 0; i < blendShapes[j].vertices.Length; i++)
                {
                    //...adjust the mesh according to the offset value and weight
                    morphedVertices[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].position * attributeProgress[j];
                    //Adjust normals as well
                    morphedNormals[blendShapes[j].vertices[i].originalIndex] += blendShapes[j].vertices[i].normal * attributeProgress[j];
                }
            }
        }
 
        //Update the actual mesh with new vertex and normal information, then recalculate the mesh bounds.		
        workingMesh.vertices = morphedVertices;
        workingMesh.normals = morphedNormals;
        workingMesh.RecalculateBounds();
    }
 
 
 
}
Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox