public static List <MeshUtility.MeshIntegrationResult> Integrate(GameObject prefab) { Undo.RecordObject(prefab, "Mesh Integration"); var instance = SkinnedMeshUtility.InstantiatePrefab(prefab); var clips = new List <BlendShapeClip>(); var proxy = instance.GetComponent <VRMBlendShapeProxy>(); if (proxy != null && proxy.BlendShapeAvatar != null) { clips = proxy.BlendShapeAvatar.Clips; } foreach (var clip in clips) { Undo.RecordObject(clip, "Mesh Integration"); } // Backup Exists BackupVrmPrefab(prefab); // Execute var results = VRMMeshIntegratorUtility.Integrate(instance, clips); foreach (var res in results) { if (res.IntegratedRenderer == null) { continue; } SaveMeshAsset(res.IntegratedRenderer.sharedMesh, instance, res.IntegratedRenderer.gameObject.name); Undo.RegisterCreatedObjectUndo(res.IntegratedRenderer.gameObject, "Integrate Renderers"); } // destroy source renderers foreach (var res in results) { foreach (var renderer in res.SourceSkinnedMeshRenderers) { Undo.RecordObject(renderer.gameObject, "Deactivate old renderer"); renderer.gameObject.SetActive(false); } foreach (var renderer in res.SourceMeshRenderers) { Undo.RecordObject(renderer.gameObject, "Deactivate old renderer"); renderer.gameObject.SetActive(false); } } // Apply to Prefab SkinnedMeshUtility.ApplyChangesToPrefab(instance); Object.DestroyImmediate(instance); return(results); }
/// 2022.05 仕様変更 /// /// * prefab 専用 /// * backup するのではなく 変更した copy を作成する。元は変えない /// * copy 先の統合前の renderer を disable で残さず destroy する /// * 実行すると mesh, blendshape, blendShape を新規に作成する /// * 新しいヒエラルキーを prefab に保存してから削除して終了する /// void Integrate() { if (m_root.GetGameObjectType() != GameObjectType.AssetPrefab) { throw new Exception("for prefab only"); } String folder = "Assets"; var prefab = m_root.GetPrefab(); if (prefab != null) { folder = AssetDatabase.GetAssetPath(prefab); Debug.Log(folder); } // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "VrmIntegrated"); var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); if (!unityPath.IsUnderAssetsFolder) { EditorUtility.DisplayDialog("asset folder", "Target folder must be in the `Assets` folder", "cancel"); return; } assetFolder = unityPath.Value; var copy = GameObject.Instantiate(m_root); // 統合 var excludes = m_excludes.Where(x => x.Exclude).Select(x => x.Mesh); var results = Integrate(copy, excludes, m_separateByBlendShape); // write mesh asset foreach (var result in results) { var childAssetPath = $"{assetFolder}/{result.IntegratedRenderer.gameObject.name}{ASSET_SUFFIX}"; Debug.LogFormat("CreateAsset: {0}", childAssetPath); AssetDatabase.CreateAsset(result.IntegratedRenderer.sharedMesh, childAssetPath); } // 統合した結果をヒエラルキーに追加する foreach (var result in results) { if (result.IntegratedRenderer != null) { result.IntegratedRenderer.transform.SetParent(copy.transform, false); } } // 統合した結果を反映した BlendShapeClip を作成して置き換える var clips = VRMMeshIntegratorUtility.FollowBlendshapeRendererChange(results, copy, assetFolder); // 用が済んだ 統合前 の renderer を削除する foreach (var result in results) { foreach (var renderer in result.SourceMeshRenderers) { GameObject.DestroyImmediate(renderer); } foreach (var renderer in result.SourceSkinnedMeshRenderers) { GameObject.DestroyImmediate(renderer); } } // reset firstperson var firstperson = copy.GetComponent <VRMFirstPerson>(); if (firstperson != null) { firstperson.Reset(); } // prefab var prefabPath = $"{assetFolder}/VrmIntegrated.prefab"; Debug.Log(prefabPath); PrefabUtility.SaveAsPrefabAsset(copy, prefabPath, out bool success); if (!success) { throw new System.Exception($"PrefabUtility.SaveAsPrefabAsset: {prefabPath}"); } // destroy scene UnityEngine.Object.DestroyImmediate(copy); var prefabReference = AssetDatabase.LoadAssetAtPath <GameObject>(prefabPath); foreach (var clip in clips) { var so = new SerializedObject(clip); so.Update(); // clip.Prefab = copy; var prop = so.FindProperty("m_prefab"); prop.objectReferenceValue = prefabReference; so.ApplyModifiedProperties(); } }