/******************************************************************************/ /* Project - MudBun Publisher - Long Bunny Labs http://LongBunnyLabs.com Author - Ming-Lun "Allen" Chou http://AllenChou.net */ /******************************************************************************/ using System.Linq; using UnityEditor; using UnityEngine; namespace MudBun { [CustomEditor(typeof(MudRenderer), true)] [CanEditMultipleObjects] public class MudRendererEditor : MudRendererBaseEditor { protected override void LockMesh() { base.LockMesh(); foreach (var renderer in targets.Select(x => (MudRenderer) x)) { if (renderer == null) continue; if (renderer.MeshLocked) continue; DoLockMesh(renderer.transform, renderer.RecursiveLockMeshByEditor); } } private void DoLockMesh(Transform t, bool recursive, int depth = 0) { if (t == null) return; if (recursive) { for (int i = 0; i < t.childCount; ++i) DoLockMesh(t.GetChild(i), recursive, depth + 1); } var renderer = t.GetComponent(); if (renderer == null || !renderer.isActiveAndEnabled) return; bool createNewObject = MeshGenerationCreateNewObject.boolValue; bool autoRigging = MeshGenerationAutoRigging.boolValue; bool generateCollider = MeshGenerationCreateCollider.boolValue; bool generateColliderMeshAsset = GenerateColliderMeshAssetByEditor.boolValue; bool generateMeshAsset = GenerateMeshAssetByEditor.boolValue; var prevMeshGenerationRenderableMeshMode = renderer.MeshGenerationRenderableMeshMode; if (createNewObject) renderer.MeshGenerationRenderableMeshMode = MudRendererBase.RenderableMeshMode.MeshRenderer; renderer.MarkNeedsCompute(); bool optimizeMeshForRendering = !GenerateMeshAssetByEditor.boolValue; // generated mesh assets are automatically optimized by the import pipeline renderer.LockMesh(autoRigging, false, null, MeshGenerationGenerateTextureUV.boolValue, MeshGenerationGenerateLightMapUV.boolValue, MeshGenerationWeldVertices.boolValue, optimizeMeshForRendering); if (createNewObject) renderer.MeshGenerationRenderableMeshMode = prevMeshGenerationRenderableMeshMode; // finish all access to serialized properties before they get disposed upon asset database refresh if (generateCollider) { var colliderMesh = renderer.AddCollider(renderer.gameObject, false, null, MeshGenerationForceConvexCollider.boolValue, MeshGenerationCreateRigidBody.boolValue); if (colliderMesh != null && generateColliderMeshAsset) { renderer.ValidateAssetNames(); string rootFolder = "Assets"; string assetsFolder = "MudBun Generated Assets"; string folderPath = $"{rootFolder}/{assetsFolder}"; string assetName = renderer.GenerateColliderMeshAssetByEditorName; if (!AssetDatabase.IsValidFolder(folderPath)) AssetDatabase.CreateFolder(rootFolder, assetsFolder); string meshAssetPath = $"{folderPath}/{assetName}.mesh"; AssetDatabase.CreateAsset(colliderMesh, meshAssetPath); AssetDatabase.Refresh(); Debug.Log($"MudBun: Saved collider mesh asset - \"{folderPath}/{assetName}.mesh\""); } } if (generateMeshAsset) { renderer.ValidateAssetNames(); string rootFolder = "Assets"; string assetsFolder = "MudBun Generated Assets"; string folderPath = $"{rootFolder}/{assetsFolder}"; string assetName = renderer.GenerateMeshAssetByEditorName; if (!AssetDatabase.IsValidFolder(folderPath)) AssetDatabase.CreateFolder(rootFolder, assetsFolder); Mesh mesh = null; Material mat = null; var meshFilter = renderer.GetComponent(); var meshRenderer = renderer.GetComponent(); var skinnedMeshRenderer = renderer.GetComponent(); if (meshRenderer != null) { if (meshFilter != null) { mesh = meshFilter.sharedMesh; } mat = meshRenderer.sharedMaterial; } else if (skinnedMeshRenderer != null) { mesh = skinnedMeshRenderer.sharedMesh; mat = skinnedMeshRenderer.sharedMaterial; } if (mesh != null) { string meshAssetPath = $"{folderPath}/{assetName}.mesh"; AssetDatabase.CreateAsset(mesh, meshAssetPath); AssetDatabase.Refresh(); Debug.Log($"MudBun: Saved mesh asset - \"{folderPath}/{assetName}.mesh\""); // somehow serialized properties get invalidated after asset database operations InitSerializedProperties(); var savedMesh = AssetDatabase.LoadAssetAtPath(meshAssetPath); if (savedMesh != null) { if (meshFilter != null) meshFilter.sharedMesh = savedMesh; } } if (mat != null) { if (meshRenderer != null) meshRenderer.sharedMaterial = mat; else if (skinnedMeshRenderer != null) skinnedMeshRenderer.sharedMaterial = mat; } } if (depth == 0 && createNewObject) { var clone = Instantiate(renderer.gameObject); clone.name = renderer.name + " (Locked Mesh Clone)"; if (autoRigging) { var cloneRenderer = clone.GetComponent(); cloneRenderer.RescanBrushesImmediate(); cloneRenderer.DestroyAllBrushesImmediate(); } else { DestroyAllChildren(clone.transform); } Undo.RegisterCreatedObjectUndo(clone, clone.name); DestroyImmediate(clone.GetComponent()); Selection.activeObject = clone; renderer.UnlockMesh(); } } protected override void GenerateSdf() { var renderer = (MudRendererBase)target; if (renderer == null) return; renderer.ValidateAssetNames(); string rootFolder = "Assets"; string assetsFolder = "MudBun Generated Assets"; string folderPath = $"{rootFolder}/{assetsFolder}"; string assetName = renderer.GenerateSdfByEditorName; if (!AssetDatabase.IsValidFolder(folderPath)) AssetDatabase.CreateFolder(rootFolder, assetsFolder); Vector3Int size = GenerateSdfTextureSize.vector3IntValue; var sdf = new Texture3D(size.x, size.y, size.z, TextureFormat.RFloat, false); renderer.GenerateSdf(sdf, GenerateSdfCenter.vector3Value, GenerateSdfDimension.vector3Value); string sdfAssetPath = $"{folderPath}/{assetName}.asset"; AssetDatabase.CreateAsset(sdf, sdfAssetPath); AssetDatabase.Refresh(); renderer.MarkNeedsCompute(); Debug.Log($"MudBun: Saved SDF texture - \"{folderPath}/{assetName}.asset\""); } } }