/// <inheritdoc/> public void Generate(IServiceRegistry services, Model model) { if (model is null) { throw new ArgumentNullException(nameof(model)); } var needsTempDevice = false; var graphicsDevice = services?.GetSafeServiceAs <IGraphicsDeviceService>().GraphicsDevice; if (graphicsDevice is null) { graphicsDevice = GraphicsDevice.New(); needsTempDevice = true; } var data = CreatePrimitiveMeshData(); if (data.Vertices.Length == 0) { throw new InvalidOperationException("Invalid GeometricPrimitive [{0}]. Expecting non-zero Vertices array."); } // Translate if necessary if (LocalOffset != Vector3.Zero) { for (var index = 0; index < data.Vertices.Length; index++) { data.Vertices[index].Position += LocalOffset; } } // Scale if necessary if (Scale != Vector3.One) { var inverseMatrix = Matrix.Scaling(Scale); inverseMatrix.Invert(); for (var index = 0; index < data.Vertices.Length; index++) { data.Vertices[index].Position *= Scale; // TODO: Shouldn't be TransformNormal? Vector3.TransformCoordinate(ref data.Vertices[index].Normal, ref inverseMatrix, out data.Vertices[index].Normal); } } var boundingBox = BoundingBox.Empty; for (int i = 0; i < data.Vertices.Length; i++) { BoundingBox.Merge(ref boundingBox, ref data.Vertices[i].Position, out boundingBox); } BoundingSphere boundingSphere; unsafe { fixed(void *verticesPtr = data.Vertices) BoundingSphere.FromPoints((IntPtr)verticesPtr, 0, data.Vertices.Length, VertexPositionNormalTexture.Size, out boundingSphere); } var originalLayout = data.Vertices[0].GetLayout(); // Generate Tangent/BiNormal vectors var resultWithTangentBiNormal = VertexHelper.GenerateTangentBinormal(originalLayout, data.Vertices, data.Indices); // Generate Multi texturing coords var maxTexCoords = MathUtil.Clamp(NumberOfTextureCoordinates, 1, 10) - 1; var result = VertexHelper.GenerateMultiTextureCoordinates(resultWithTangentBiNormal, vertexStride: 0, maxTexCoords); var meshDraw = new MeshDraw(); var layout = result.Layout; var vertexBuffer = result.VertexBuffer; var indices = data.Indices; if (indices.Length < 0xFFFF) { // 16-bit indices var indicesShort = new ushort[indices.Length]; for (int i = 0; i < indicesShort.Length; i++) { indicesShort[i] = (ushort)indices[i]; } var indexBuffer = Buffer.Index.New(graphicsDevice, indicesShort) .RecreateWith(indicesShort); meshDraw.IndexBuffer = new IndexBufferBinding(indexBuffer, is32Bit: false, indices.Length); if (needsTempDevice) { var indexData = BufferData.New(BufferFlags.IndexBuffer, indicesShort); meshDraw.IndexBuffer = new IndexBufferBinding(indexData.ToSerializableVersion(), is32Bit: false, indices.Length); } } else { // 32-bit indices var indexBuffer = Buffer.Index.New(graphicsDevice, indices) .RecreateWith(indices); meshDraw.IndexBuffer = new IndexBufferBinding(indexBuffer, is32Bit: true, indices.Length); if (needsTempDevice) { var indexData = BufferData.New(BufferFlags.IndexBuffer, indices); meshDraw.IndexBuffer = new IndexBufferBinding(indexData.ToSerializableVersion(), is32Bit: true, indices.Length); } } var geometryBuffer = Buffer.New(graphicsDevice, vertexBuffer, BufferFlags.VertexBuffer) .RecreateWith(vertexBuffer); meshDraw.VertexBuffers = new[] { new VertexBufferBinding(geometryBuffer, layout, data.Vertices.Length) }; if (needsTempDevice) { var vertexData = BufferData.New(BufferFlags.VertexBuffer, vertexBuffer); meshDraw.VertexBuffers = new[] { new VertexBufferBinding(vertexData.ToSerializableVersion(), layout, data.Vertices.Length) }; } meshDraw.DrawCount = indices.Length; meshDraw.PrimitiveType = PrimitiveType.TriangleList; var mesh = new Mesh { Draw = meshDraw, BoundingBox = boundingBox, BoundingSphere = boundingSphere }; model.BoundingBox = boundingBox; model.BoundingSphere = boundingSphere; model.Add(mesh); if (MaterialInstance?.Material is not null) { model.Materials.Add(MaterialInstance); } if (needsTempDevice) { graphicsDevice.Dispose(); } }
public void Generate(IServiceRegistry services, Model model) { if (model == null) { throw new ArgumentNullException(nameof(model)); } var needsTempDevice = false; var graphicsDevice = services?.GetSafeServiceAs <IGraphicsDeviceService>().GraphicsDevice; if (graphicsDevice == null) { graphicsDevice = GraphicsDevice.New(); needsTempDevice = true; } var data = CreatePrimitiveMeshData(); if (data.Vertices.Length == 0) { throw new InvalidOperationException("Invalid GeometricPrimitive [{0}]. Expecting non-zero Vertices array"); } //Scale if necessary if (Scale != Vector3.One) { var inverseMatrix = Matrix.Scaling(Scale); inverseMatrix.Invert(); for (var index = 0; index < data.Vertices.Length; index++) { data.Vertices[index].Position *= Scale; Vector3.TransformCoordinate(ref data.Vertices[index].Normal, ref inverseMatrix, out data.Vertices[index].Normal); } } var boundingBox = BoundingBox.Empty; for (int i = 0; i < data.Vertices.Length; i++) { BoundingBox.Merge(ref boundingBox, ref data.Vertices[i].Position, out boundingBox); } BoundingSphere boundingSphere; unsafe { fixed(void *verticesPtr = data.Vertices) BoundingSphere.FromPoints((IntPtr)verticesPtr, 0, data.Vertices.Length, VertexPositionNormalTexture.Size, out boundingSphere); } var originalLayout = data.Vertices[0].GetLayout(); // Generate Tangent/BiNormal vectors var resultWithTangentBiNormal = VertexHelper.GenerateTangentBinormal(originalLayout, data.Vertices, data.Indices); // Generate Multitexcoords var result = VertexHelper.GenerateMultiTextureCoordinates(resultWithTangentBiNormal); var meshDraw = new MeshDraw(); var layout = result.Layout; var vertexBuffer = result.VertexBuffer; var indices = data.Indices; if (indices.Length < 0xFFFF) { var indicesShort = new ushort[indices.Length]; for (int i = 0; i < indicesShort.Length; i++) { indicesShort[i] = (ushort)indices[i]; } meshDraw.IndexBuffer = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indicesShort).RecreateWith(indicesShort), false, indices.Length); if (needsTempDevice) { var indexData = BufferData.New(BufferFlags.IndexBuffer, indicesShort); meshDraw.IndexBuffer = new IndexBufferBinding(indexData.ToSerializableVersion(), false, indices.Length); } } else { if (graphicsDevice.Features.CurrentProfile <= GraphicsProfile.Level_9_3) { throw new InvalidOperationException("Cannot generate more than 65535 indices on feature level HW <= 9.3"); } meshDraw.IndexBuffer = new IndexBufferBinding(Buffer.Index.New(graphicsDevice, indices).RecreateWith(indices), true, indices.Length); if (needsTempDevice) { var indexData = BufferData.New(BufferFlags.IndexBuffer, indices); meshDraw.IndexBuffer = new IndexBufferBinding(indexData.ToSerializableVersion(), true, indices.Length); } } meshDraw.VertexBuffers = new[] { new VertexBufferBinding(Buffer.New(graphicsDevice, vertexBuffer, BufferFlags.VertexBuffer).RecreateWith(vertexBuffer), layout, data.Vertices.Length) }; if (needsTempDevice) { var vertexData = BufferData.New(BufferFlags.VertexBuffer, vertexBuffer); meshDraw.VertexBuffers = new[] { new VertexBufferBinding(vertexData.ToSerializableVersion(), layout, data.Vertices.Length) }; } meshDraw.DrawCount = indices.Length; meshDraw.PrimitiveType = PrimitiveType.TriangleList; var mesh = new Mesh { Draw = meshDraw, BoundingBox = boundingBox, BoundingSphere = boundingSphere }; model.BoundingBox = boundingBox; model.BoundingSphere = boundingSphere; model.Add(mesh); if (MaterialInstance?.Material != null) { model.Materials.Add(MaterialInstance); } if (needsTempDevice) { graphicsDevice.Dispose(); } }