#pragma warning disable 0414, 0649 using UnityEditor; using UnityEngine; using System.Linq; using System; using System.Collections.Generic; using UniGLTF.MeshUtility; using System.IO; namespace VRM { public class MeshIntegratorWizard : ScriptableWizard { [SerializeField] GameObject m_root; [Header("Validation")] [SerializeField] Material[] m_uniqueMaterials; [Serializable] struct MaterialKey { public string Shader; public KeyValuePair[] Properties; public override bool Equals(object obj) { if (!(obj is MaterialKey)) { return base.Equals(obj); } var key = (MaterialKey)obj; return Shader == key.Shader && Properties.SequenceEqual(key.Properties) ; } public override int GetHashCode() { return base.GetHashCode(); } } [Serializable] struct MaterialList { public Material[] Materials; public MaterialList(Material[] list) { Materials = list; } } [SerializeField] MaterialList[] m_duplicateMaterials; [Serializable] public class ExcludeItem { public Mesh Mesh; public bool Exclude; } [Header("Options")] [SerializeField] List m_excludes = new List(); [Header("Result")] [SerializeField] MeshMap[] integrationResults; public static void CreateWizard() { ScriptableWizard.DisplayWizard("MeshIntegratorWizard", "Integrate and close window", "Integrate"); } private void OnEnable() { m_root = Selection.activeGameObject; OnValidate(); } static object GetPropertyValue(Shader shader, int i, Material m) { var propType = ShaderUtil.GetPropertyType(shader, i); switch (propType) { case ShaderUtil.ShaderPropertyType.Color: return m.GetColor(ShaderUtil.GetPropertyName(shader, i)); case ShaderUtil.ShaderPropertyType.Range: case ShaderUtil.ShaderPropertyType.Float: return m.GetFloat(ShaderUtil.GetPropertyName(shader, i)); case ShaderUtil.ShaderPropertyType.Vector: return m.GetVector(ShaderUtil.GetPropertyName(shader, i)); case ShaderUtil.ShaderPropertyType.TexEnv: return m.GetTexture(ShaderUtil.GetPropertyName(shader, i)); default: throw new NotImplementedException(propType.ToString()); } } static MaterialKey GetMaterialKey(Material m) { var key = new MaterialKey { Shader = m.shader.name, }; key.Properties = Enumerable.Range(0, ShaderUtil.GetPropertyCount(m.shader)) .Select(x => new KeyValuePair( ShaderUtil.GetPropertyName(m.shader, x), GetPropertyValue(m.shader, x, m)) ) .OrderBy(x => x.Key) .ToArray() ; return key; } void OnValidate() { if (m_root == null || !PrefabUtility.IsPartOfAnyPrefab(m_root) || m_root.transform.parent != null) { Debug.LogWarning("Invalidate"); m_uniqueMaterials = new Material[] { }; m_duplicateMaterials = new MaterialList[] { }; m_excludes.Clear(); return; } Debug.Log("OnValidate"); m_uniqueMaterials = MeshIntegratorUtility.EnumerateSkinnedMeshRenderer(m_root.transform, false) .SelectMany(x => x.sharedMaterials) .Distinct() .ToArray(); m_duplicateMaterials = m_uniqueMaterials .GroupBy(x => GetMaterialKey(x), x => x) .Select(x => new MaterialList(x.ToArray())) .Where(x => x.Materials.Length > 1) .ToArray() ; var exclude_map = new Dictionary(); var excludes = new List(); foreach (var x in m_root.GetComponentsInChildren()) { var mesh = x.GetMesh(); if (mesh == null) { continue; } var item = new ExcludeItem { Mesh = mesh }; excludes.Add(item); exclude_map[mesh] = item; } foreach (var x in m_excludes) { if (exclude_map.TryGetValue(x.Mesh, out ExcludeItem item)) { // update item.Exclude = x.Exclude; } } m_excludes.Clear(); foreach (var kv in exclude_map) { m_excludes.Add(kv.Value); } } void OnWizardUpdate() { helpString = "select target mesh root"; } void Integrate() { if (m_root == null) { Debug.LogWarning("no root object"); return; } var prefabPath = AssetDatabase.GetAssetPath(m_root); var path = EditorUtility.SaveFilePanel("save prefab", Path.GetDirectoryName(prefabPath), m_root.name, "prefab"); if (string.IsNullOrEmpty(path)) { return; } var assetPath = UniGLTF.UnityPath.FromFullpath(path); if (!assetPath.IsUnderAssetsFolder) { Debug.LogWarning($"{path} is not asset path"); return; } var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); integrationResults = MeshIntegratorEditor.Integrate(m_root, assetPath, excludes).Select(x => x.MeshMap).ToArray(); } void OnWizardCreate() { Debug.Log("OnWizardCreate"); Integrate(); // close } void OnWizardOtherButton() { Debug.Log("OnWizardOtherButton"); Integrate(); } } }