XNA - 使用动态顶点缓冲区且仅使用四 (4) 个顶点

发布于 2024-09-08 11:52:04 字数 1794 浏览 1 评论 0原文

只是一个关于绘制四边形的快速问题。我目前正在使用:

GraphicsDevice.DrawPrimitives(PrimitiveType primitiveType,
                        int startVertex, int primitiveCount);

这可以完美地绘制我的四边形,但我可以使其工作的唯一方法是为我的四边形使用六(6)个顶点(将它们绘制为两个三角形)。我只是想知道是否可以为 GPU 提供四 (4) 个顶点,同时仍然保留我的动态顶点缓冲区。

我知道我可以使用 DrawUserIndexedPrimitives() 来做到这一点,但我想要我的缓冲区! ;)

编辑:我需要吗?如果需要,我在哪里告诉我的 GPU 我正在为每两个三角形提供四个顶点?我目前将我的四边形作为 nQuads * 6 顶点存储在顶点缓冲区中,并且我的 GPU 使用每三个顶点作为一个三角形。因此,仅仅切换到四个顶点意味着:

Quads: {v1,v2,v3,v4} {v5,v6,v7,v8} ...
Triangles: {v1,v2,v3} {v4,v5,v6} {v7,v8 ...}

这不是一件好事,因为第二个三角形使用第一个四边形中的一个顶点,第三个三角形使用第二个四边形中的两个顶点,依此类推。

编辑2:抱歉,我实际上正在使用动态顶点缓冲区。

发布一些关于如何使用六个顶点制作四边形的代码:

        // ## CONSTRUCTION
        // Setting up buffer and vertex holder.
        particleVertexBuffer = new DynamicVertexBuffer(graphicsDevice,
            ParticleQuad.VerticesSizeInBytes * nMaxParticles,
            BufferUsage.WriteOnly);
        particleVertices = new ParticleVertex[nMaxParticles * 6];

        // ## ADD VERTICES
        particleVertices[i].Set();
        particleVertices[i+1].Set();
        particleVertices[i+2].Set();
        particleVertices[i+3].Set();
        particleVertices[i+4].Set();
        particleVertices[i+5].Set();


        // ## SET BUFFER
        particleVertexBuffer.SetData(particleVertices, 0, nMaxParticles * 6, SetDataOptions.NoOverwrite);
        graphicsDevice.Vertices[0].SetSource(particleVertexBuffer, 0, ParticleVertex.SizeInBytes);

        // ## DRAW
        graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList,
                    FirstUsedParticle * 6, ((LastUsedParticle - FirstUsedParticle)+1)* 2);

现在,还有更多内容,因为我使用循环队列和其他一些东西,但这足以理解。

Just a quick question on drawing quads. I'm currently using:

GraphicsDevice.DrawPrimitives(PrimitiveType primitiveType,
                        int startVertex, int primitiveCount);

This draws my quads perfectly fine but the only way I can make it work is to use six (6) vertices for my quads (drawing them as two triangles). I'm just wondering if it is possible to feed the GPU with four (4) vertices and still retain my dynamic vertex buffer.

I know that I can do so with DrawUserIndexedPrimitives() but I want my buffer! ;)

Edit: Do I need, and if so where do I tell my GPU that I'm feeding it four vertices per two triangles? I'm currently storing my quads as nQuads * 6 vertices in a vertex buffer and my GPU uses every three vertices as a triangle. So just switching to four vertices means:

Quads: {v1,v2,v3,v4} {v5,v6,v7,v8} ...
Triangles: {v1,v2,v3} {v4,v5,v6} {v7,v8 ...}

Which is not a good thing since triangle number two uses one vertex from the first quad, number three uses two from the second quad, and so on and so forth.

Edit 2: I'm sorry, I'm actually using a dynamic vertex buffer.

Posting some code on how I do my quads with six vertices:

        // ## CONSTRUCTION
        // Setting up buffer and vertex holder.
        particleVertexBuffer = new DynamicVertexBuffer(graphicsDevice,
            ParticleQuad.VerticesSizeInBytes * nMaxParticles,
            BufferUsage.WriteOnly);
        particleVertices = new ParticleVertex[nMaxParticles * 6];

        // ## ADD VERTICES
        particleVertices[i].Set();
        particleVertices[i+1].Set();
        particleVertices[i+2].Set();
        particleVertices[i+3].Set();
        particleVertices[i+4].Set();
        particleVertices[i+5].Set();


        // ## SET BUFFER
        particleVertexBuffer.SetData(particleVertices, 0, nMaxParticles * 6, SetDataOptions.NoOverwrite);
        graphicsDevice.Vertices[0].SetSource(particleVertexBuffer, 0, ParticleVertex.SizeInBytes);

        // ## DRAW
        graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList,
                    FirstUsedParticle * 6, ((LastUsedParticle - FirstUsedParticle)+1)* 2);

Now, there are a bit more to it because I use a circular queue and a bit other stuff, but this would be enough for understandability.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

随遇而安 2024-09-15 11:52:04

是的,这是可能的。您需要使用 TriangleStrip 作为 PrimitiveType。在您的 VertexBuffer 中,您按以下顺序定义顶点:

1---3
|\  |
| \ |
|  \|
0---2

EDIT to adress Your modified question

我不知道您的代码是什么样子,但一般来说,有关基元计数的信息在以下位置使用:

  • 缓冲区创建:public VertexBuffer (
    GraphicsDevice 图形设备,
    int 大小(以字节为单位),
    BufferUsage 使用情况
    )
    //sizeInBytes 取决于基元计数。
  • 绘制调用:public void DrawPrimitives (
    PrimitiveType 原始类型,
    int 起始顶点,
    int 原始计数
    )

请注意,更多地方需要有关顶点格式的大小的信息,但这应该不是问题,因为大小不应改变。

更新

谢谢澄清,现在我知道你想要实现什么。处理您的问题的正确方法是将顶点缓冲区与索引缓冲区结合使用。顶点缓冲区保存顶点,索引缓冲区保存连接顶点形成三角形的顺序。想象一下,您想在屏幕上绘制以下四边形:

 (0,1)________(1,1)
     |        |
     |        |
     |________|
 (0,0)        (1,0)

您之前所做的是:

Vector3 v0, v1, v2, v3;
v0 = new Vector3(0, 0, 0);
v1 = new Vector3(1, 0, 0);
v2 = new Vector3(0, 1, 0);
v3 = new Vector3(1, 1, 0);

List vertices = new List();
//first triangle
vertices.add(v0);
vertices.add(v2);
vertices.add(v1);

//second triangle
vertices.add(v2);
vertices.add(v1);
vertices.add(v3);

VertexBuffer vb = new VertexBuffer(...);
vb.setData(verticesToDraw);

//draw the scene using PrimitiveType.TriangleList and primitive count 2

您现在所做的是:

//vertices stay the same as in the example above!
List vertices = new List();
vertices.add(v0);
vertices.add(v1);
vertices.add(v2);
vertices.add(v3);

int[] indices = new int[6];
//first triangle
indices[0] = 0;
indices[1] = 2; 
indices[2] = 1;

//second triangle
indices[3] = 2;
indices[4] = 1;
indices[5] = 3;

VertexBuffer vb = new VertexBuffer(...);
IndexBuffer ib = new IndexBuffer(...);

vb.setData(vertices);
ib.setData(indices);

/*draw using the DrawIndexedPrimitives() method rather than the
DrawPrimitives() method and use PrimitiveType.TriangleList and
primitive count 2.*/

您看,每个四边形保存 2 个顶点,但必须使用 6 个索引来指定构建顺序从顶点开始的三角形。因此,只有当您的顶点很大(带有法线、纹理坐标等许多信息)并且由许多三角形共享时,此方法才有用。

Riemers.net 有一个非常好的、简短的关于顶点和索引缓冲区的易于理解的教程。

Yes that's possible. You'll need to use TriangleStrip as the PrimitiveType. In Your VertexBuffer, You define Your vertices in the following order:

1---3
|\  |
| \ |
|  \|
0---2

EDIT to adress Your modified question

I don't know, how Your code looks like, but in general the information about the primitve count is used in the following places:

  • Buffer creation: public VertexBuffer (
    GraphicsDevice graphicsDevice,
    int sizeInBytes,
    BufferUsage usage
    )
    //sizeInBytes depends on the primitive count.
  • Draw call: public void DrawPrimitives (
    PrimitiveType primitiveType,
    int startVertex,
    int primitiveCount
    )

Note, the information about the size of Your vertex format is needed in a couple more places but shouldn't be a problem as the size shouldn't change.

Update

Thx for the clarification, now I know, what You want to achieve. The correct way to handle Your problem is to use a vertex buffer in conjunction with a index buffer. The vertex buffer holds the vertices, the index buffer holds the order in which to connect the vertices to form triangles. Imagine You want to draw the following quad on Your screen:

 (0,1)________(1,1)
     |        |
     |        |
     |________|
 (0,0)        (1,0)

What You did earlier was this:

Vector3 v0, v1, v2, v3;
v0 = new Vector3(0, 0, 0);
v1 = new Vector3(1, 0, 0);
v2 = new Vector3(0, 1, 0);
v3 = new Vector3(1, 1, 0);

List vertices = new List();
//first triangle
vertices.add(v0);
vertices.add(v2);
vertices.add(v1);

//second triangle
vertices.add(v2);
vertices.add(v1);
vertices.add(v3);

VertexBuffer vb = new VertexBuffer(...);
vb.setData(verticesToDraw);

//draw the scene using PrimitiveType.TriangleList and primitive count 2

What You do now is this:

//vertices stay the same as in the example above!
List vertices = new List();
vertices.add(v0);
vertices.add(v1);
vertices.add(v2);
vertices.add(v3);

int[] indices = new int[6];
//first triangle
indices[0] = 0;
indices[1] = 2; 
indices[2] = 1;

//second triangle
indices[3] = 2;
indices[4] = 1;
indices[5] = 3;

VertexBuffer vb = new VertexBuffer(...);
IndexBuffer ib = new IndexBuffer(...);

vb.setData(vertices);
ib.setData(indices);

/*draw using the DrawIndexedPrimitives() method rather than the
DrawPrimitives() method and use PrimitiveType.TriangleList and
primitive count 2.*/

You see, You save 2 vertices per quad but have instead to use 6 indices which specify the order in which to build triangle from the vertices. So this method is only useful if Your vertices are big (cary many information like normals, texture coordinates etc) and are shared by many triangles.

Riemers.net has a really nice, short and easy to understand tutorial on vertex and index buffers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文