using System.Linq; using UnityEngine; using System; using System.Collections.Generic; namespace UniVRM10 { [Serializable] public sealed class PreviewMeshItem { public string Path { get; private set; } public SkinnedMeshRenderer SkinnedMeshRenderer { get; private set; } public Mesh Mesh { get; private set; } public string[] BlendShapeNames { get; private set; } public int BlendShapeCount { get { return BlendShapeNames.Length; } } public Material[] Materials { get; private set; } Transform m_transform; public Vector3 Position { get { return m_transform.position; } } public Quaternion Rotation { get { return m_transform.rotation; } } PreviewMeshItem(string path, Transform transform, Material[] materials) { Path = path; m_transform = transform; Materials = materials; } public void Bake(IEnumerable values, float weight) { if (SkinnedMeshRenderer == null) return; // Update baked mesh if (values != null) { // clear for (int i = 0; i < BlendShapeCount; ++i) { SkinnedMeshRenderer.SetBlendShapeWeight(i, 0); } foreach (var x in values) { if (x.RelativePath == Path) { if (x.Index >= 0 && x.Index < SkinnedMeshRenderer.sharedMesh.blendShapeCount) { SkinnedMeshRenderer.SetBlendShapeWeight(x.Index, x.Weight * weight * MorphTargetBinding.VRM_TO_UNITY); } else { Debug.LogWarningFormat("Out of range {0}: 0 <= {1} < {2}", SkinnedMeshRenderer.name, x.Index, SkinnedMeshRenderer.sharedMesh.blendShapeCount); } } } } SkinnedMeshRenderer.BakeMesh(Mesh); } public static PreviewMeshItem Create(Transform t, Transform root, Func getOrCreateMaterial) { //Debug.Log("create"); var meshFilter = t.GetComponent(); var meshRenderer = t.GetComponent(); var skinnedMeshRenderer = t.GetComponent(); if (meshFilter != null && meshRenderer != null) { // copy meshRenderer.sharedMaterials = meshRenderer.sharedMaterials.Select(x => getOrCreateMaterial(x)).ToArray(); return new PreviewMeshItem(t.RelativePathFrom(root), t, meshRenderer.sharedMaterials) { Mesh = meshFilter.sharedMesh }; } else if (skinnedMeshRenderer != null) { // copy skinnedMeshRenderer.sharedMaterials = skinnedMeshRenderer.sharedMaterials.Select(x => getOrCreateMaterial(x)).ToArray(); if (skinnedMeshRenderer.sharedMesh.blendShapeCount > 0) { // bake required var sharedMesh = skinnedMeshRenderer.sharedMesh; return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials) { SkinnedMeshRenderer = skinnedMeshRenderer, Mesh = new Mesh(), // for bake BlendShapeNames = Enumerable.Range(0, sharedMesh.blendShapeCount).Select(x => sharedMesh.GetBlendShapeName(x)).ToArray() }; } else { return new PreviewMeshItem(t.RelativePathFrom(root), t, skinnedMeshRenderer.sharedMaterials) { Mesh = skinnedMeshRenderer.sharedMesh, }; } } else { return null; } } } }