public void Simplify(WMesh inputMesh, WMesh outputMesh, float quality) { var enableLogging = false; int totalTriangleCount; var sourceMesh = ToMeshDecimatorMesh(inputMesh, out totalTriangleCount); int targetTriangleCount = Mathf.CeilToInt(totalTriangleCount * quality); var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); DecimationAlgorithm.StatusReportCallback statusCallback = (iteration, tris, currentTris, targetTris) => { Debug.LogFormat("Iteration {0}: tris {1} current {2} target {3}", iteration, tris, currentTris, targetTris); }; if (enableLogging) { algorithm.StatusReport += statusCallback; } var destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); if (enableLogging) { algorithm.StatusReport -= statusCallback; } FromMeshDecimatorMesh(destMesh, false, ref outputMesh); }
/// <summary> /// Decimates an array of meshes, and combines them into one mesh. /// </summary> /// <param name="meshes">The meshes to decimate.</param> /// <param name="transforms">The mesh transforms.</param> /// <param name="materials">The mesh materials, including submesh materials.</param> /// <param name="quality">The desired quality.</param> /// <param name="recalculateNormals">If normals should be recalculated.</param> /// <param name="resultMaterials">The resulting materials array.</param> /// <param name="statusCallback">The optional status report callback.</param> /// <returns>The decimated mesh.</returns> public static UMesh DecimateMeshes(UMesh[] meshes, UMatrix[] transforms, UMaterial[][] materials, float quality, bool recalculateNormals, out UMaterial[] resultMaterials, DecimationAlgorithm.StatusReportCallback statusCallback = null) { UTransform[] mergedBones; return(DecimateMeshes(meshes, transforms, materials, null, quality, recalculateNormals, out resultMaterials, out mergedBones, statusCallback)); }
/// <summary> /// Decimates an array of meshes, and combines them into one mesh. /// </summary> /// <param name="meshes">The meshes to decimate.</param> /// <param name="transforms">The mesh transforms.</param> /// <param name="materials">The mesh materials, with submesh materials.</param> /// <param name="meshBones">The bones for each mesh.</param> /// <param name="quality">The desired quality.</param> /// <param name="recalculateNormals">If normals should be recalculated.</param> /// <param name="resultMaterials">The resulting materials array.</param> /// <param name="mergedBones">The output merged bones.</param> /// <param name="statusCallback">The optional status report callback.</param> /// <returns>The decimated mesh.</returns> public static UMesh DecimateMeshes(UMesh[] meshes, UMatrix[] transforms, UMaterial[][] materials, UTransform[][] meshBones, float quality, bool recalculateNormals, out UMaterial[] resultMaterials, out UTransform[] mergedBones, DecimationAlgorithm.StatusReportCallback statusCallback = null) { if (meshes == null) { throw new ArgumentNullException("meshes"); } else if (meshes.Length == 0) { throw new ArgumentException("You have to simplify at least one mesh.", "meshes"); } else if (transforms == null) { throw new ArgumentNullException("transforms"); } else if (transforms.Length != meshes.Length) { throw new ArgumentException("The array of transforms must match the length of the meshes array.", "transforms"); } else if (materials == null) { throw new ArgumentNullException("materials"); } else if (materials.Length != meshes.Length) { throw new ArgumentException("If materials are provided, the length of the array must match the length of the meshes array.", "materials"); } else if (meshBones != null && meshBones.Length != meshes.Length) { throw new ArgumentException("If mesh bones are provided, the length of the array must match the length of the meshes array.", "meshBones"); } int totalVertexCount = 0; int totalSubMeshCount = 0; for (int meshIndex = 0; meshIndex < meshes.Length; meshIndex++) { UMesh mesh = meshes[meshIndex]; totalVertexCount += mesh.vertexCount; totalSubMeshCount += mesh.subMeshCount; var meshMaterials = materials[meshIndex]; if (meshMaterials == null) { throw new ArgumentException(string.Format("The mesh materials for index {0} is null!", meshIndex), "materials"); } else if (meshMaterials.Length != mesh.subMeshCount) { throw new ArgumentException(string.Format("The mesh materials at index {0} don't match the submesh count! ({1} != {2})", meshIndex, meshMaterials.Length, mesh.subMeshCount), "materials"); } for (int i = 0; i < meshMaterials.Length; i++) { if (meshMaterials[i] == null) { throw new ArgumentException(string.Format("The mesh material index {0} at material array index {1} is null!", i, meshIndex), "materials"); } } } int totalTriangleCount = 0; var vertices = new List <Vector3d>(totalVertexCount); var indices = new List <int[]>(totalSubMeshCount); List <Vector3> normals = null; List <Vector4> tangents = null; List <Vector2> uv1 = null; List <Vector2> uv2 = null; List <Vector2> uv3 = null; List <Vector2> uv4 = null; List <Vector4> colors = null; List <BoneWeight> boneWeights = null; List <UMatrix> usedBindposes = null; List <UTransform> usedBones = null; List <UMaterial> usedMaterials = new List <UMaterial>(totalSubMeshCount); Dictionary <UMaterial, int> materialMap = new Dictionary <UMaterial, int>(); int currentVertexCount = 0; for (int meshIndex = 0; meshIndex < meshes.Length; meshIndex++) { var mesh = meshes[meshIndex]; var transform = transforms[meshIndex]; var meshMaterials = materials[meshIndex]; var bones = (meshBones != null ? meshBones[meshIndex] : null); int meshVertexCount = mesh.vertexCount; var meshVertices = mesh.vertices; var meshNormals = mesh.normals; var meshTangents = mesh.tangents; var meshUV1 = mesh.uv; var meshUV2 = mesh.uv2; var meshUV3 = mesh.uv3; var meshUV4 = mesh.uv4; var meshColors = mesh.colors; var meshBoneWeights = mesh.boneWeights; var meshBindposes = mesh.bindposes; if (bones != null && meshBoneWeights != null && meshBoneWeights.Length > 0 && meshBindposes != null && meshBindposes.Length > 0 && bones.Length == meshBindposes.Length) { if (usedBindposes == null) { usedBindposes = new List <UMatrix>(meshBindposes); usedBones = new List <UTransform>(bones); } else { bool bindPoseMismatch = false; int[] boneIndices = new int[bones.Length]; for (int i = 0; i < bones.Length; i++) { int usedBoneIndex = usedBones.IndexOf(bones[i]); if (usedBoneIndex == -1) { usedBoneIndex = usedBones.Count; usedBones.Add(bones[i]); usedBindposes.Add(meshBindposes[i]); } else { if (meshBindposes[i] != usedBindposes[usedBoneIndex]) { bindPoseMismatch = true; } } boneIndices[i] = usedBoneIndex; } // If any bindpose is mismatching, we correct it first if (bindPoseMismatch) { var correctedBindposes = new UMatrix[meshBindposes.Length]; for (int i = 0; i < meshBindposes.Length; i++) { int usedBoneIndex = boneIndices[i]; correctedBindposes[i] = usedBindposes[usedBoneIndex]; } TransformVertices(meshVertices, meshBoneWeights, meshBindposes, correctedBindposes); } // Then we remap the bones RemapBones(meshBoneWeights, boneIndices); } } // Transforms the vertices TransformVertices(meshVertices, ref transform); AddToList(vertices, meshVertices, currentVertexCount, totalVertexCount); AddToList(ref normals, meshNormals, currentVertexCount, meshVertexCount, totalVertexCount, new Vector3(1f, 0f, 0f)); AddToList(ref tangents, meshTangents, currentVertexCount, meshVertexCount, totalVertexCount, new Vector4(0f, 0f, 1f, 1f)); // Is the default value correct? AddToList(ref uv1, meshUV1, currentVertexCount, meshVertexCount, totalVertexCount, new Vector2()); AddToList(ref uv2, meshUV2, currentVertexCount, meshVertexCount, totalVertexCount, new Vector2()); AddToList(ref uv3, meshUV3, currentVertexCount, meshVertexCount, totalVertexCount, new Vector2()); AddToList(ref uv4, meshUV4, currentVertexCount, meshVertexCount, totalVertexCount, new Vector2()); AddToList(ref colors, meshColors, currentVertexCount, meshVertexCount, totalVertexCount); AddToList(ref boneWeights, meshBoneWeights, currentVertexCount, meshVertexCount, totalVertexCount); int subMeshCount = mesh.subMeshCount; for (int subMeshIndex = 0; subMeshIndex < subMeshCount; subMeshIndex++) { var subMeshMaterial = meshMaterials[subMeshIndex]; int[] subMeshIndices = mesh.GetTriangles(subMeshIndex); if (currentVertexCount > 0) { for (int i = 0; i < subMeshIndices.Length; i++) { subMeshIndices[i] += currentVertexCount; } } totalTriangleCount += subMeshIndices.Length / 3; int mergeWithIndex; if (materialMap.TryGetValue(subMeshMaterial, out mergeWithIndex)) { int[] currentIndices = indices[mergeWithIndex]; indices[mergeWithIndex] = MergeArrays(currentIndices, subMeshIndices); } else { materialMap.Add(subMeshMaterial, indices.Count); usedMaterials.Add(subMeshMaterial); indices.Add(subMeshIndices); } } currentVertexCount += meshVertices.Length; } quality = UMath.Clamp01(quality); int targetTriangleCount = UMath.CeilToInt(totalTriangleCount * quality); var sourceMesh = new Mesh(vertices.ToArray(), indices.ToArray()); if (normals != null) { sourceMesh.Normals = normals.ToArray(); } if (tangents != null) { sourceMesh.Tangents = tangents.ToArray(); } if (uv1 != null) { sourceMesh.UV1 = uv1.ToArray(); } if (uv2 != null) { sourceMesh.UV2 = uv2.ToArray(); } if (uv3 != null) { sourceMesh.UV3 = uv3.ToArray(); } if (uv4 != null) { sourceMesh.UV4 = uv4.ToArray(); } if (colors != null) { sourceMesh.Colors = colors.ToArray(); } if (boneWeights != null) { sourceMesh.BoneWeights = boneWeights.ToArray(); } var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); algorithm.MaxVertexCount = ushort.MaxValue; if (statusCallback != null) { algorithm.StatusReport += statusCallback; } var destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); var newMeshVertices = FromSimplifyVertices(destMesh.Vertices); if (statusCallback != null) { algorithm.StatusReport -= statusCallback; } var bindposes = (usedBindposes != null ? usedBindposes.ToArray() : null); resultMaterials = usedMaterials.ToArray(); mergedBones = (usedBones != null ? usedBones.ToArray() : null); return(CreateMesh(bindposes, newMeshVertices, destMesh, recalculateNormals)); }
/// <summary> /// Decimates a mesh. /// </summary> /// <param name="mesh">The mesh to decimate.</param> /// <param name="transform">The mesh transform.</param> /// <param name="quality">The desired quality.</param> /// <param name="recalculateNormals">If normals should be recalculated.</param> /// <param name="statusCallback">The optional status report callback.</param> /// <returns>The decimated mesh.</returns> public static UMesh DecimateMesh(UMesh mesh, UMatrix transform, float quality, bool recalculateNormals, DecimationAlgorithm.StatusReportCallback statusCallback = null) { if (mesh == null) { throw new ArgumentNullException("mesh"); } int subMeshCount = mesh.subMeshCount; var meshVertices = mesh.vertices; var meshNormals = mesh.normals; var meshTangents = mesh.tangents; var meshUV1 = mesh.uv; var meshUV2 = mesh.uv2; var meshUV3 = mesh.uv3; var meshUV4 = mesh.uv4; var meshColors = mesh.colors; var meshBoneWeights = mesh.boneWeights; var meshBindposes = mesh.bindposes; int totalTriangleCount = 0; var meshIndices = new int[subMeshCount][]; for (int i = 0; i < subMeshCount; i++) { meshIndices[i] = mesh.GetTriangles(i); totalTriangleCount += meshIndices[i].Length / 3; } // Transforms the vertices TransformVertices(meshVertices, ref transform); var vertices = ToSimplifyVertices(meshVertices); quality = UMath.Clamp01(quality); int targetTriangleCount = UMath.CeilToInt(totalTriangleCount * quality); var sourceMesh = new Mesh(vertices, meshIndices); if (meshNormals != null && meshNormals.Length > 0) { sourceMesh.Normals = ToSimplifyVec(meshNormals); } if (meshTangents != null && meshTangents.Length > 0) { sourceMesh.Tangents = ToSimplifyVec(meshTangents); } if (meshUV1 != null && meshUV1.Length > 0) { sourceMesh.UV1 = ToSimplifyVec(meshUV1); } if (meshUV2 != null && meshUV2.Length > 0) { sourceMesh.UV2 = ToSimplifyVec(meshUV2); } if (meshUV3 != null && meshUV3.Length > 0) { sourceMesh.UV3 = ToSimplifyVec(meshUV3); } if (meshUV4 != null && meshUV4.Length > 0) { sourceMesh.UV4 = ToSimplifyVec(meshUV4); } if (meshColors != null && meshColors.Length > 0) { sourceMesh.Colors = ToSimplifyVec(meshColors); } if (meshBoneWeights != null && meshBoneWeights.Length > 0) { sourceMesh.BoneWeights = ToSimplifyBoneWeights(meshBoneWeights); } var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); algorithm.MaxVertexCount = ushort.MaxValue; if (statusCallback != null) { algorithm.StatusReport += statusCallback; } //var destMesh = MeshDecimation.DecimateMeshLossless( sourceMesh); var destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); var newMeshVertices = FromSimplifyVertices(destMesh.Vertices); if (statusCallback != null) { algorithm.StatusReport -= statusCallback; } return(CreateMesh(meshBindposes, newMeshVertices, destMesh, recalculateNormals)); }
public static UMesh DecimateMeshBasic(Mesh sourceMesh, UMatrix transform, float quality, bool recalculateNormals, DecimationAlgorithm.StatusReportCallback statusCallback = null) { var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.FastQuadraticMesh); algorithm.MaxVertexCount = ushort.MaxValue; if (statusCallback != null) { algorithm.StatusReport += statusCallback; } int totalTriangleCount = sourceMesh.Indices.Length / 3; int targetTriangleCount = UMath.CeilToInt(totalTriangleCount * quality); //var destMesh = MeshDecimation.DecimateMeshLossless( sourceMesh); var destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); var newMeshVertices = FromSimplifyVertices(destMesh.Vertices); if (statusCallback != null) { algorithm.StatusReport -= statusCallback; } return(CreateMesh(null, newMeshVertices, destMesh, recalculateNormals)); }
/// <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); }
private static Mesh GenerateSkinnedLOD(Transform transform, SkinnedMeshRenderer[] renderers, float quality, out Material[] materials, out Transform[] mergedBones, DecimationAlgorithm.StatusReportCallback statusCallback) { if (renderers.Length == 1) { return(GenerateSkinnedLOD(transform, renderers[0], quality, out materials, out mergedBones, statusCallback)); } else { var sourceMeshes = new Mesh[renderers.Length]; var transforms = new Matrix4x4[renderers.Length]; var meshMaterials = new Material[renderers.Length][]; var meshBones = new Transform[renderers.Length][]; for (int i = 0; i < renderers.Length; i++) { var renderer = renderers[i]; var rendererTransform = renderer.transform; sourceMeshes[i] = renderer.sharedMesh; transforms[i] = transform.worldToLocalMatrix * rendererTransform.localToWorldMatrix; meshMaterials[i] = renderer.sharedMaterials; meshBones[i] = renderer.bones; } return(MeshDecimatorUtility.DecimateMeshes(sourceMeshes, transforms, meshMaterials, meshBones, quality, false, out materials, out mergedBones, statusCallback)); } }
private static Mesh GenerateSkinnedLOD(Transform transform, SkinnedMeshRenderer renderer, float quality, out Material[] materials, out Transform[] mergedBones, DecimationAlgorithm.StatusReportCallback statusCallback) { var rendererTransform = renderer.transform; var mesh = renderer.sharedMesh; var meshTransform = transform.worldToLocalMatrix * rendererTransform.localToWorldMatrix; materials = renderer.sharedMaterials; mergedBones = renderer.bones; return(MeshDecimatorUtility.DecimateMesh(mesh, meshTransform, quality, false, statusCallback)); }
private static Mesh GenerateStaticLOD(Transform transform, MeshRenderer renderer, float quality, out Material[] materials, DecimationAlgorithm.StatusReportCallback statusCallback) { var rendererTransform = renderer.transform; var meshFilter = renderer.GetComponent <MeshFilter>(); var mesh = meshFilter.sharedMesh; var meshTransform = transform.worldToLocalMatrix * rendererTransform.localToWorldMatrix; materials = renderer.sharedMaterials; return(MeshDecimatorUtility.DecimateMesh(mesh, meshTransform, quality, false, statusCallback)); }
private static Mesh GenerateStaticLOD(Transform transform, MeshRenderer[] renderers, float quality, out Material[] materials, DecimationAlgorithm.StatusReportCallback statusCallback) { if (renderers.Length == 1) { var renderer = renderers[0]; var rendererTransform = renderer.transform; var meshFilter = renderer.GetComponent <MeshFilter>(); var mesh = meshFilter.sharedMesh; var meshTransform = transform.worldToLocalMatrix * rendererTransform.localToWorldMatrix; materials = renderer.sharedMaterials; return(MeshDecimatorUtility.DecimateMesh(mesh, meshTransform, quality, false, statusCallback)); } else { var sourceMeshes = new Mesh[renderers.Length]; var transforms = new Matrix4x4[renderers.Length]; var meshMaterials = new Material[renderers.Length][]; for (int i = 0; i < renderers.Length; i++) { var renderer = renderers[i]; var rendererTransform = renderer.transform; var meshFilter = renderer.GetComponent <MeshFilter>(); sourceMeshes[i] = meshFilter.sharedMesh; transforms[i] = transform.worldToLocalMatrix * rendererTransform.localToWorldMatrix; meshMaterials[i] = renderer.sharedMaterials; } return(MeshDecimatorUtility.DecimateMeshes(sourceMeshes, transforms, meshMaterials, quality, false, out materials, statusCallback)); } }