/** Move to the specified segment and move a fraction of the way to the next segment */ public void MoveToSegment(int index, float fractionAlongSegment) { if (path == null) { return; } if (index < 0 || index >= path.Count - 1) { throw new System.ArgumentOutOfRangeException("index"); } while (segmentIndex > index) { PrevSegment(); } while (segmentIndex < index) { NextSegment(); } distance = distanceToSegmentStart + Mathf.Clamp01(fractionAlongSegment) * currentSegmentLength; }
/// <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)); }