public ConvexHullSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; SetCamera(new Vector3F(0, 1, 10), 0, 0); // Generate random points. var points = new List <Vector3F>(); for (int i = 0; i < 100; i++) { points.Add(RandomHelper.Random.NextVector3F(-1, 1)); } // Apply random transformation to points to make this sample more interesting. Matrix44F transform = new Matrix44F( Matrix33F.CreateRotation(RandomHelper.Random.NextQuaternionF()) * Matrix33F.CreateScale(RandomHelper.Random.NextVector3F(0.1f, 2f)), RandomHelper.Random.NextVector3F(-1, 1)); for (int i = 0; i < points.Count; i++) { points[i] = transform.TransformPosition(points[i]); } // Compute convex hull. The result is the mesh of the hull represented as a // Doubly-Connected Edge List (DCEL). DcelMesh convexHull = GeometryHelper.CreateConvexHull(points); // We don't need the DCEL representation. Let's store the hull as a simpler triangle mesh. TriangleMesh convexHullMesh = convexHull.ToTriangleMesh(); // Compute a tight-fitting oriented bounding box. Vector3F boundingBoxExtent; // The bounding box dimensions (widths in X, Y and Z). Pose boundingBoxPose; // The pose (world space position and orientation) of the bounding box. GeometryHelper.ComputeBoundingBox(points, out boundingBoxExtent, out boundingBoxPose); // (Note: The GeometryHelper also contains methods to compute a bounding sphere.) var debugRenderer = GraphicsScreen.DebugRenderer; foreach (var point in points) { debugRenderer.DrawPoint(point, Color.White, true); } debugRenderer.DrawShape(new TriangleMeshShape(convexHullMesh), Pose.Identity, Vector3F.One, Color.Violet, false, false); debugRenderer.DrawBox(boundingBoxExtent.X, boundingBoxExtent.Y, boundingBoxExtent.Z, boundingBoxPose, Color.Red, true, false); }
/// <summary> /// Projects a position from world space into screen space. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="position">The position in view space.</param> /// <param name="projection">The projection matrix.</param> /// <returns> /// The position in screen space: The x- and y-components define the pixel position. The /// z-component defines the depth in clip space mapped to the range /// [<see cref="Viewport.MinDepth"/>, <see cref="Viewport.MaxDepth"/>] (usually [0, 1]). /// </returns> public static Vector3F Project(this Viewport viewport, Vector3F position, Matrix44F projection) { // Transform position to clip space. (TransformPosition() transforms the position // to clip space and performs the homogeneous divide.) Vector3F positionClip = projection.TransformPosition(position); Vector3F positionScreen = new Vector3F { X = (1f + positionClip.X) * 0.5f * viewport.Width + viewport.X, Y = (1f - positionClip.Y) * 0.5f * viewport.Height + viewport.Y, Z = positionClip.Z * (viewport.MaxDepth - viewport.MinDepth) + viewport.MinDepth }; return(positionScreen); }
/// <summary> /// Projects a position from world space into viewport. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="position">The position in view space.</param> /// <param name="projection">The projection matrix.</param> /// <returns> /// The position in the viewport: The x- and y-components define the pixel position /// in the range [0, viewport width/height]. The z-component defines the depth in clip space. /// </returns> internal static Vector3F ProjectToViewport(this Viewport viewport, Vector3F position, Matrix44F projection) { // Transform position to clip space. (TransformPosition() transforms the position // to clip space and performs the homogeneous divide.) Vector3F positionClip = projection.TransformPosition(position); Vector3F positionScreen = new Vector3F { X = (1f + positionClip.X) * 0.5f * viewport.Width, Y = (1f - positionClip.Y) * 0.5f * viewport.Height, Z = positionClip.Z, }; return(positionScreen); }
/// <summary> /// Transforms all vertices by the given matrix. /// </summary> /// <param name="matrix">The transformation matrix.</param> public void Transform(Matrix44F matrix) { if (Vertices == null) { return; } int numberOfVertices = Vertices.Count; for (int i = 0; i < numberOfVertices; i++) { Vertices[i] = matrix.TransformPosition(Vertices[i]); } }
public static Vector3F Unproject(this Viewport viewport, Vector3F position, Matrix44F projection) { Matrix44F fromClipSpace = projection.Inverse; Vector3F positionClip = new Vector3F { X = (position.X - viewport.X) / viewport.Width * 2f - 1f, Y = -((position.Y - viewport.Y) / viewport.Height * 2f - 1f), Z = (position.Z - viewport.MinDepth) / (viewport.MaxDepth - viewport.MinDepth), }; // Transform position from clip space to the desired coordinate space. // (TransformPosition() undoes the homogeneous divide and transforms the // position from clip space to the desired coordinate space.) return(fromClipSpace.TransformPosition(positionClip)); }
public ConvexHullSample(Microsoft.Xna.Framework.Game game) : base(game) { SampleFramework.IsMouseVisible = false; GraphicsScreen.ClearBackground = true; GraphicsScreen.BackgroundColor = Color.CornflowerBlue; SetCamera(new Vector3F(0, 1, 10), 0, 0); // Generate random points. var points = new List<Vector3F>(); for (int i = 0; i < 100; i++) points.Add(RandomHelper.Random.NextVector3F(-1, 1)); // Apply random transformation to points to make this sample more interesting. Matrix44F transform = new Matrix44F( Matrix33F.CreateRotation(RandomHelper.Random.NextQuaternionF()) * Matrix33F.CreateScale(RandomHelper.Random.NextVector3F(0.1f, 2f)), RandomHelper.Random.NextVector3F(-1, 1)); for (int i = 0; i < points.Count; i++) points[i] = transform.TransformPosition(points[i]); // Compute convex hull. The result is the mesh of the hull represented as a // Doubly-Connected Edge List (DCEL). DcelMesh convexHull = GeometryHelper.CreateConvexHull(points); // We don't need the DCEL representation. Let's store the hull as a simpler triangle mesh. TriangleMesh convexHullMesh = convexHull.ToTriangleMesh(); // Compute a tight-fitting oriented bounding box. Vector3F boundingBoxExtent; // The bounding box dimensions (widths in X, Y and Z). Pose boundingBoxPose; // The pose (world space position and orientation) of the bounding box. GeometryHelper.ComputeBoundingBox(points, out boundingBoxExtent, out boundingBoxPose); // (Note: The GeometryHelper also contains methods to compute a bounding sphere.) var debugRenderer = GraphicsScreen.DebugRenderer; foreach (var point in points) debugRenderer.DrawPoint(point, Color.White, true); debugRenderer.DrawShape(new TriangleMeshShape(convexHullMesh), Pose.Identity, Vector3F.One, Color.Violet, false, false); debugRenderer.DrawBox(boundingBoxExtent.X, boundingBoxExtent.Y, boundingBoxExtent.Z, boundingBoxPose, Color.Red, true, false); }
/// <summary> /// Projects a position from world space into viewport. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="position">The position in view space.</param> /// <param name="projection">The projection matrix.</param> /// <returns> /// The position in the viewport: The x- and y-components define the pixel position /// in the range [0, viewport width/height]. The z-component defines the depth in clip space. /// </returns> internal static Vector3F ProjectToViewport(this Viewport viewport, Vector3F position, Matrix44F projection) { // Transform position to clip space. (TransformPosition() transforms the position // to clip space and performs the homogeneous divide.) Vector3F positionClip = projection.TransformPosition(position); Vector3F positionScreen = new Vector3F { X = (1f + positionClip.X) * 0.5f * viewport.Width, Y = (1f - positionClip.Y) * 0.5f * viewport.Height, Z = positionClip.Z, }; return positionScreen; }
/// <summary> /// Projects a position from world space into screen space. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="position">The position in view space.</param> /// <param name="projection">The projection matrix.</param> /// <returns> /// The position in screen space: The x- and y-components define the pixel position. The /// z-component defines the depth in clip space mapped to the range /// [<see cref="Viewport.MinDepth"/>, <see cref="Viewport.MaxDepth"/>] (usually [0, 1]). /// </returns> public static Vector3F Project(this Viewport viewport, Vector3F position, Matrix44F projection) { // Transform position to clip space. (TransformPosition() transforms the position // to clip space and performs the homogeneous divide.) Vector3F positionClip = projection.TransformPosition(position); Vector3F positionScreen = new Vector3F { X = (1f + positionClip.X) * 0.5f * viewport.Width + viewport.X, Y = (1f - positionClip.Y) * 0.5f * viewport.Height + viewport.Y, Z = positionClip.Z * (viewport.MaxDepth - viewport.MinDepth) + viewport.MinDepth }; return positionScreen; }
/// <summary> /// Draws the batched primitives. /// </summary> /// <param name="context">The render context.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="context"/> is <see langword="null"/>. /// </exception> public void Render(RenderContext context) { if (context == null) { throw new ArgumentNullException("context"); } if (Effect == null || _primitives.Count == 0) { return; } context.Validate(Effect); context.ThrowIfCameraMissing(); var graphicsService = context.GraphicsService; var graphicsDevice = graphicsService.GraphicsDevice; var savedRenderState = new RenderStateSnapshot(graphicsDevice); if (AutoRasterizerState) { graphicsDevice.RasterizerState = DrawWireFrame ? GraphicsHelper.RasterizerStateWireFrame : GraphicsHelper.RasterizerStateCullCounterClockwise; } // Sort primitives if necessary. Matrix44F view = context.CameraNode.View; if (SortBackToFront && _usesTransparency) { // Update depth (distance from camera). foreach (var job in _primitives) { Vector3F position = job.Pose.Position; job.Depth = view.TransformPosition(position).Z; } _primitives.Sort(PrimitiveJobDepthComparer.Instance); } // Reset the texture stages. If a floating point texture is set, we get exceptions // when a sampler with bilinear filtering is set. graphicsDevice.ResetTextures(); Effect.LightingEnabled = !DrawWireFrame; Effect.TextureEnabled = false; Effect.View = (Matrix)view; Effect.Projection = context.CameraNode.Camera.Projection; foreach (var job in _primitives) { Effect.Alpha = job.Color.A / 255.0f; Effect.DiffuseColor = job.Color.ToVector3(); Effect.VertexColorEnabled = false; switch (job.Type) { case PrimitiveJobType.Box: RenderBox(graphicsService, job); break; case PrimitiveJobType.Capsule: RenderCapsule(graphicsService, job); break; case PrimitiveJobType.Cone: RenderCone(graphicsService, job); break; case PrimitiveJobType.Cylinder: RenderCylinder(graphicsService, job); break; case PrimitiveJobType.ViewVolume: RenderViewVolume(job, context); break; case PrimitiveJobType.Sphere: RenderSphere(graphicsService, job, context); break; case PrimitiveJobType.Shape: RenderShape(graphicsDevice, job); break; case PrimitiveJobType.Model: RenderModel(graphicsDevice, job); break; case PrimitiveJobType.Submesh: RenderSubmesh(job); break; } } if (DrawWireFrame) { _lineBatch.Render(context); _lineBatch.Clear(); } savedRenderState.Restore(); }
protected override void OnProcess(RenderContext context) { context.ThrowIfCameraMissing(); var graphicsDevice = GraphicsService.GraphicsDevice; var renderTargetPool = GraphicsService.RenderTargetPool; var cameraNode = context.CameraNode; var source = context.SourceTexture; var target = context.RenderTarget; var viewport = context.Viewport; Projection projection = cameraNode.Camera.Projection; Matrix44F projMatrix = projection; float near = projection.Near; float far = projection.Far; _frustumInfoParameter.SetValue(new Vector4( projection.Left / near, projection.Top / near, (projection.Right - projection.Left) / near, (projection.Bottom - projection.Top) / near)); _numberOfAOSamplesParameter.SetValue(NumberOfSamples); // The height of a 1 unit object 1 unit in front of the camera. // (Compute 0.5 unit multiply by 2 and divide by 2 to convert from [-1, 1] to [0, 1] range.) float projectionScale = projMatrix.TransformPosition(new Vector3F(0, 0.5f, -1)).Y - projMatrix.TransformPosition(new Vector3F(0, 0, -1)).Y; _aoParameters0.SetValue(new Vector4( projectionScale, Radius, Strength / (float)Math.Pow(Radius, 6), Bias)); _aoParameters1.SetValue(new Vector4( viewport.Width, viewport.Height, far, MaxOcclusion)); _aoParameters2.SetValue(new Vector4( SampleDistribution, 1.0f / (EdgeSoftness + 0.001f) * far, BlurScale, MinBias)); context.ThrowIfGBuffer0Missing(); _gBuffer0Parameter.SetValue(context.GBuffer0); //var view = cameraNode.View; //_viewParameter.SetValue((Matrix)view); //_gBuffer1Parameter.SetValue(context.GBuffer1); // We use two temporary render targets. var format = new RenderTargetFormat( context.Viewport.Width, context.Viewport.Height, false, SurfaceFormat.Color, DepthFormat.None); var tempTarget0 = renderTargetPool.Obtain2D(format); var tempTarget1 = renderTargetPool.Obtain2D(format); // Create SSAO. graphicsDevice.SetRenderTarget(tempTarget0); _createAOPass.Apply(); graphicsDevice.Clear(new Color(1.0f, 1.0f, 1.0f, 1.0f)); graphicsDevice.DrawFullScreenQuad(); // Horizontal blur. graphicsDevice.SetRenderTarget(tempTarget1); _occlusionTextureParameter.SetValue(tempTarget0); _blurHorizontalPass.Apply(); graphicsDevice.DrawFullScreenQuad(); // Vertical blur graphicsDevice.SetRenderTarget(target); graphicsDevice.Viewport = viewport; _occlusionTextureParameter.SetValue(tempTarget1); if (!CombineWithSource) { _blurVerticalPass.Apply(); } else { if (_sourceTextureParameter != null) { _sourceTextureParameter.SetValue(source); } if (TextureHelper.IsFloatingPointFormat(source.Format)) { graphicsDevice.SamplerStates[0] = SamplerState.PointClamp; } else { graphicsDevice.SamplerStates[0] = SamplerState.LinearClamp; } _blurVerticalAndCombinePass.Apply(); } graphicsDevice.DrawFullScreenQuad(); // Clean up. renderTargetPool.Recycle(tempTarget0); renderTargetPool.Recycle(tempTarget1); if (_sourceTextureParameter != null) { _sourceTextureParameter.SetValue((Texture2D)null); } _occlusionTextureParameter.SetValue((Texture2D)null); _gBuffer0Parameter.SetValue((Texture2D)null); //_gBuffer1Parameter.SetValue((Texture2D)null); context.SourceTexture = source; context.RenderTarget = target; context.Viewport = viewport; }
/// <summary> /// Transforms all vertices by the given matrix. /// </summary> /// <param name="matrix">The transformation matrix.</param> public void Transform(Matrix44F matrix) { if (Vertices == null) return; int numberOfVertices = Vertices.Count; for (int i = 0; i < numberOfVertices; i++) Vertices[i] = matrix.TransformPosition(Vertices[i]); }
private static void CacheVertexBuffer(FigureNode node, GraphicsDevice graphicsDevice) { var figureRenderData = node.Figure.RenderData; var nodeRenderData = (FigureNodeRenderData)node.RenderData; Vector3F[] positions = figureRenderData.Vertices.Array; #region ----- Cache vertex/index buffer for fill. ----- var fillIndices = figureRenderData.FillIndices; if (fillIndices != null && fillIndices.Count > 0 && !Numeric.IsZero(node.FillAlpha)) { // This code is similar to the code in Fill(). Matrix44F world = node.PoseWorld * Matrix44F.CreateScale(node.ScaleWorld); Vector3F color3F = node.FillColor * node.FillAlpha; Color color = new Color(color3F.X, color3F.Y, color3F.Z, node.FillAlpha); int numberOfVertices = figureRenderData.Vertices.Count; int numberOfIndices = figureRenderData.FillIndices.Count; VertexPositionColor[] vertices = new VertexPositionColor[numberOfVertices]; // Copy all vertices. for (int i = 0; i < numberOfVertices; i++) { vertices[i].Position = (Vector3)world.TransformPosition(positions[i]); vertices[i].Color = color; } nodeRenderData.FillVertexBuffer = new VertexBuffer( graphicsDevice, VertexPositionColor.VertexDeclaration, numberOfVertices, BufferUsage.WriteOnly); nodeRenderData.FillVertexBuffer.SetData(vertices); if (numberOfVertices <= ushort.MaxValue) { // Copy all indices from int[] to ushort[]. int[] int32Indices = figureRenderData.FillIndices.Array; ushort[] indices = new ushort[numberOfIndices]; for (int i = 0; i < numberOfIndices; i++) { indices[i] = (ushort)int32Indices[i]; } nodeRenderData.FillIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.SixteenBits, numberOfIndices, BufferUsage.WriteOnly); nodeRenderData.FillIndexBuffer.SetData(indices); } else { nodeRenderData.FillIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.ThirtyTwoBits, numberOfIndices, BufferUsage.WriteOnly); // Note: The FillIndices.Array may contain more than numberOfIndices entries! --> // Specify number of indices explicitly! nodeRenderData.FillIndexBuffer.SetData(figureRenderData.FillIndices.Array, 0, numberOfIndices); } } #endregion #region ----- Cache vertex/index buffer for stroke. ----- var strokeIndices = figureRenderData.StrokeIndices; if (strokeIndices != null && strokeIndices.Count > 0 && !Numeric.IsZero(node.StrokeThickness) && !Numeric.IsZero(node.StrokeAlpha)) { // This code is similar to the code in Stroke() and in the ctor. Matrix44F world = node.PoseWorld * Matrix44F.CreateScale(node.ScaleWorld); float thickness = node.StrokeThickness; Vector3F color3F = node.StrokeColor * node.StrokeAlpha; HalfVector4 color = new HalfVector4(color3F.X, color3F.Y, color3F.Z, node.StrokeAlpha); Vector4F dash = node.StrokeDashPattern * node.StrokeThickness; bool usesDashPattern = (dash.Y + dash.Z) != 0; HalfVector4 dashSum = new HalfVector4( dash.X, dash.X + dash.Y, dash.X + dash.Y + dash.Z, dash.X + dash.Y + dash.Z + dash.W); // Convert to vertices. float lastDistance = 0; Vector3F lastPosition = new Vector3F(float.NaN); Vector3F lastWorld = new Vector3F(); HalfVector4 data0 = new HalfVector4(0, 1, thickness, 0); HalfVector4 data1 = new HalfVector4(0, 0, thickness, 0); HalfVector4 data2 = new HalfVector4(1, 0, thickness, 0); HalfVector4 data3 = new HalfVector4(1, 1, thickness, 0); int[] figureIndices = strokeIndices.Array; int numberOfLineSegments = strokeIndices.Count / 2; int numberOfVertices = numberOfLineSegments * 4; StrokeVertex[] vertices = new StrokeVertex[numberOfVertices]; for (int i = 0; i < numberOfLineSegments; i++) { int startIndex = figureIndices[i * 2 + 0]; int endIndex = figureIndices[i * 2 + 1]; Vector3F start = positions[startIndex]; Vector3F end = positions[endIndex]; bool notConnectedWithLast = start != lastPosition; lastPosition = end; Vector3F startWorld = notConnectedWithLast ? world.TransformPosition(start) : lastWorld; Vector3F endWorld = world.TransformPosition(end); lastWorld = endWorld; // Compute start/end distances of lines from beginning of line strip // for dash patterns. float startDistance = 0; float endDistance = 1; if (usesDashPattern) { Debug.Assert(node.DashInWorldSpace, "Cannot cache vertex buffer for figure with screen-space dash patterns."); if (notConnectedWithLast) { lastDistance = 0; } startDistance = lastDistance; endDistance = startDistance + (endWorld - startWorld).Length; lastDistance = endDistance; // The shader needs to know that DashInWorldSpace is true. To avoid // effect parameter changes, we store the value in the sign of the distance! startDistance = -startDistance; endDistance = -endDistance; } Vector4 s = new Vector4(startWorld.X, startWorld.Y, startWorld.Z, startDistance); Vector4 e = new Vector4(endWorld.X, endWorld.Y, endWorld.Z, endDistance); vertices[i * 4 + 0].Start = s; vertices[i * 4 + 0].End = e; vertices[i * 4 + 0].Data = data0; vertices[i * 4 + 0].Color = color; vertices[i * 4 + 0].Dash = dashSum; vertices[i * 4 + 1].Start = s; vertices[i * 4 + 1].End = e; vertices[i * 4 + 1].Data = data1; vertices[i * 4 + 1].Color = color; vertices[i * 4 + 1].Dash = dashSum; vertices[i * 4 + 2].Start = s; vertices[i * 4 + 2].End = e; vertices[i * 4 + 2].Data = data2; vertices[i * 4 + 2].Color = color; vertices[i * 4 + 2].Dash = dashSum; vertices[i * 4 + 3].Start = s; vertices[i * 4 + 3].End = e; vertices[i * 4 + 3].Data = data3; vertices[i * 4 + 3].Color = color; vertices[i * 4 + 3].Dash = dashSum; } nodeRenderData.StrokeVertexBuffer = new VertexBuffer( graphicsDevice, StrokeVertex.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly); nodeRenderData.StrokeVertexBuffer.SetData(vertices); // Create stroke indices. int numberOfIndices = numberOfLineSegments * 6; if (numberOfVertices <= ushort.MaxValue) { ushort[] indices = new ushort[numberOfIndices]; for (int i = 0; i < numberOfLineSegments; i++) { // Create index buffer for quad (= two triangles, clockwise). // 1--2 // | /| // |/ | // 0--3 indices[i * 6 + 0] = (ushort)(i * 4 + 0); indices[i * 6 + 1] = (ushort)(i * 4 + 1); indices[i * 6 + 2] = (ushort)(i * 4 + 2); indices[i * 6 + 3] = (ushort)(i * 4 + 0); indices[i * 6 + 4] = (ushort)(i * 4 + 2); indices[i * 6 + 5] = (ushort)(i * 4 + 3); } nodeRenderData.StrokeIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.SixteenBits, numberOfIndices, BufferUsage.WriteOnly); nodeRenderData.StrokeIndexBuffer.SetData(indices); } else { int[] indices = new int[numberOfIndices]; for (int i = 0; i < numberOfLineSegments; i++) { // Create index buffer for quad (= two triangles, clockwise). // 1--2 // | /| // |/ | // 0--3 indices[i * 6 + 0] = i * 4 + 0; indices[i * 6 + 1] = i * 4 + 1; indices[i * 6 + 2] = i * 4 + 2; indices[i * 6 + 3] = i * 4 + 0; indices[i * 6 + 4] = i * 4 + 2; indices[i * 6 + 5] = i * 4 + 3; } nodeRenderData.StrokeIndexBuffer = new IndexBuffer( graphicsDevice, IndexElementSize.ThirtyTwoBits, numberOfIndices, BufferUsage.WriteOnly); nodeRenderData.StrokeIndexBuffer.SetData(indices); } } #endregion nodeRenderData.IsValid = true; }
private void Fill(FigureNode node, ArrayList <Vector3F> vertices, ArrayList <int> indices) { if (_mode != RenderMode.Fill) { Flush(); _fillEffect.CurrentTechnique.Passes[0].Apply(); _mode = RenderMode.Fill; } // Use cached vertex buffer if available. var nodeRenderData = node.RenderData as FigureNodeRenderData; if (nodeRenderData != null && nodeRenderData.IsValid) { Flush(); var graphicsDevice = _graphicsService.GraphicsDevice; graphicsDevice.SetVertexBuffer(nodeRenderData.FillVertexBuffer); graphicsDevice.Indices = nodeRenderData.FillIndexBuffer; int primitiveCount = nodeRenderData.FillIndexBuffer.IndexCount / 3; #if MONOGAME graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, primitiveCount); #else int vertexCount = nodeRenderData.FillVertexBuffer.VertexCount; graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexCount, 0, primitiveCount); #endif return; } Matrix44F world = node.PoseWorld * Matrix44F.CreateScale(node.ScaleWorld); Vector3F color3F = node.FillColor * node.FillAlpha; Color color = new Color(color3F.X, color3F.Y, color3F.Z, node.FillAlpha); var numberOfVertices = vertices.Count; var numberOfIndices = indices.Count; VertexPositionColor[] batchVertices = _fillBatch.Vertices; ushort[] batchIndices = _fillBatch.Indices; if (numberOfVertices > batchVertices.Length || numberOfIndices > batchIndices.Length) { string message = string.Format( CultureInfo.InvariantCulture, "The BufferSize of this FigureRenderer is not large enough to render the FigureNode (Name = \"{0}\").", node.Name); throw new GraphicsException(message); } int vertexBufferStartIndex, indexBufferStartIndex; _fillBatch.Submit(PrimitiveType.TriangleList, numberOfVertices, numberOfIndices, out vertexBufferStartIndex, out indexBufferStartIndex); // Copy all vertices. Vector3F[] vertexArray = vertices.Array; for (int i = 0; i < numberOfVertices; i++) { batchVertices[vertexBufferStartIndex + i].Position = (Vector3)(world.TransformPosition(vertexArray[i])); batchVertices[vertexBufferStartIndex + i].Color = color; } // Copy all indices. int[] indexArray = indices.Array; for (int i = 0; i < numberOfIndices; i++) { batchIndices[indexBufferStartIndex + i] = (ushort)(vertexBufferStartIndex + indexArray[i]); } }