using System; using System.Collections; using System.Collections.Generic; using LibMMD.Model; using UnityEngine; namespace LibMMD.Unity3D { // Converts PMX vertex-type morphs into Unity BlendShape frames at load time, so morph // playback can drive SkinnedMeshRenderer.SetBlendShapeWeight instead of rewriting // Mesh.vertices every frame. Bone/UV/material morphs are untouched (handled elsewhere / // unimplemented, same as before this change). internal static class MorphBlendShapeBuilder { internal static IEnumerator BuildIncremental(Mesh mesh, MmdModel model, List vertexIndexList, MmdModelOptions options, Action completed) { var vertexCount = vertexIndexList?.Count ?? model.Vertices.Length; var globalToLocal = vertexIndexList != null ? BuildReverseMap(vertexIndexList) : null; var blendShapeIndex = new int[model.Morphs.Length]; Array.Fill(blendShapeIndex, -1); var deltaVertices = new Vector3[vertexCount]; var slice = new MmdLoadTimeSlicer(options); for (var morphIndex = 0; morphIndex < model.Morphs.Length; morphIndex++) { var morph = model.Morphs[morphIndex]; if (morph.Type != Morph.MorphType.MorphTypeVertex) continue; Array.Clear(deltaVertices, 0, deltaVertices.Length); var affectsThisMesh = false; foreach (var morphData in morph.MorphDatas) { var data = (Morph.VertexMorph)morphData; int localIndex; if (globalToLocal == null) localIndex = data.VertexIndex; else if (!globalToLocal.TryGetValue(data.VertexIndex, out localIndex)) continue; deltaVertices[localIndex] += data.Offset; affectsThisMesh = true; if (slice.ShouldYield()) yield return null; } if (!affectsThisMesh) continue; mesh.AddBlendShapeFrame(morph.Name, 100f, (Vector3[])deltaVertices.Clone(), null, null); blendShapeIndex[morphIndex] = mesh.blendShapeCount - 1; if (slice.ShouldYield()) yield return null; } completed(blendShapeIndex); } private static Dictionary BuildReverseMap(List vertexIndexList) { var map = new Dictionary(vertexIndexList.Count); for (var i = 0; i < vertexIndexList.Count; ++i) { map[vertexIndexList[i]] = i; } return map; } } }