2

我正在尝试在不使用自定义着色器的情况下绘制具有宽颜色轮廓的 2D 多边形。
(如果我要写一个,它可能会比使用 CPU 慢,因为我不精通着色器)
为此,我计划像正常一样绘制多边形,然后使用生成的深度缓冲区作为绘制相同的扩展几何图形时使用模板。

XNA "GraphicsDevice" 可以在给定任何 IVertexType 实例数组的情况下绘制图元:

DrawUserPrimitives<T>(PrimitiveType primitiveType, T[] vertexData, int vertexOffset, int primitiveCount, VertexDeclaration vertexDeclaration) where T : struct;

我为 2D 坐标空间定义了一个 IvertexType:

public struct VertexPosition2DColor : IVertexType
{
    public VertexPosition2DColor (Vector2 position, Color color) {
        this.position = position;
        this.color = color;
    }

    public Vector2 position;
    public Color color;

    public static VertexDeclaration declaration = new VertexDeclaration (
        new VertexElement(0, VertexElementFormat.Vector2, VertexElementUsage.Position, 0),
        new VertexElement(sizeof(float)*2, VertexElementFormat.Color, VertexElementUsage.Color, 0)
    );

    VertexDeclaration IVertexType.VertexDeclaration {
        get {return declaration;}
    }
}

我已经定义了一个数组类来存储多边形的顶点、颜色和边缘法线:
我希望将这个类作为 GraphicDevice 的 DrawPrimitives 函数中的 T[] 参数传递。
目标是通过 GPU 计算轮廓顶点,因为它显然擅长此类事情。

internal class VertexOutlineArray : Array
{
    internal VertexOutlineArray (Vector2[] positions, Vector2[] normals, Color[] colors, Color[] outlineColors, bool outlineDrawMode) {
        this.positions = positions;
        this.normals = normals;
        this.colors = colors;
        this.outlineColors = outlineColors;
        this.outlineDrawMode = outlineDrawMode;
    }

    internal Vector2[] positions, normals;
    internal Color[] colors, outlineColors;
    internal float outlineWidth;
    internal bool outlineDrawMode;

    internal void SetVertex(int index, Vector2 position, Vector2 normal, Color color, Color outlineColor) {
        positions[index] = position;
        normals[index] = normal;
        colors[index] = color;
        outlineColors[index] = outlineColor;
    }

    internal VertexPosition2DColor this[int i] {
        get {return (outlineDrawMode)? new VertexPosition2DColor(positions[i] + outlineWidth*normals[i], outlineColors[i]) 
                                     : new VertexPosition2DColor(positions[i], colors[i]);
        }
    }
}

我希望能够渲染形状及其轮廓,如下所示: 在绘制扩展的轮廓几何图形时,深度缓冲区用作模板

protected override void RenderLocally (GraphicsDevice device)
{
    // Draw shape
    mVertices.outlineDrawMode = true; //mVertices is a VertexOutlineArray instance

    device.RasterizerState = RasterizerState.CullNone;
    device.PresentationParameters.DepthStencilFormat = DepthFormat.Depth16;
    device.Clear(ClearOptions.DepthBuffer, Color.SkyBlue, 0, 0);
    device.DrawUserPrimitives<VertexPosition2DColor>(PrimitiveType.TriangleList, (VertexPosition2DColor[])mVertices, 0, mVertices.Length -2, VertexPosition2DColor.declaration);

    // Draw outline
    mVertices.outlineDrawMode = true;

    device.DepthStencilState = new DepthStencilState {
        DepthBufferWriteEnable = true,
        DepthBufferFunction = CompareFunction.Greater //keeps the outline from writing over the shape
    };
    device.DrawUserPrimitives(PrimitiveType.TriangleList, mVertices.ToArray(), 0, mVertices.Count -2);
}

但这不起作用,因为我无法将 VertexArray 类作为 T[] 传递。在没有自定义着色器的情况下,我如何修改它或以其他方式实现在 GPU 上进行轮廓计算的目标?

4

1 回答 1

1

我想知道您为什么不简单地编写一个使用成对的细三角形作为线来绘制轮廓的类?您可以创建一个通用的折线例程,该例程接收 2d 点的输入和线的宽度,并且该例程会输出一个 VertexBuffer。

我意识到这并没有回答你的问题,但我看不出尝试按照你的方式去做有什么好处。是否有您想要实现的特定效果,或者您是否会非常频繁地操作数据或大量缩放多边形?


您可能遇到的问题是 Windows Phone 7 的 XNA4 根本不支持自定义着色器。事实上,他们故意将其限制为一组预定义的着色器,因为需要测试的排列数量。目前支持的有:

AlphaTestEffect BasicEffect EnvironmentMapEffect DualTextureEffect SkinnedEffect

你可以在这里阅读它们:

http://msdn.microsoft.com/en-us/library/bb203872(v=xnagamestudio.40).aspx

我没有测试创建或使用具有 Vector2 位置和正常的 IVertexType,因此我无法评论它是否受支持。如果我要这样做,我将只使用 BasicEffect 和 VertexPositionNormal 进行主要的多边形形状渲染,并为每个多边形调整 DiffuseColor。为了渲染轮廓,您使用现有的 VertexBuffer 并通过调用 GraphicsDevice.Viewport.Unproject() 来确定生成 n 像素 2d 屏幕距离(您的轮廓宽度)所需的 3d 坐标距离。

请记住,当您使用 BasicEffect 或任何与此相关的效果时,您必须遍历 CurrentTechnique 的 EffectPass 数组,并在进行 Draw 调用之前为每个 pass 调用 Apply() 方法。

        device.DepthStencilState = DepthStencilState.Default;
        device.BlendState = BlendState.AlphaBlend;
        device.RasterizerState = RasterizerState.CullCounterClockwise;

        //Set the appropriate vertex and indice buffers
        device.SetVertexBuffer(_polygonVertices);
        device.Indices = _polygonIndices;

        foreach (EffectPass pass in _worldEffect.CurrentTechnique.Passes)
        {
            pass.Apply();
            PApp.Graphics.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, _polygonVertices.VertexCount, 0, _polygonIndices.IndexCount / 3);
        }
于 2012-10-17T06:19:38.617 回答