internal static LODData GetLODData(string assetPath) { var lodData = AssetDatabase.LoadAssetAtPath <LODData>(GetLODDataPath(assetPath)); if (!lodData) { lodData = ScriptableObject.CreateInstance <LODData>(); } var overrideDefaults = lodData.overrideDefaults; var importSettings = lodData.importSettings; if (importSettings == null) { importSettings = new LODImportSettings(); lodData.importSettings = importSettings; } if (!overrideDefaults) { importSettings.generateOnImport = enabled; importSettings.meshSimplifier = meshSimplifierType.AssemblyQualifiedName; importSettings.maxLODGenerated = maxLOD; importSettings.initialLODMaxPolyCount = initialLODMaxPolyCount; } return(lodData); }
void OnPostprocessModel(GameObject go) { if (enabled && !go.GetComponentInChildren <LODGroup>() && meshSimplifierType != null) { if (go.GetComponentsInChildren <SkinnedMeshRenderer>().Any()) { Debug.Log("Automatic LOD generation on does not currently support skinned meshes on import"); return; } var originalMeshFilters = go.GetComponentsInChildren <MeshFilter>(); uint polyCount = 0; foreach (var mf in originalMeshFilters) { var m = mf.sharedMesh; for (int i = 0; i < m.subMeshCount; i++) { var topology = m.GetTopology(i); var indexCount = m.GetIndexCount(i); switch (topology) { case MeshTopology.Quads: indexCount /= 4; break; case MeshTopology.Triangles: indexCount /= 3; break; case MeshTopology.Lines: case MeshTopology.LineStrip: indexCount /= 2; break; } polyCount += indexCount; } } var meshLODs = new List <MeshLOD>(); var preprocessMeshes = new HashSet <int>(); var lodData = AssetDatabase.LoadAssetAtPath <LODData>(GetLODDataPath(assetPath)); if (!lodData) { lodData = ScriptableObject.CreateInstance <LODData>(); } var overrideDefaults = lodData.overrideDefaults; var importSettings = lodData.importSettings; if (importSettings == null) { importSettings = new LODImportSettings(); lodData.importSettings = importSettings; } if (!overrideDefaults) { importSettings.generateOnImport = true; importSettings.meshSimplifier = meshSimplifierType.AssemblyQualifiedName; importSettings.maxLODGenerated = maxLOD; importSettings.initialLODMaxPolyCount = initialLODMaxPolyCount; } if (importSettings.generateOnImport && importSettings.maxLODGenerated == 0 && polyCount <= importSettings.initialLODMaxPolyCount) { return; } if (!overrideDefaults || importSettings.generateOnImport) { if (polyCount > importSettings.initialLODMaxPolyCount) { foreach (var mf in originalMeshFilters) { var inputMesh = mf.sharedMesh; var outputMesh = new Mesh(); outputMesh.name = inputMesh.name; outputMesh.bounds = inputMesh.bounds; mf.sharedMesh = outputMesh; var meshLOD = new MeshLOD(); meshLOD.inputMesh = inputMesh; meshLOD.outputMesh = outputMesh; meshLOD.quality = (float)importSettings.initialLODMaxPolyCount / (float)polyCount; meshLODs.Add(meshLOD); preprocessMeshes.Add(outputMesh.GetInstanceID()); } } // Clear out previous LOD data in case the number of LODs has been reduced for (int i = 0; i <= LODData.MaxLOD; i++) { lodData[i] = null; } lodData[0] = originalMeshFilters.Select(mf => mf.GetComponent <Renderer>()).ToArray(); for (int i = 1; i <= importSettings.maxLODGenerated; i++) { var lodMeshes = new List <Renderer>(); foreach (var mf in originalMeshFilters) { var inputMesh = mf.sharedMesh; var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(mf.name, k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform; lodTransform.parent = mf.transform; lodTransform.localPosition = Vector3.zero; var lodMF = lodTransform.GetComponent <MeshFilter>(); var lodRenderer = lodTransform.GetComponent <MeshRenderer>(); AppendLODNameToRenderer(lodRenderer, i); var outputMesh = new Mesh(); outputMesh.name = string.Format("{0} LOD{1}", inputMesh.name, i); outputMesh.bounds = inputMesh.bounds; lodMF.sharedMesh = outputMesh; lodMeshes.Add(lodRenderer); EditorUtility.CopySerialized(mf.GetComponent <MeshRenderer>(), lodRenderer); var meshLOD = new MeshLOD(); meshLOD.inputMesh = inputMesh; meshLOD.outputMesh = outputMesh; meshLOD.quality = Mathf.Pow(0.5f, i); meshLODs.Add(meshLOD); } lodData[i] = lodMeshes.ToArray(); } // Change the name of the original renderers last, so the name change doesn't end up in the clones for other LODs AppendLODNameToRenderers(go.transform, 0); if (meshLODs.Count > 0) { if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(lodData))) { AssetDatabase.CreateAsset(lodData, GetLODDataPath(assetPath)); } else { var objects = AssetDatabase.LoadAllAssetsAtPath(GetLODDataPath(assetPath)); foreach (var o in objects) { var mesh = o as Mesh; if (mesh) { UnityObject.DestroyImmediate(mesh, true); } } EditorUtility.SetDirty(lodData); } meshLODs.ForEach(ml => AssetDatabase.AddObjectToAsset(ml.outputMesh, lodData)); AssetDatabase.SaveAssets(); foreach (var ml in meshLODs) { GenerateMeshLOD(ml, preprocessMeshes); } } } else { // Don't allow overriding LOD0 lodData[0] = originalMeshFilters.Select(mf => { var r = mf.GetComponent <Renderer>(); AppendLODNameToRenderer(r, 0); return(r); }).ToArray(); for (int i = 1; i <= LODData.MaxLOD; i++) { var renderers = lodData[i]; for (int j = 0; j < renderers.Length; j++) { var r = renderers[j]; var lodTransform = EditorUtility.CreateGameObjectWithHideFlags(r.name, k_DefaultHideFlags, typeof(MeshFilter), typeof(MeshRenderer)).transform; lodTransform.parent = go.transform; lodTransform.localPosition = Vector3.zero; var lodMF = lodTransform.GetComponent <MeshFilter>(); var lodRenderer = lodTransform.GetComponent <MeshRenderer>(); EditorUtility.CopySerialized(r.GetComponent <MeshFilter>(), lodMF); EditorUtility.CopySerialized(r, lodRenderer); AppendLODNameToRenderer(lodRenderer, i); renderers[j] = lodRenderer; } } } List <LOD> lods = new List <LOD>(); var maxLODFound = -1; for (int i = 0; i <= LODData.MaxLOD; i++) { var renderers = lodData[i]; if (renderers == null || renderers.Length == 0) { break; } maxLODFound++; } for (int i = 0; i <= maxLODFound; i++) { var lod = new LOD(); lod.renderers = lodData[i]; lod.screenRelativeTransitionHeight = i == maxLODFound ? 0.01f : Mathf.Pow(0.5f, i + 1); lods.Add(lod); } var lodGroup = go.AddComponent <LODGroup>(); lodGroup.SetLODs(lods.ToArray()); lodGroup.RecalculateBounds(); s_ModelAssetsProcessed.Add(assetPath); } }