コード例 #1
0
        public void DrawBeziers(int count, Position <float>[] controls, Color <float>[] colors, float[] width, Matrix4x4[] transforms)
        {
            Utility.Assert(controls.Length >= 3 * count && colors.Length >= count && width.Length >= count);
            Utility.Assert(Mode == RenderMode.Draw);

            if (count == 0)
            {
                return;
            }

            TransformMatrix[] transformMatrices = new TransformMatrix[count];
            Equation[]        equations         = new Equation[count];
            Vector4[]         color             = new Vector4[count];

            Vertex[] vertices = new Vertex[4]
            {
                new Vertex()
                {
                    Position = new Vector3(0, 0, 0)
                },
                new Vertex()
                {
                    Position = new Vector3(0, 1, 0)
                },
                new Vertex()
                {
                    Position = new Vector3(1, 1, 0)
                },
                new Vertex()
                {
                    Position = new Vector3(1, 0, 0)
                }
            };

            var size = new Vector2(mCanvasSize.Width, mCanvasSize.Height) * 0.5f;

            for (int index = 0; index < count; index++)
            {
                Vector2[] points = new Vector2[]
                {
                    new Vector2(controls[index * 3 + 0].X, controls[index * 3 + 0].Y),
                    new Vector2(controls[index * 3 + 1].X, controls[index * 3 + 1].Y),
                    new Vector2(controls[index * 3 + 2].X, controls[index * 3 + 2].Y)
                };

                //get bounding box(before transform) of bezier curve
                var box = QuadraticBezierCurve.BoundingBox(points, width[index]);

                //create transform matrix
                transformMatrices[index] = new TransformMatrix()
                {
                    World =
                        Matrix4x4.CreateScale(box.Max.X - box.Min.X, box.Max.Y - box.Min.Y, 1) *
                        Matrix4x4.CreateTranslation(box.Min.X, box.Min.Y, 0) *
                        Transform,
                    Projection = mProjection
                };

                //we need transform the control points to screen space
                var transformMatrix = (transforms == null ? Matrix4x4.Identity : transforms[index]) * Transform * mProjection;

                //transform points
                for (int i = 0; i < 3; i++)
                {
                    points[i]   = (Vector2.Transform(points[i], transformMatrix) + Vector2.One) * size;
                    points[i].Y = mCanvasSize.Height - points[i].Y;
                }

                //get parameter format of bezier curve
                //Q(t) = At^2 + B^t + C
                var parameters = QuadraticBezierCurve.ParameterFormat(points);
                var A          = parameters[0];
                var B          = parameters[1];
                var C          = parameters[2];

                //For point P, when any root of equation(Q'(s) * (P - Q(s)) = 0) is legal, the P is inside the curve
                //The equation full-format is (-2A^2)t^3 + (-3AB)t^2 + (2AP - 2AC - B^2)t + B(P - C) = 0
                //we can use Cardano formula to solve it in pixel shader.
                //but we can cache some calculation for opt.
                var c0 = -2 * Vector2.Dot(A, A);
                var c1 = -3 * Vector2.Dot(A, B);
                var c2 = -2 * Vector2.Dot(A, C) - Vector2.Dot(B, B);
                var c3 = -Vector2.Dot(B, C);

                equations[index] = new Equation()
                {
                    Coefficient0 = new Vector4(c0, c1, c2, c3),
                    Coefficient1 = new Vector4(A.X, A.Y, B.X, B.Y),
                    Coefficient2 = new Vector4(C.X, C.Y, width[index] * width[index] * 0.25f, width[index] * width[index] * 0.25f)
                };

                color[index] = new Vector4(colors[index].Red, colors[index].Green, colors[index].Blue, colors[index].Alpha);
            }

            if (mColorBufferArray == null || mColorBufferArray.ElementCount != count)
            {
                Utility.Dispose(ref mColorBufferArray);
                Utility.Dispose(ref mEquationBufferArray);
                Utility.Dispose(ref mTransformBufferArray);

                Utility.Dispose(ref mColorBufferArrayUsage);
                Utility.Dispose(ref mEquationBufferArrayUsage);
                Utility.Dispose(ref mTransformBufferArrayUsage);

                mColorBufferArray = new GpuBufferArray(
                    Utility.SizeOf <Vector4>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mEquationBufferArray = new GpuBufferArray(
                    Utility.SizeOf <Equation>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTransformBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TransformMatrix>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mColorBufferArrayUsage     = new GpuResourceUsage(mDevice, mColorBufferArray);
                mEquationBufferArrayUsage  = new GpuResourceUsage(mDevice, mEquationBufferArray);
                mTransformBufferArrayUsage = new GpuResourceUsage(mDevice, mTransformBufferArray);
            }

            mColorBufferArray.Update(color);
            mEquationBufferArray.Update(equations);
            mTransformBufferArray.Update(transformMatrices);

            mDrawVertexBuffer.Update(vertices);

            //change shader we use
            mDevice.SetVertexShader(mDrawBeziersVertexShader);
            mDevice.SetPixelShader(mDrawBeziersPixelShader);

            //set vertex buffer
            mDevice.SetVertexBuffer(mDrawVertexBuffer);
            mDevice.SetIndexBuffer(mDrawIndexBuffer);

            //set constant buffer and resource
            mDevice.SetResourceUsage(mColorBufferArrayUsage, 0);
            mDevice.SetResourceUsage(mEquationBufferArrayUsage, 1);
            mDevice.SetResourceUsage(mTransformBufferArrayUsage, 2);

            //drwa indexed instanced
            mDevice.DrawIndexedInstanced(6, count);

            //reset the shader
            mDevice.SetVertexShader(mDrawBezierVertexShader);
            mDevice.SetPixelShader(mDrawBezierPixelShader);
        }
コード例 #2
0
        public void FillBeziers(int count, Position <float>[] controls, Color <float>[] colors, Matrix4x4[] transforms)
        {
            Utility.Assert(controls.Length >= count * 3 && colors.Length >= count * 3);
            Utility.Assert(Mode == RenderMode.Fill);

            if (count == 0)
            {
                return;
            }

            TrianglePoints[] trianglePointsCanvas = new TrianglePoints[count];
            TrianglePoints[] trianglePoints       = new TrianglePoints[count];
            TriangleColors[] triangleColors       = new TriangleColors[count];

            var size = new Vector4(mCanvasSize.Width * 0.5f, mCanvasSize.Height * 0.5f, 0, 0);

            //create triangle points struct
            for (int index = 0; index < count; index++)
            {
                //get transform matrix
                var transformMatrix = (transforms == null ? Matrix4x4.Identity : transforms[index]) * Transform * mProjection;

                //get control points for bezier_i
                var points = new Position <float>[]
                {
                    controls[index * 3 + 0],
                    controls[index * 3 + 1],
                    controls[index * 3 + 2]
                };

                Vector4 FromColor(Color <float> color) => new Vector4(color.Red, color.Green, color.Blue, color.Alpha);

                //create data for bezier_i in shader
                TrianglePoints subTrianglePoints = new TrianglePoints()
                {
                    Position0 = Vector4.Transform(new Vector3(points[0].X, points[0].Y, 0), transformMatrix),
                    Position1 = Vector4.Transform(new Vector3(points[1].X, points[1].Y, 0), transformMatrix),
                    Position2 = Vector4.Transform(new Vector3(points[2].X, points[2].Y, 0), transformMatrix),
                };

                TriangleColors subTriangleColors = new TriangleColors()
                {
                    Color0 = FromColor(colors[index * 3 + 0]),
                    Color1 = FromColor(colors[index * 3 + 1]),
                    Color2 = FromColor(colors[index * 3 + 2])
                };

                TrianglePoints subTrianglePointsCanvas = new TrianglePoints()
                {
                    Position0 = (subTrianglePoints.Position0 + new Vector4(1)) * size,
                    Position1 = (subTrianglePoints.Position1 + new Vector4(1)) * size,
                    Position2 = (subTrianglePoints.Position2 + new Vector4(1)) * size
                };

                subTrianglePointsCanvas.Position0.Y = mCanvasSize.Height - subTrianglePointsCanvas.Position0.Y;
                subTrianglePointsCanvas.Position1.Y = mCanvasSize.Height - subTrianglePointsCanvas.Position1.Y;
                subTrianglePointsCanvas.Position2.Y = mCanvasSize.Height - subTrianglePointsCanvas.Position2.Y;

                trianglePointsCanvas[index] = subTrianglePointsCanvas;
                trianglePoints[index]       = subTrianglePoints;
                triangleColors[index]       = subTriangleColors;
            }

            if (mTrianglePointsBufferArray == null || mTrianglePointsBufferArray.ElementCount != count)
            {
                Utility.Dispose(ref mTrianglePointsBufferArray);
                Utility.Dispose(ref mTriangleColorsBufferArray);
                Utility.Dispose(ref mTrianglePointsCanvasBufferArray);

                Utility.Dispose(ref mTrianglePointsBufferArrayUsage);
                Utility.Dispose(ref mTriangleColorsBufferArrayUsage);
                Utility.Dispose(ref mTrianglePointsCanvasBufferArrayUsage);

                mTrianglePointsBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TrianglePoints>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTriangleColorsBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TrianglePoints>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTrianglePointsCanvasBufferArray = new GpuBufferArray(
                    Utility.SizeOf <TrianglePoints>(),
                    count,
                    mDevice,
                    GpuResourceInfo.BufferArray());

                mTrianglePointsBufferArrayUsage       = new GpuResourceUsage(mDevice, mTrianglePointsBufferArray);
                mTriangleColorsBufferArrayUsage       = new GpuResourceUsage(mDevice, mTriangleColorsBufferArray);
                mTrianglePointsCanvasBufferArrayUsage = new GpuResourceUsage(mDevice, mTrianglePointsCanvasBufferArray);
            }

            mTrianglePointsBufferArray.Update(trianglePoints);
            mTriangleColorsBufferArray.Update(triangleColors);
            mTrianglePointsCanvasBufferArray.Update(trianglePointsCanvas);

            //change shader we use
            mDevice.SetVertexShader(mFillBeziersVertexShader);
            mDevice.SetPixelShader(mFillBeziersPixelShader);

            //set vertex buffer
            mDevice.SetVertexBuffer(mFillVertexBuffer);
            mDevice.SetIndexBuffer(mFillIndexBuffer);

            //set constant buffer and resource
            mDevice.SetResourceUsage(mTrianglePointsBufferArrayUsage, 0);
            mDevice.SetResourceUsage(mTriangleColorsBufferArrayUsage, 1);
            mDevice.SetResourceUsage(mTrianglePointsCanvasBufferArrayUsage, 2);

            //drwa indexed instanced
            mDevice.DrawIndexedInstanced(3, count);

            //reset the shader
            mDevice.SetVertexShader(mFillBezierVertexShader);
            mDevice.SetPixelShader(mFillBezierPixelShader);
        }