Created
April 9, 2018 23:44
-
-
Save kalineh/7ffa5c9c84ee498b898b068d43d17491 to your computer and use it in GitHub Desktop.
MeshCombinerNew.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
#if UNITY_EDITOR | |
using UnityEditor; | |
[InitializeOnLoad()] | |
class MeshCombinerHelperTag | |
{ | |
static MeshCombinerHelperTag() | |
{ | |
icon = EditorGUIUtility.ObjectContent(null, typeof(Mesh)).image; | |
EditorApplication.hierarchyWindowItemOnGUI -= OnHierarchyItem; | |
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyItem; | |
EditorApplication.RepaintHierarchyWindow(); | |
} | |
static Texture icon; | |
static void OnHierarchyItem(int instanceID, Rect instanceRect) | |
{ | |
var obj = EditorUtility.InstanceIDToObject(instanceID); | |
var gameObject = obj as GameObject; | |
if (!gameObject) | |
return; | |
var combiner = gameObject.GetComponent<MeshCombinerHelper>(); | |
if (!combiner) | |
return; | |
var width = 16; | |
var rightAlignedRect = new Rect( | |
instanceRect.xMax - width, | |
instanceRect.yMin, | |
width, | |
instanceRect.height + 1 | |
); | |
GUI.Label(rightAlignedRect, icon); | |
} | |
} | |
[CustomEditor(typeof(MeshCombinerHelper))] | |
[CanEditMultipleObjects()] | |
public class MeshCombinerHelperEditor | |
: Editor | |
{ | |
public override void OnInspectorGUI() | |
{ | |
base.OnInspectorGUI(); | |
if (GUILayout.Button("Save Combined Mesh")) | |
{ | |
foreach (var t in targets) | |
{ | |
Undo.RecordObject(t, "Combine Mesh"); | |
(t as MeshCombinerHelper).DoCombine(); | |
} | |
} | |
if (GUILayout.Button("Revert Mesh Combine (DANGER)")) | |
{ | |
foreach (var t in targets) | |
{ | |
Undo.RecordObject(t, "Revert Mesh Combine"); | |
(t as MeshCombinerHelper).DoUncombine(); | |
} | |
} | |
} | |
} | |
#endif | |
[DisallowMultipleComponent] | |
public class MeshCombinerHelper | |
: MonoBehaviour | |
{ | |
public bool autoCombineOnStart = false; | |
public bool autoLODPre = false; | |
public bool autoLODPost = false; | |
public bool autoStatic = true; | |
[Range(0.0f, 8.0f)] | |
public float autoLODPreWeight = 0.0f; | |
[Range(0.0f, 8.0f)] | |
public float autoLODPostWeight = 0.0f; | |
public bool overrideShadowCast = false; | |
public bool overrideShadowReceive = false; | |
public bool shadowCast = false; | |
public bool shadowReceive = false; | |
public void Start() | |
{ | |
// NOTE: disabling just in case something is going on | |
//if (autoCombineOnStart) | |
//DoCombine(); | |
} | |
public string GetGeneratedName(int index, Material mat) | |
{ | |
return string.Format("MeshCombine{0}.{1}.{2}", index, gameObject.name, mat.name); | |
} | |
public void DoCombine() | |
{ | |
var hadShadowReceivers = false; | |
var hadShadowCasters = false; | |
var meshFilters = GetComponentsInChildren<MeshFilter>(); | |
var perMaterialCombines = new Dictionary<Material, List<CombineInstance>>(); | |
var index = 0; | |
while (index < meshFilters.Length) | |
{ | |
var meshRenderer = meshFilters[index].gameObject.GetComponent<MeshRenderer>(); | |
var meshMaterial = meshRenderer.sharedMaterial; | |
if (!perMaterialCombines.ContainsKey(meshMaterial)) | |
perMaterialCombines.Add(meshMaterial, new List<CombineInstance>()); | |
var combines = perMaterialCombines[meshMaterial]; | |
var combine = new CombineInstance(); | |
combine.mesh = meshFilters[index].sharedMesh; | |
combine.transform = Matrix4x4.Inverse(transform.localToWorldMatrix) * meshFilters[index].transform.localToWorldMatrix; | |
combines.Add(combine); | |
meshFilters[index].gameObject.SetActive(false); | |
index++; | |
if (meshRenderer.shadowCastingMode == UnityEngine.Rendering.ShadowCastingMode.On) | |
hadShadowCasters = true; | |
if (meshRenderer.receiveShadows) | |
hadShadowReceivers = true; | |
} | |
if (overrideShadowCast) | |
hadShadowCasters = shadowCast; | |
if (overrideShadowReceive) | |
hadShadowReceivers = shadowReceive; | |
var count = 0; | |
foreach (var entry in perMaterialCombines) | |
{ | |
var obj = gameObject; | |
obj = new GameObject(GetGeneratedName(count, entry.Key)); | |
obj.transform.SetParent(transform); | |
obj.transform.ResetLocalTransforms(); | |
var combineInstancesRaw = entry.Value.ToArray(); | |
var combineInstancesProcessed = new CombineInstance[combineInstancesRaw.Length]; | |
for (int i = 0; i < combineInstancesRaw.Length; ++i) | |
{ | |
if (autoLODPre) | |
{ | |
combineInstancesProcessed[i] = new CombineInstance(); | |
combineInstancesProcessed[i].mesh = LODMaker.MakeLODMesh(combineInstancesRaw[i].mesh, autoLODPreWeight); | |
combineInstancesProcessed[i].subMeshIndex = combineInstancesRaw[i].subMeshIndex; | |
combineInstancesProcessed[i].transform = combineInstancesRaw[i].transform; | |
} | |
else | |
{ | |
combineInstancesProcessed[i] = combineInstancesRaw[i]; | |
} | |
} | |
if (autoLODPost) | |
{ | |
var lod0Mesh = new Mesh(); | |
lod0Mesh.CombineMeshes(combineInstancesRaw); | |
var lod1Mesh = LODMaker.MakeLODMesh(lod0Mesh, autoLODPostWeight); | |
lod0Mesh.RecalculateBounds(); | |
lod0Mesh.RecalculateNormals(); | |
lod1Mesh.RecalculateBounds(); | |
lod1Mesh.RecalculateNormals(); | |
var lod0obj = new GameObject(); | |
var lod1obj = new GameObject(); | |
lod0obj.transform.SetParent(obj.transform, false); | |
lod1obj.transform.SetParent(obj.transform, false); | |
var lod0MeshFilter = lod0obj.AddComponent<MeshFilter>(); | |
var lod1MeshFilter = lod1obj.AddComponent<MeshFilter>(); | |
var lod0MeshRenderer = lod0obj.AddComponent<MeshRenderer>(); | |
var lod1MeshRenderer = lod1obj.AddComponent<MeshRenderer>(); | |
lod0MeshRenderer.sharedMaterial = entry.Key; | |
lod1MeshRenderer.sharedMaterial = entry.Key; | |
lod0obj.name = "LOD0"; | |
lod1obj.name = "LOD1"; | |
lod0MeshFilter.mesh = lod0Mesh; | |
lod1MeshFilter.mesh = lod1Mesh; | |
var lodGroup = obj.AddComponent<LODGroup>(); | |
var lods = new LOD[] { | |
new LOD(), | |
new LOD(), | |
}; | |
lods[0].screenRelativeTransitionHeight = 0.7f; | |
lods[1].screenRelativeTransitionHeight = 0.02f; | |
lods[0].renderers = new Renderer[] { lod0MeshRenderer }; | |
lods[1].renderers = new Renderer[] { lod1MeshRenderer }; | |
lodGroup.SetLODs(lods); | |
lodGroup.RecalculateBounds(); | |
} | |
else | |
{ | |
var meshFilter = obj.AddComponent<MeshFilter>(); | |
var meshRenderer = obj.AddComponent<MeshRenderer>(); | |
meshRenderer.sharedMaterial = entry.Key; | |
meshFilter.sharedMesh = new Mesh(); | |
meshFilter.sharedMesh.CombineMeshes(combineInstancesProcessed); | |
meshFilter.sharedMesh.RecalculateBounds(); | |
meshFilter.sharedMesh.RecalculateNormals(); | |
meshRenderer.receiveShadows = hadShadowReceivers; | |
meshRenderer.shadowCastingMode = hadShadowCasters ? UnityEngine.Rendering.ShadowCastingMode.On : UnityEngine.Rendering.ShadowCastingMode.Off; | |
} | |
if (autoStatic) | |
obj.isStatic = true; | |
obj.SetActive(true); | |
count++; | |
} | |
} | |
private static List<Transform> eraseList; | |
public void DoUncombine() | |
{ | |
Debug.LogFormat("Undo Mesh Combine..."); | |
if (eraseList == null) | |
eraseList = new List<Transform>(); | |
eraseList.Clear(); | |
for (int i = 0; i < transform.childCount; ++i) | |
{ | |
var child = transform.GetChild(i); | |
if (child.name.Contains("MeshCombine")) | |
eraseList.Add(child); | |
} | |
foreach (var tfm in eraseList) | |
{ | |
Debug.LogFormat("> destroy combined child '{0}'", tfm.name); | |
tfm.SetParent(null); | |
DestroyImmediate(tfm.gameObject); | |
} | |
eraseList.Clear(); | |
var meshFilters = GetComponentsInChildren<MeshFilter>(true); | |
Debug.LogFormat("> found {0} meshFilters...", meshFilters.Length); | |
foreach (var mf in meshFilters) | |
{ | |
if (mf.gameObject.activeSelf == false) | |
{ | |
Debug.LogFormat("> * re-enable mesh filter child '{0}'", mf.name); | |
mf.gameObject.SetActive(true); | |
} | |
} | |
Debug.LogFormat("> destroying mesh filter / mesh renderer"); | |
DestroyImmediate(GetComponent<MeshFilter>()); | |
DestroyImmediate(GetComponent<MeshRenderer>()); | |
Debug.LogFormat("Undo Mesh Combine complete."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment