/// <summary> /// Hook up the BlendShape data /// </summary> /// <param name="go"> /// A <see cref="GameObject"/> /// </param> public virtual void OnPostprocessModel(GameObject go) { // early out if no blend shape data were found if (baseShapePairs.Count < 1) { return; } // process each blend shape data object foreach (GameObject indexMap in baseShapePairs.Keys) { // grab the container for the new BlendShape component from the HashTable Transform blendContainer = TransformHelpers.GetTransformInHierarchy(go.transform, baseShapePairs[indexMap] as string); // if no match is found, try to find a skin with the mesh Component[] skins = go.GetComponentsInChildren <SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer skin in skins) { if (skin.sharedMesh.name == baseShapePairs[indexMap] as string) { blendContainer = skin.transform; } } // if no match was found, then assume it is the root if (blendContainer == null || blendContainer.GetComponent <Renderer>() == null) { blendContainer = go.transform; } // add the blendShape component if it does not yet exist BlendShape blendShapeNode = blendContainer.gameObject.AddComponent <BlendShape>(); blendShapeNode.meshRenderer = blendShapeNode.GetComponent <Renderer>(); // grab the base mesh to map target indices and the ArrayList of target models Mesh taggedBaseMesh = indexMap.GetComponent <MeshFilter>().sharedMesh; ArrayList targetModels = targetMeshes[indexMap.name] as ArrayList; // grab the seamless base mesh GameObject seamlessBaseModel = seamlessShapePairs[indexMap.name] as GameObject; blendShapeNode.seamlessBaseMesh = seamlessBaseModel.GetComponent <MeshFilter>().sharedMesh; // create the index map between the seamless base mesh and the actual base mesh Mesh outMesh; if (blendShapeNode.GetComponent <MeshFilter>() == null) { outMesh = blendShapeNode.GetComponent <SkinnedMeshRenderer>().sharedMesh; } else { outMesh = blendShapeNode.GetComponent <MeshFilter>().sharedMesh; } blendShapeNode.indexMap = new int[outMesh.vertexCount]; for (int i = 0; i < taggedBaseMesh.colors.Length; i++) { // point indices on the seamless mesh should be identical to tag values blendShapeNode.indexMap[i] = ColorToTag(taggedBaseMesh.colors[i]); } // create BlendShapeTargets from the target models blendShapeNode.targets = new BlendShape.Target[targetModels.Count]; for (int i = 0; i < targetModels.Count; i++) { // create the new BlendShapeTarget GameObject targetModel = targetModels[i] as GameObject; Mesh targetMesh = targetModel.GetComponent <MeshFilter>().sharedMesh; BlendShape.Target target = new BlendShape.Target(); target.name = targetMesh.name.Substring(targetMesh.name.LastIndexOf("__blendShapeTarget__") + 20); // store the indices and deltaPosition values for the target ArrayList vertices = new ArrayList(); ArrayList deltaPos = new ArrayList(); for (int j = 0; j < targetMesh.vertexCount; j++) { int tag = ColorToTag(targetMesh.colors[j]); Vector3 compareTo = blendShapeNode.seamlessBaseMesh.vertices[tag]; // simply use tag since it should be identical to point index on seamless mesh // early out if the threshold test is not satisfied if ((targetMesh.vertices[j] - compareTo).sqrMagnitude < sqrMagThreshold) { continue; } vertices.Add(tag); deltaPos.Add(targetMesh.vertices[j] - compareTo); } target.vertices = new int[vertices.Count]; for (int j = 0; j < target.vertices.Length; j++) { target.vertices[j] = (int)vertices[j]; } target.deltaPositions = new Vector3[deltaPos.Count]; for (int j = 0; j < target.deltaPositions.Length; j++) { target.deltaPositions[j] = (Vector3)deltaPos[j]; } // copy the target to the BlendShape component blendShapeNode.targets[i] = target; // remove the target's assets GameObject.DestroyImmediate(targetMesh, true); GameObject.DestroyImmediate(targetModel, true); } // remove the tagged base mesh assets GameObject.DestroyImmediate(taggedBaseMesh, true); GameObject.DestroyImmediate(indexMap, true); // remove the seamless base mesh GameObject GameObject.DestroyImmediate(seamlessBaseModel, true); } }