【问题标题】:Computing polygon outline vertices on the GPU在 GPU 上计算多边形轮廓顶点
【发布时间】:2012-09-19 23:24:28
【问题描述】:

我正在尝试在不使用自定义着色器的情况下绘制具有宽颜色轮廓的 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 上进行轮廓计算的目标?

【问题讨论】:

  • 你应该删除一个帖子,你创建了重复的问题
  • @Cuong Le 不错,已删除。
  • 嗯,我想你在这里误会了。 GPU 的速度比 CPU 快得惊人,几乎不会出错。此外,它从 CPU 到 GPU 的发送速度很慢——你正在走最慢的路线。
  • @DeadMG 我可以得到一个链接吗?知道 XNA BasicEffect 是否必须发送这么慢的数据吗?

标签: c# arrays windows-phone-7 xna gpu


【解决方案1】:

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

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


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

AlphaTestEffect 基本效果 环境贴图效果 双重纹理效果 蒙皮效果

您可以在这里阅读它们:

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 或任何与此相关的效果时,您必须在调用 Draw 之前遍历 CurrentTechnique 的 EffectPass 数组并为每个通道调用 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);
        }

【讨论】:

  • 会有很多缩放和突变,我想要一个可以应用于任何光栅化、正交几何的效果
  • 我不确定您所说的正交几何;这只是平行于正交投影的视口渲染的多边形的技术术语吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
  • 1970-01-01
  • 2019-12-27
  • 2011-03-27
  • 2014-02-07
相关资源
最近更新 更多