/// <summary> /// Method for mesh decimation /// </summary> /// <param name="meshStore">mesh data</param> /// <param name="targetTriangleCount">target triangle count for decimation</param> public static void Decimate(ref MeshStore meshStore, int targetTriangleCount) { // extract origin mesh data and create mesh instance Vector3d[] vertices = new Vector3d[meshStore.Vertexes.Count / 3]; for (int i = 0, j = 0; i < meshStore.Vertexes.Count; i += 3, ++j) { vertices[j] = new Vector3d(meshStore.Vertexes[i], meshStore.Vertexes[i + 1], meshStore.Vertexes[i + 2]); } Mesh sourceMesh = new Mesh(vertices, meshStore.Indexes.ToArray()); // decimate mesh var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); algorithm.Verbose = true; Mesh destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); // change meshstore meshStore.Indexes = destMesh.Indices.ToList(); List <double> newVertices = new List <double>(); foreach (Vector3d vec in destMesh.Vertices) { newVertices.Add(vec.x); newVertices.Add(vec.y); newVertices.Add(vec.z); } meshStore.Vertexes = newVertices; }
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); }
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)); }
static void Main(string[] args) { if (args.Length < 2) { PrintUsage(); return; } try { string sourcePath = Path.GetFullPath(args[0]); string destPath = Path.GetFullPath(args[1]); float quality = 0.5f; if (args.Length > 2) { if (!float.TryParse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture, out quality)) { Console.Error.WriteLine("Unable to convert '{0}' into a float.", args[2]); return; } } quality = MathHelper.Clamp01(quality); ObjMesh sourceObjMesh = new ObjMesh(); sourceObjMesh.ReadFile(sourcePath); var sourceVertices = sourceObjMesh.Vertices; var sourceIndices = sourceObjMesh.Indices; var sourceMesh = new Mesh(sourceVertices, sourceIndices); int currentTriangleCount = sourceIndices.Length / 3; int targetTriangleCount = (int)Math.Ceiling(currentTriangleCount * quality); Console.WriteLine("Input: {0} vertices, {1} triangles (target {2})", sourceVertices.Length, currentTriangleCount, targetTriangleCount); var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Reset(); stopwatch.Start(); var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); algorithm.Verbose = true; Mesh destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); stopwatch.Stop(); var destVertices = destMesh.Vertices; var destIndices = destMesh.Indices; ObjMesh destObjMesh = new ObjMesh(destVertices, destIndices); destObjMesh.WriteFile(destPath); float reduction = (float)(destIndices.Length / 3) / (float)currentTriangleCount; float timeTaken = (float)stopwatch.Elapsed.TotalSeconds; Console.WriteLine("Output: {0} vertices, {1} triangles ({2} reduction; {3:0.0000} sec)", destVertices.Length, destIndices.Length / 3, reduction, timeTaken); } catch (Exception ex) { Console.Error.WriteLine("Error decimating mesh. Reason: {0}", ex.Message); } }
public async void SimplifyObj(string sourcePath, string destPath, float quality) { simplifyTask = new Task(() => { quality = MathHelper.Clamp01(quality); ObjMesh sourceObjMesh = new ObjMesh(); sourceObjMesh.ReadFile(sourcePath); var sourceVertices = sourceObjMesh.Vertices; var sourceNormals = sourceObjMesh.Normals; var sourceTexCoords2D = sourceObjMesh.TexCoords2D; var sourceTexCoords3D = sourceObjMesh.TexCoords3D; var sourceSubMeshIndices = sourceObjMesh.SubMeshIndices; var sourceMesh = new MeshDecimator.Mesh(sourceVertices, sourceSubMeshIndices); sourceMesh.Normals = sourceNormals; if (sourceTexCoords2D != null) { sourceMesh.SetUVs(0, sourceTexCoords2D); } else if (sourceTexCoords3D != null) { sourceMesh.SetUVs(0, sourceTexCoords3D); } int currentTriangleCount = 0; for (int i = 0; i < sourceSubMeshIndices.Length; i++) { currentTriangleCount += (sourceSubMeshIndices[i].Length / 3); } int targetTriangleCount = (int)Math.Ceiling(currentTriangleCount * quality); string info_1 = string.Format("Input: {0} vertices, {1} triangles (target {2}) \n", sourceVertices.Length, currentTriangleCount, targetTriangleCount); // Console.WriteLine(info_1); simplifyInfo.Invoke(info_1); var stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Reset(); stopwatch.Start(); var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); algorithm.Verbose = true; MeshDecimator.Mesh destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); stopwatch.Stop(); var destVertices = destMesh.Vertices; var destNormals = destMesh.Normals; var destIndices = destMesh.GetSubMeshIndices(); ObjMesh destObjMesh = new ObjMesh(destVertices, destIndices); destObjMesh.Normals = destNormals; destObjMesh.MaterialLibraries = sourceObjMesh.MaterialLibraries; destObjMesh.SubMeshMaterials = sourceObjMesh.SubMeshMaterials; if (sourceTexCoords2D != null) { var destUVs = destMesh.GetUVs2D(0); destObjMesh.TexCoords2D = destUVs; } else if (sourceTexCoords3D != null) { var destUVs = destMesh.GetUVs3D(0); destObjMesh.TexCoords3D = destUVs; } destObjMesh.WriteFile(destPath); int outputTriangleCount = 0; for (int i = 0; i < destIndices.Length; i++) { outputTriangleCount += (destIndices[i].Length / 3); } float reduction = (float)outputTriangleCount / (float)currentTriangleCount; float timeTaken = (float)stopwatch.Elapsed.TotalSeconds; string info_2 = string.Format("Output: {0} vertices, {1} triangles ({2} reduction; {3:0.0000} sec) \n", destVertices.Length, outputTriangleCount, reduction, timeTaken); // Console.WriteLine(info_2); simplifyInfo.Invoke(info_2); simplifyInfo.Invoke("finish"); DisposeTask(); }); simplifyTask.Start(); }
/// <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 Rmv2Geometry CreatedReducedCopy(float factor) { var quality = factor; // ObjMesh sourceObjMesh = new ObjMesh(); // sourceObjMesh.ReadFile(sourcePath); var sourceVertices = _vertexArray.Select(x => new MeshDecimator.Math.Vector3d(x.Position.X, x.Position.Y, x.Position.Z)).ToArray(); // var sourceTexCoords3D = sourceObjMesh.TexCoords3D; var sourceSubMeshIndices = _indexList.Select(x => (int)x).ToArray(); var sourceMesh = new Mesh(sourceVertices, sourceSubMeshIndices); sourceMesh.Normals = _vertexArray.Select(x => new MeshDecimator.Math.Vector3(x.Normal.X, x.Normal.Y, x.Normal.Z)).ToArray(); sourceMesh.Tangents = _vertexArray.Select(x => new MeshDecimator.Math.Vector4(x.Tangent.X, x.Tangent.Y, x.Tangent.Z, 0)).ToArray(); // Should last 0 be 1? sourceMesh.SetUVs(0, _vertexArray.Select(x => new MeshDecimator.Math.Vector2(x.TextureCoordinate.X, x.TextureCoordinate.Y)).ToArray()); if (WeightCount == 4) { sourceMesh.BoneWeights = _vertexArray.Select(x => new BoneWeight( (int)x.BlendIndices.X, (int)x.BlendIndices.Y, (int)x.BlendIndices.Z, (int)x.BlendIndices.W, x.BlendWeights.X, x.BlendWeights.Y, x.BlendWeights.Z, x.BlendWeights.W)).ToArray(); } else if (WeightCount == 2) { sourceMesh.BoneWeights = _vertexArray.Select(x => new BoneWeight( (int)x.BlendIndices.X, (int)x.BlendIndices.Y, 0, 0, x.BlendWeights.X, x.BlendWeights.Y, 0, 0)).ToArray(); } else if (WeightCount == 0) { sourceMesh.BoneWeights = _vertexArray.Select(x => new BoneWeight( 0, 0, 0, 0, 0, 0, 0, 0)).ToArray(); } int currentTriangleCount = sourceSubMeshIndices.Length / 3; int targetTriangleCount = (int)Math.Ceiling(currentTriangleCount * quality); var algorithm = MeshDecimation.CreateAlgorithm(Algorithm.Default); algorithm.Verbose = true; Mesh destMesh = MeshDecimation.DecimateMesh(algorithm, sourceMesh, targetTriangleCount); var destVertices = destMesh.Vertices; var destNormals = destMesh.Normals; var destIndices = destMesh.GetSubMeshIndices(); VertexPositionNormalTextureCustom[] outputVerts = new VertexPositionNormalTextureCustom[destVertices.Length]; for (int i = 0; i < outputVerts.Length; i++) { var pos = destMesh.Vertices[i]; var norm = destMesh.Normals[i]; var tangents = destMesh.Tangents[i]; var uv = destMesh.UV1[i]; var boneWeight = destMesh.BoneWeights[i]; Vector3 normal = new Vector3(norm.x, norm.y, norm.z); Vector3 tangent = new Vector3(tangents.x, tangents.y, tangents.z); var binormal = Vector3.Normalize(Vector3.Cross(normal, tangent));// * sign var vert = new VertexPositionNormalTextureCustom(); vert.Position = new Vector4((float)pos.x, (float)pos.y, (float)pos.z, 1); vert.Normal = new Vector3(norm.x, norm.y, norm.z); vert.Tangent = new Vector3(tangents.x, tangents.y, tangents.z); vert.BiNormal = new Vector3(binormal.X, binormal.Y, binormal.Z); vert.TextureCoordinate = new Vector2(uv.x, uv.y); if (WeightCount == 4) { vert.BlendIndices = new Vector4(boneWeight.boneIndex0, boneWeight.boneIndex1, boneWeight.boneIndex2, boneWeight.boneIndex3); vert.BlendWeights = new Vector4(boneWeight.boneWeight0, boneWeight.boneWeight1, boneWeight.boneWeight2, boneWeight.boneWeight3); } else if (WeightCount == 2) { vert.BlendIndices = new Vector4(boneWeight.boneIndex0, boneWeight.boneIndex1, 0, 0); vert.BlendWeights = new Vector4(boneWeight.boneWeight0, boneWeight.boneWeight1, 0, 0); } else if (WeightCount == 0) { vert.BlendIndices = new Vector4(0, 0, 0, 0); vert.BlendWeights = new Vector4(0, 0, 0, 0); } if ((vert.BlendWeights.X + vert.BlendWeights.Y + vert.BlendWeights.Z + vert.BlendWeights.W) == 0) { vert.BlendWeights.X = 1; } outputVerts[i] = vert; } var clone = Clone(false) as Rmv2Geometry; clone._indexList = destIndices[0].Select(x => (ushort)x).ToArray(); clone._vertexArray = outputVerts; clone.RebuildIndexBuffer(); clone.RebuildVertexBuffer(); return(clone); }