/// <summary> /// Generates the LODs for this object. /// </summary> /// <param name="statusCallback">The status report callback.</param> public void GenerateLODs(LODStatusReportCallback statusCallback = null) { if (levels != null) { LODGenerator.GenerateLODs(gameObject, levels, statusCallback); } generated = true; }
/// <summary> /// Generates the LODs and sets up a LOD Group for the specified game object. /// </summary> /// <param name="gameObj">The game object to set up.</param> /// <param name="levels">The LOD levels.</param> /// <param name="statusCallback">The optional status report callback.</param> public static void GenerateLODs(GameObject gameObj, LODSettings[] levels, LODStatusReportCallback statusCallback = null) { DestroyLODs(gameObj); var transform = gameObj.transform; var meshRenderers = gameObj.GetComponentsInChildren <MeshRenderer>(); var skinnedRenderers = gameObj.GetComponentsInChildren <SkinnedMeshRenderer>(); // Check if there's anything to do if (meshRenderers.Length == 0 && skinnedRenderers.Length == 0) { return; } var lodsParentObj = new GameObject(ParentGameObjectName); var lodsParent = lodsParentObj.transform; lodsParent.parent = transform; lodsParent.localPosition = Vector3.zero; lodsParent.localRotation = Quaternion.identity; lodsParent.localScale = Vector3.one; var lodGroup = gameObj.GetComponent <LODGroup>(); if (lodGroup == null) { lodGroup = gameObj.AddComponent <LODGroup>(); } float screenRelativeTransitionHeight = 0.5f; LOD[] lodLevels = new LOD[levels.Length + 1]; var firstLevelRenderers = CombineRenderers(meshRenderers, skinnedRenderers); lodLevels[0] = new LOD(screenRelativeTransitionHeight, firstLevelRenderers); screenRelativeTransitionHeight *= 0.5f; float minimumQuality = 1f; for (int levelIndex = 0; levelIndex < levels.Length; levelIndex++) { var level = levels[levelIndex]; float quality = Mathf.Clamp(level.quality, 0.01f, minimumQuality); screenRelativeTransitionHeight *= quality * quality; GameObject lodObj = new GameObject(string.Format("Level{0}", levelIndex)); var lodParent = lodObj.transform; lodParent.parent = lodsParent; lodParent.localPosition = Vector3.zero; lodParent.localRotation = Quaternion.identity; lodParent.localScale = Vector3.one; DecimationAlgorithm.StatusReportCallback levelStatusCallback = null; if (statusCallback != null) { levelStatusCallback = (iteration, originalTris, currentTris, targetTris) => { statusCallback.Invoke(levelIndex, iteration, originalTris, currentTris, targetTris); }; } GameObject staticLodObj = lodObj; GameObject skinnedLodObj = lodObj; Transform staticLodParent = lodParent; Transform skinnedLodParent = lodParent; if (meshRenderers.Length > 0 && skinnedRenderers.Length > 0) { staticLodObj = new GameObject("Static", typeof(MeshFilter), typeof(MeshRenderer)); staticLodParent = staticLodObj.transform; staticLodParent.parent = lodParent; staticLodParent.localPosition = Vector3.zero; staticLodParent.localRotation = Quaternion.identity; staticLodParent.localScale = Vector3.one; skinnedLodObj = new GameObject("Skinned", typeof(SkinnedMeshRenderer)); skinnedLodParent = skinnedLodObj.transform; skinnedLodParent.parent = lodParent; skinnedLodParent.localPosition = Vector3.zero; skinnedLodParent.localRotation = Quaternion.identity; skinnedLodParent.localScale = Vector3.one; } Renderer[] staticLodRenderers = null; Renderer[] skinnedLodRenderers = null; if (meshRenderers.Length > 0) { if (level.combineMeshes) { Material[] materials; Mesh lodMesh = GenerateStaticLOD(transform, meshRenderers, quality, out materials, levelStatusCallback); lodMesh.name = string.Format("{0}_static{1}", gameObj.name, levelIndex); var meshFilter = staticLodObj.AddComponent <MeshFilter>(); meshFilter.sharedMesh = lodMesh; var lodRenderer = staticLodObj.AddComponent <MeshRenderer>(); lodRenderer.sharedMaterials = materials; SetupLODRenderer(lodRenderer, level); staticLodRenderers = new Renderer[] { lodRenderer }; } else { staticLodRenderers = new Renderer[meshRenderers.Length]; Material[] materials; for (int rendererIndex = 0; rendererIndex < meshRenderers.Length; rendererIndex++) { var renderer = meshRenderers[rendererIndex]; Mesh lodMesh = GenerateStaticLOD(transform, renderer, quality, out materials, levelStatusCallback); lodMesh.name = string.Format("{0}_static{1}_{2}", gameObj.name, levelIndex, rendererIndex); var rendererLodObj = new GameObject(renderer.name, typeof(MeshFilter), typeof(MeshRenderer)); rendererLodObj.transform.parent = staticLodParent; rendererLodObj.transform.localPosition = Vector3.zero; rendererLodObj.transform.localRotation = Quaternion.identity; rendererLodObj.transform.localScale = Vector3.one; var meshFilter = rendererLodObj.GetComponent <MeshFilter>(); meshFilter.sharedMesh = lodMesh; var lodRenderer = rendererLodObj.GetComponent <MeshRenderer>(); lodRenderer.sharedMaterials = materials; SetupLODRenderer(lodRenderer, level); staticLodRenderers[rendererIndex] = lodRenderer; } } } if (skinnedRenderers.Length > 0) { if (level.combineMeshes) { Transform[] bones; Material[] materials; Mesh lodMesh = GenerateSkinnedLOD(transform, skinnedRenderers, quality, out materials, out bones, levelStatusCallback); lodMesh.name = string.Format("{0}_skinned{1}", gameObj.name, levelIndex); Transform rootBone = FindRootBone(transform, bones); var lodRenderer = skinnedLodObj.AddComponent <SkinnedMeshRenderer>(); lodRenderer.sharedMesh = lodMesh; lodRenderer.sharedMaterials = materials; lodRenderer.rootBone = rootBone; lodRenderer.bones = bones; SetupLODRenderer(lodRenderer, level); skinnedLodRenderers = new Renderer[] { lodRenderer }; } else { skinnedLodRenderers = new Renderer[skinnedRenderers.Length]; Transform[] bones; Material[] materials; for (int rendererIndex = 0; rendererIndex < skinnedRenderers.Length; rendererIndex++) { var renderer = skinnedRenderers[rendererIndex]; Mesh lodMesh = GenerateSkinnedLOD(transform, renderer, quality, out materials, out bones, levelStatusCallback); lodMesh.name = string.Format("{0}_skinned{1}_{2}", gameObj.name, levelIndex, rendererIndex); Transform rootBone = FindRootBone(transform, bones); var rendererLodObj = new GameObject(renderer.name, typeof(SkinnedMeshRenderer)); rendererLodObj.transform.parent = skinnedLodParent; rendererLodObj.transform.localPosition = Vector3.zero; rendererLodObj.transform.localRotation = Quaternion.identity; rendererLodObj.transform.localScale = Vector3.one; var lodRenderer = rendererLodObj.GetComponent <SkinnedMeshRenderer>(); lodRenderer.sharedMesh = lodMesh; lodRenderer.sharedMaterials = materials; lodRenderer.rootBone = rootBone; lodRenderer.bones = bones; SetupLODRenderer(lodRenderer, level); skinnedLodRenderers[rendererIndex] = lodRenderer; } } } Renderer[] lodRenderers; if (staticLodRenderers != null && skinnedLodRenderers != null) { lodRenderers = staticLodRenderers.Concat <Renderer>(skinnedLodRenderers).ToArray(); } else if (staticLodRenderers != null) { lodRenderers = staticLodRenderers; } else if (skinnedLodRenderers != null) { lodRenderers = skinnedLodRenderers; } else { lodRenderers = new Renderer[0]; } minimumQuality = quality; lodLevels[levelIndex + 1] = new LOD(screenRelativeTransitionHeight, lodRenderers); } lodGroup.SetLODs(lodLevels); }