public static Submesh CreateIcosphere(GraphicsDevice graphicsDevice, int numberOfSubdivisions) { if (graphicsDevice == null) { throw new ArgumentNullException("graphicsDevice"); } if (numberOfSubdivisions < 1) { throw new ArgumentOutOfRangeException("numberOfSubdivisions", "numberOfSegments must be greater than 0"); } var submesh = new Submesh { PrimitiveType = PrimitiveType.TriangleList, }; var mesh = GeometryHelper.CreateIcosphere(numberOfSubdivisions, false); int numberOfVertices = mesh.Vertices.Count; var vertexData = new VertexPositionNormal[numberOfVertices]; for (int i = 0; i < numberOfVertices; i++) { Vector3 v = (Vector3)mesh.Vertices[i]; vertexData[i] = new VertexPositionNormal(v, v); } submesh.VertexBuffer = new VertexBuffer( graphicsDevice, VertexPositionNormal.VertexDeclaration, vertexData.Length, BufferUsage.None); submesh.VertexBuffer.SetData(vertexData); submesh.VertexCount = submesh.VertexBuffer.VertexCount; int numberOfTriangles = mesh.NumberOfTriangles; int numberOfIndices = mesh.Indices.Count; var indexData = new ushort[numberOfIndices]; for (int i = 0; i < numberOfTriangles; i++) { // Flip vertex order. (DigitalRune Geometry uses CCW, XNA uses CW.) indexData[3 * i + 0] = (ushort)mesh.Indices[3 * i + 0]; indexData[3 * i + 2] = (ushort)mesh.Indices[3 * i + 1]; indexData[3 * i + 1] = (ushort)mesh.Indices[3 * i + 2]; } submesh.IndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.SixteenBits, indexData.Length, BufferUsage.None); submesh.IndexBuffer.SetData(indexData); submesh.PrimitiveCount = indexData.Length / 3; return(submesh); }
internal static void CreateVertexBuffer(GraphicsDevice graphicsDevice, TriangleMesh mesh, float angleLimit, out VertexBuffer vertexBuffer, out PrimitiveType primitiveType, out int primitiveCount) { // Note: We do not use shared vertices and an IndexBuffer because a vertex can be used by // several triangles with different normals. if (graphicsDevice == null) throw new ArgumentNullException("graphicsDevice"); if (mesh == null) throw new ArgumentNullException("mesh"); var numberOfTriangles = mesh.NumberOfTriangles; if (numberOfTriangles == 0) { primitiveType = PrimitiveType.TriangleList; primitiveCount = 0; vertexBuffer = null; return; } primitiveType = PrimitiveType.TriangleList; primitiveCount = numberOfTriangles; int vertexCount = numberOfTriangles * 3; // Create vertex data for a triangle list. var vertices = new VertexPositionNormal[vertexCount]; // Create vertex normals. var normals = mesh.ComputeNormals(false, angleLimit); for (int i = 0; i < numberOfTriangles; i++) { var i0 = mesh.Indices[i * 3 + 0]; var i1 = mesh.Indices[i * 3 + 1]; var i2 = mesh.Indices[i * 3 + 2]; var v0 = mesh.Vertices[i0]; var v1 = mesh.Vertices[i1]; var v2 = mesh.Vertices[i2]; Vector3 n0, n1, n2; if (angleLimit < 0) { // If the angle limit is negative, ComputeNormals() returns one normal per vertex. n0 = normals[i0]; n1 = normals[i1]; n2 = normals[i2]; } else { // If the angle limits is >= 0, ComputeNormals() returns 3 normals per triangle. n0 = normals[i * 3 + 0]; n1 = normals[i * 3 + 1]; n2 = normals[i * 3 + 2]; } // Add new vertex data. // DigitalRune.Geometry uses counter-clockwise front faces. XNA uses // clockwise front faces (CullMode.CullCounterClockwiseFace) per default. // Therefore we change the vertex orientation of the triangles. vertices[i * 3 + 0] = new VertexPositionNormal((Vector3)v0, (Vector3)n0); vertices[i * 3 + 1] = new VertexPositionNormal((Vector3)v2, (Vector3)n2); // v2 instead of v1! vertices[i * 3 + 2] = new VertexPositionNormal((Vector3)v1, (Vector3)n1); } // Create a vertex buffer. vertexBuffer = new VertexBuffer(graphicsDevice, typeof(VertexPositionNormal), vertexCount, BufferUsage.None); vertexBuffer.SetData(vertices); }
public static Submesh CreateHemisphere(GraphicsDevice graphicsDevice, int numberOfSegments) { if (graphicsDevice == null) { throw new ArgumentNullException("graphicsDevice"); } if (numberOfSegments < 3) { throw new ArgumentOutOfRangeException("numberOfSegments", "numberOfSegments must be greater than 2"); } var submesh = new Submesh { PrimitiveType = PrimitiveType.TriangleList, }; // The number of rings. int numberOfRings = numberOfSegments / 4; int numberOfVertices = numberOfSegments * numberOfRings + 1; var vertices = new VertexPositionNormal[numberOfVertices]; // Create rings. float angle = ConstantsF.TwoPi / numberOfSegments; // Next free index in vertices. int i = 0; // Top vertex. vertices[i++] = new VertexPositionNormal(new Vector3(0, 1, 0), new Vector3(0, 1, 0)); // Compute vertices for rings from pole to equator and from the x-axis in // counterclockwise direction (when viewed from top). for (int ring = 0; ring < numberOfRings; ring++) { float upAngle = angle * (ring + 1); float y = (float)Math.Cos(upAngle); float ringRadius = (float)Math.Sin(upAngle); for (int segment = 0; segment < numberOfSegments; segment++) { float x = ringRadius * (float)Math.Cos(angle * segment); float z = ringRadius * (float)Math.Sin(angle * segment); vertices[i++] = new VertexPositionNormal(new Vector3(x, y, z), new Vector3(x, y, z)); } } Debug.Assert(i == numberOfVertices); submesh.VertexBuffer = new VertexBuffer( graphicsDevice, VertexPositionNormal.VertexDeclaration, vertices.Length, BufferUsage.None); submesh.VertexBuffer.SetData(vertices); submesh.VertexCount = submesh.VertexBuffer.VertexCount; // Build array of indices. int numberOfTriangles = numberOfSegments // Triangles in top cap. + numberOfSegments * 2 * (numberOfRings - 1); int numberOfIndices = 3 * numberOfTriangles; var indices = new ushort[numberOfIndices]; i = 0; // Indices for top cap. for (int segment = 0; segment < numberOfSegments; segment++) { indices[i++] = 0; indices[i++] = (ushort)(segment + 1); if (segment + 1 < numberOfSegments) { indices[i++] = (ushort)(segment + 2); } else { indices[i++] = 1; // Wrap around to first vertex of the first ring. } } // Indices for rings between the caps. for (int ring = 1; ring < numberOfRings; ring++) { for (int segment = 0; segment < numberOfSegments; segment++) { // Each segment has 2 triangles. if (segment + 1 < numberOfSegments) { indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment); indices[i++] = (ushort)(1 + ring * numberOfSegments + segment); indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1); indices[i++] = (ushort)(1 + ring * numberOfSegments + segment + 1); indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment + 1); indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment); } else { // Handle wrap around. indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment); indices[i++] = (ushort)(1 + ring * numberOfSegments + segment); indices[i++] = (ushort)(1 + ring * numberOfSegments); indices[i++] = (ushort)(1 + ring * numberOfSegments); indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments); indices[i++] = (ushort)(1 + (ring - 1) * numberOfSegments + segment); } } } Debug.Assert(i == numberOfIndices); submesh.IndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.None); submesh.IndexBuffer.SetData(indices); submesh.PrimitiveCount = indices.Length / 3; return(submesh); }