using System; using LibMMD.Model; using LibMMD.Motion; using UnityEngine; namespace LibMMD.Unity3D.Animation { internal sealed class MmdMorphRenderer { private SkinnedMeshRenderer _mainRenderer; private SkinnedMeshRenderer[] _partRenderers; private int[] _mainBlendShapeIndexes; private int[][] _partBlendShapeIndexes; private float[] _weights; private float[] _appliedWeights; internal void Configure(MmdModel model, SkinnedMeshRenderer mainRenderer, SkinnedMeshRenderer[] partRenderers, int[] mainBlendShapeIndexes, int[][] partBlendShapeIndexes) { if (model == null) throw new ArgumentNullException(nameof(model)); _mainRenderer = mainRenderer; _partRenderers = partRenderers; _mainBlendShapeIndexes = mainBlendShapeIndexes; _partBlendShapeIndexes = partBlendShapeIndexes; _weights = new float[model.Morphs.Length]; _appliedWeights = new float[model.Morphs.Length]; } internal void Update(MmdModel model, MotionPlayer motionPlayer, double poseTime) { if (motionPlayer == null || model == null || _weights == null) return; motionPlayer.CalculateMorphWeights(model, poseTime, _weights); ApplyWeights(); } internal void Reset() { if (_weights == null) return; Array.Clear(_weights, 0, _weights.Length); ApplyWeights(); } private void ApplyWeights() { if (_mainRenderer != null) { ApplyWeightsToRenderer(_mainRenderer, _mainBlendShapeIndexes); } else if (_partRenderers != null) { for (var i = 0; i < _partRenderers.Length; ++i) ApplyWeightsToRenderer(_partRenderers[i], _partBlendShapeIndexes[i]); } Array.Copy(_weights, _appliedWeights, _weights.Length); } private void ApplyWeightsToRenderer(SkinnedMeshRenderer renderer, int[] morphToBlendShapeIndex) { for (var morphIndex = 0; morphIndex < morphToBlendShapeIndex.Length; ++morphIndex) { var blendShapeIndex = morphToBlendShapeIndex[morphIndex]; if (blendShapeIndex < 0) continue; var weight = _weights[morphIndex]; if (Mathf.Approximately(weight, _appliedWeights[morphIndex])) continue; renderer.SetBlendShapeWeight(blendShapeIndex, weight * 100f); } } } }