private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level) { if (level > 0) { IList <Vector3D> positions = subdivisionMesh.Positions; Vector3D n01 = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize(); Vector3D n12 = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize(); Vector3D n20 = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize(); Vector3D p01 = n01.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii); Vector3D p12 = n12.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii); Vector3D p20 = n20.MultiplyComponents(subdivisionMesh.Ellipsoid.Radii); positions.Add(p01); positions.Add(p12); positions.Add(p20); int i01 = positions.Count - 3; int i12 = positions.Count - 2; int i20 = positions.Count - 1; if ((subdivisionMesh.Normals != null) || (subdivisionMesh.TextureCoordinate != null)) { Vector3D d01 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p01); Vector3D d12 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p12); Vector3D d20 = subdivisionMesh.Ellipsoid.GeodeticSurfaceNormal(p20); if (subdivisionMesh.Normals != null) { subdivisionMesh.Normals.Add(d01.ToVector3H()); subdivisionMesh.Normals.Add(d12.ToVector3H()); subdivisionMesh.Normals.Add(d20.ToVector3H()); } if (subdivisionMesh.TextureCoordinate != null) { subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d01)); subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d12)); subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(d20)); } } // // Subdivide input triangle into four triangles // --level; Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level); Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level); Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level); Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level); } else { subdivisionMesh.Indices.AddTriangle(triangle); } }
public void TriangleIndicesTest() { TriangleIndicesUnsignedInt triangle = new TriangleIndicesUnsignedInt(0, 1, 2); Assert.AreEqual(0, triangle.UI0); Assert.AreEqual(1, triangle.UI1); Assert.AreEqual(2, triangle.UI2); TriangleIndicesUnsignedInt triangle2 = triangle; Assert.AreEqual(triangle, triangle2); TriangleIndicesUnsignedInt triangle3 = new TriangleIndicesUnsignedInt(3, 4, 5); Assert.AreNotEqual(triangle, triangle3); }
private static void Subdivide(SubdivisionMesh subdivisionMesh, TriangleIndicesUnsignedInt triangle, int level) { if (level > 0) { IList <Vector3D> positions = subdivisionMesh.Positions; Vector3D p01 = ((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize(); Vector3D p12 = ((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize(); Vector3D p20 = ((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize(); positions.Add(p01); positions.Add(p12); positions.Add(p20); int i01 = positions.Count - 3; int i12 = positions.Count - 2; int i20 = positions.Count - 1; if (subdivisionMesh.Normals != null) { subdivisionMesh.Normals.Add(p01.ToVector3H()); subdivisionMesh.Normals.Add(p12.ToVector3H()); subdivisionMesh.Normals.Add(p20.ToVector3H()); } if (subdivisionMesh.TextureCoordinate != null) { subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p01)); subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p12)); subdivisionMesh.TextureCoordinate.Add(SubdivisionUtility.ComputeTextureCoordinate(p20)); } // // Subdivide input triangle into four triangles // --level; Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level); Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level); Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i01, i12, i20), level); Subdivide(subdivisionMesh, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level); } else { subdivisionMesh.Indices.AddTriangle(triangle); } }
private static void Subdivide(IList <Vector3D> positions, IndicesUnsignedInt indices, TriangleIndicesUnsignedInt triangle, int level) { if (level > 0) { positions.Add(((positions[triangle.I0] + positions[triangle.I1]) * 0.5).Normalize()); positions.Add(((positions[triangle.I1] + positions[triangle.I2]) * 0.5).Normalize()); positions.Add(((positions[triangle.I2] + positions[triangle.I0]) * 0.5).Normalize()); int i01 = positions.Count - 3; int i12 = positions.Count - 2; int i20 = positions.Count - 1; // // Subdivide input triangle into four triangles // --level; Subdivide(positions, indices, new TriangleIndicesUnsignedInt(triangle.I0, i01, i20), level); Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, triangle.I1, i12), level); Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i01, i12, i20), level); Subdivide(positions, indices, new TriangleIndicesUnsignedInt(i20, i12, triangle.I2), level); } else { indices.AddTriangle(triangle); } }
public static TriangleMeshSubdivisionResult Compute(IEnumerable <Vector3D> positions, IndicesUnsignedInt indices, double granularity) { if (positions == null) { throw new ArgumentNullException("positions"); } if (indices == null) { throw new ArgumentNullException("positions"); } if (indices.Values.Count < 3) { throw new ArgumentOutOfRangeException("indices", "At least three indices are required."); } if (indices.Values.Count % 3 != 0) { throw new ArgumentException("indices", "The number of indices must be divisable by three."); } if (granularity <= 0.0) { throw new ArgumentOutOfRangeException("granularity", "Granularity must be greater than zero."); } // // Use two queues: one for triangles that need (or might need) to be // subdivided and other for triangles that are fully subdivided. // Queue <TriangleIndicesUnsignedInt> triangles = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3); Queue <TriangleIndicesUnsignedInt> done = new Queue <TriangleIndicesUnsignedInt>(indices.Values.Count / 3); IList <uint> indicesValues = indices.Values; for (int i = 0; i < indicesValues.Count; i += 3) { triangles.Enqueue(new TriangleIndicesUnsignedInt(indicesValues[i], indicesValues[i + 1], indicesValues[i + 2])); } // // New positions due to edge splits are appended to the positions list. // IList <Vector3D> subdividedPositions = CollectionAlgorithms.CopyEnumerableToList(positions); // // Used to make sure shared edges are not split more than once. // Dictionary <Edge, int> edges = new Dictionary <Edge, int>(); // // Subdivide triangles until we run out // while (triangles.Count != 0) { TriangleIndicesUnsignedInt triangle = triangles.Dequeue(); Vector3D v0 = subdividedPositions[triangle.I0]; Vector3D v1 = subdividedPositions[triangle.I1]; Vector3D v2 = subdividedPositions[triangle.I2]; double g0 = v0.AngleBetween(v1); double g1 = v1.AngleBetween(v2); double g2 = v2.AngleBetween(v0); double max = Math.Max(g0, Math.Max(g1, g2)); if (max > granularity) { if (g0 == max) { Edge edge = new Edge(Math.Min(triangle.I0, triangle.I1), Math.Max(triangle.I0, triangle.I1)); int i; if (!edges.TryGetValue(edge, out i)) { subdividedPositions.Add((v0 + v1) * 0.5); i = subdividedPositions.Count - 1; edges.Add(edge, i); } triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I0, i, triangle.I2)); triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I1, triangle.I2)); } else if (g1 == max) { Edge edge = new Edge(Math.Min(triangle.I1, triangle.I2), Math.Max(triangle.I1, triangle.I2)); int i; if (!edges.TryGetValue(edge, out i)) { subdividedPositions.Add((v1 + v2) * 0.5); i = subdividedPositions.Count - 1; edges.Add(edge, i); } triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I1, i, triangle.I0)); triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I2, triangle.I0)); } else if (g2 == max) { Edge edge = new Edge(Math.Min(triangle.I2, triangle.I0), Math.Max(triangle.I2, triangle.I0)); int i; if (!edges.TryGetValue(edge, out i)) { subdividedPositions.Add((v2 + v0) * 0.5); i = subdividedPositions.Count - 1; edges.Add(edge, i); } triangles.Enqueue(new TriangleIndicesUnsignedInt(triangle.I2, i, triangle.I1)); triangles.Enqueue(new TriangleIndicesUnsignedInt(i, triangle.I0, triangle.I1)); } } else { done.Enqueue(triangle); } } // // New indices // IndicesUnsignedInt subdividedIndices = new IndicesUnsignedInt(done.Count * 3); foreach (TriangleIndicesUnsignedInt t in done) { subdividedIndices.AddTriangle(t); } return(new TriangleMeshSubdivisionResult(subdividedPositions, subdividedIndices)); }
public void AddTriangle(TriangleIndicesUnsignedInt triangle) { _values.Add(triangle.UI0); _values.Add(triangle.UI1); _values.Add(triangle.UI2); }