KINDNICK_URP/Assets/External/VRM10/Editor/MeshUtility/Vrm10ExpressionUpdater.cs
2025-04-25 21:14:54 +09:00

120 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using UniGLTF.MeshUtility;
using UnityEditor;
using UnityEngine;
namespace UniVRM10
{
public class Vrm10ExpressionUpdater
{
// BlendShapeBinding.RelativePath からの逆引き
Dictionary<string, List<MeshIntegrationResult>> _rendererPathMap = new();
GameObject _root;
Vrm10ExpressionUpdater(GameObject root, List<MeshIntegrationResult> results)
{
_root = root;
foreach (var result in results)
{
foreach (var x in result.SourceSkinnedMeshRenderers)
{
var srcPath = x.transform.RelativePathFrom(root.transform);
if (_rendererPathMap.TryGetValue(srcPath, out var value))
{
value.Add(result);
}
else
{
value = new List<MeshIntegrationResult>();
value.Add(result);
_rendererPathMap.Add(srcPath, value);
}
}
}
}
// 分割されて増える => 増えない BlendShape のある方にいく
// 統合されて減る => 名前が同じものが統合される
IEnumerable<MorphTargetBinding> ReplaceBlendShapeBinding(IEnumerable<MorphTargetBinding> values)
{
var used = new HashSet<MorphTargetBinding>();
foreach (var val in values)
{
if (_rendererPathMap.TryGetValue(val.RelativePath, out var results))
{
foreach (var result in results)
{
if (result.Integrated == null)
{
continue;
}
var name = result.Integrated.Mesh.GetBlendShapeName(val.Index);
var newIndex = result.Integrated.Mesh.GetBlendShapeIndex(name);
if (newIndex == -1)
{
throw new KeyNotFoundException($"blendshape:{name} not found");
}
var dstPath = result.Integrated.IntegratedRenderer.transform.RelativePathFrom(_root.transform);
var binding = new MorphTargetBinding
{
RelativePath = dstPath,
Index = newIndex,
Weight = val.Weight,
};
if (used.Contains(binding))
{
Debug.LogWarning($"duplicated: {binding}");
}
else
{
if (VRMShaders.Symbols.VRM_DEVELOP)
{
Debug.Log($"{val} >> {binding}");
}
used.Add(binding);
yield return binding;
}
}
}
else
{
// skip
Debug.LogWarning($"SkinnedMeshRenderer not found: {val.RelativePath}");
}
}
}
public static Dictionary<VRM10Expression, VRM10Expression> Update(string assetFolder, GameObject instance,
List<MeshIntegrationResult> results)
{
var vrm = instance.GetComponent<Vrm10Instance>();
var util = new Vrm10ExpressionUpdater(instance, results);
// write Vrm10Expressions
var copyMap = new Dictionary<VRM10Expression, VRM10Expression>();
foreach (var (preset, clip) in vrm.Vrm.Expression.Clips)
{
var copy = ScriptableObject.Instantiate(clip);
copy.MorphTargetBindings = util.ReplaceBlendShapeBinding(clip.MorphTargetBindings).ToArray();
var assetPath = $"{assetFolder}/{copy.name}.asset";
AssetDatabase.CreateAsset(copy, assetPath);
copyMap.Add(clip, copy);
}
// write Vrm10Object
{
var copy = ScriptableObject.Instantiate<VRM10Object>(vrm.Vrm);
var assetPath = $"{assetFolder}/{copy.name}.asset";
copy.Expression.Replace(copyMap);
AssetDatabase.CreateAsset(copy, assetPath);
vrm.Vrm = copy;
}
return copyMap;
}
}
}