OpenGL/JOGL:顶点数组中的多个三角形扇形

发布于 2024-10-06 18:42:02 字数 1535 浏览 4 评论 0原文

我正在努力用顶点数组制作一些相当简单的形状,并且取得了一些良好的进展,但现在我想绘制 2 个(或更多)三角形扇形对象。有没有办法只对 gl.glDrawArrays(GL.GL_TRIANGLE_FAN,... 进行一次调用,或者我是否需要为每个风扇进行单独的调用?

维基百科的 三角带文章描述了一种称为原始重启的东西,但是OpenGL的顶点规范让我觉得这不适用于顶点数组。

绘制多个三角形扇形的正确方法是什么?这是我当前的绘制方法:

public void draw(GL gl){
if(vertices.length == 0)
    return;

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL.GL_COLOR_ARRAY);
    gl.glEnableClientState(GL.GL_NORMAL_ARRAY);

    gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertBuff);
    gl.glColorPointer(3, GL.GL_FLOAT, 0, colorBuff);
    gl.glNormalPointer(GL.GL_FLOAT,0, normalBuff);

    // drawArrays count is num of points, not indices.
    gl.glDrawArrays(GL.GL_TRIANGLES, 0, triangleCount);
    gl.glDrawArrays(GL.GL_QUADS, triangleCount, quadCount);
    gl.glDrawArrays(GL.GL_TRIANGLE_FAN, triangleCount+quadCount, fanCount);

    gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL.GL_COLOR_ARRAY);
    gl.glDisableClientState(GL.GL_NORMAL_ARRAY);
}

编辑

我更新了相关像这样绘制的部分:

    for(int i = 0; i < fanLength.length; i++){
        gl.glDrawArrays(GL.GL_TRIANGLE_FAN, 
            triangleCount+quadCount+fanDist[i], fanLength[i]);
    }

其中 fanDist 是该扇形开始的偏移量(从扇形的起点开始),而 fanLength 是该扇形的长度

这似乎确实有效,这很好,但仍然是这样 。有更好的方法吗?

I'm working on making some moderately simple shapes with vertex arrays, and I'm making some good headway, but now I want to draw 2 (or more) triangle fan objects. Is there any way to only make one call to gl.glDrawArrays(GL.GL_TRIANGLE_FAN,... or do I need to make a separate call for each fan?

Wikipedia's Triangle strip article describes something called primitive restart, but OpenGL's Vertex Specification makes me think this doesn't work with vertex arrays.

What is the correct way to draw multiple triangle fans? Here is my current draw method:

public void draw(GL gl){
if(vertices.length == 0)
    return;

gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL.GL_COLOR_ARRAY);
    gl.glEnableClientState(GL.GL_NORMAL_ARRAY);

    gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertBuff);
    gl.glColorPointer(3, GL.GL_FLOAT, 0, colorBuff);
    gl.glNormalPointer(GL.GL_FLOAT,0, normalBuff);

    // drawArrays count is num of points, not indices.
    gl.glDrawArrays(GL.GL_TRIANGLES, 0, triangleCount);
    gl.glDrawArrays(GL.GL_QUADS, triangleCount, quadCount);
    gl.glDrawArrays(GL.GL_TRIANGLE_FAN, triangleCount+quadCount, fanCount);

    gl.glDisableClientState(GL.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL.GL_COLOR_ARRAY);
    gl.glDisableClientState(GL.GL_NORMAL_ARRAY);
}

Edit

I updated the relevant section of draw like so:

    for(int i = 0; i < fanLength.length; i++){
        gl.glDrawArrays(GL.GL_TRIANGLE_FAN, 
            triangleCount+quadCount+fanDist[i], fanLength[i]);
    }

Where fanDist is the offset (from the start of the fans) of the start of this fan, and fanLength is the length of this fan.

This does seem to work, which is nice, but still, is this the right way to do this? Is there a better way?

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

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

发布评论

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

评论(1

谎言月老 2024-10-13 18:42:02

原始重启确实适用于顶点数组和顶点缓冲区 - 如果不适用,它就不会真正有用。

但是,确实它与 glDrawArrays 结合使用时没有用处。

让我们看一下两种技术:

原始重启


让我向您介绍一下 glDrawElements: 像这样的调用

glDrawArrays(mode, 0, 5);

类似于

GLuint idxs[] = {0, 1, 2, 3, 4}; // C code, but idea's the same in Java
glDrawElements(mode, 5, GL_UNSIGNED_INT, idxs);

So,而不是指定要从数组中绘制的元素的范围 ,您指定这些元素的精确索引

然后你可以通过使用这样的数组来引入图元重新启动:

GLuint PRIMITIVE_RESTART = 12345; // magic value

glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(PRIMITIVE_RESTART);
GLuint idxs[] = {0, 1, 2, 3, PRIMITIVE_RESTART, 4, 5, 6, 7};
glDrawElements(mode, 9, GL_UNSIGNED_INT, idxs);

这将从前4个顶点绘制一个扇形,然后遇到“符号”以重新启动图元,然后它将在最后4个顶点绘制另一个扇形。

传递给 DrawElements 的索引不必是连续的范围!它们可以采用任何顺序,并且可以根据需要重复 - 这是该函数最好的部分。事实上,最好尽可能频繁地重用一个索引,因为如果结果被缓存,它只会被顶点着色器处理一次。因此,您可以自由地创建缓冲区,例如:

GLuint idxs[] = {0, 6, 3, 4, 6, 2, PRIMITIVE_RESTART, 2, 6, 3, 3, 5, 2}; // etc.

MultiDrawElements


在您的情况下,您可能需要使用 glMultiDrawElements 来代替。

例如,如果您有 20 个顶点,并且您想从第一个顶点开始绘制一个 8 个顶点的扇形,并从第 10 个顶点开始绘制一个 10 个顶点的扇形,您可以执行以下操作:

// assuming glVertexPointer is already set
GLuint startingElements[] = {0, 9};
GLuint counts[] = {8, 10};
glMultiDrawArrays(GL_TRIANGLE_FAN, startingElements, counts, 2); // 2 fans

因此您要做的工作会少一些。


选择您认为更有用的技术。我将让您在 Java/JOGL 中重写它,原理是相同的,但我猜您必须使用 Buffer 类来实现所有这些。

Primitive restart does work with vertex arrays and vertex buffers - it wouldn't be really useful if it didn't.

However, it's true that it's not useful in conjunction with glDrawArrays.

Let's have a look on two techniques:

Primitive Restart


Let me introduce glDrawElements to you: A call like

glDrawArrays(mode, 0, 5);

is analogous to

GLuint idxs[] = {0, 1, 2, 3, 4}; // C code, but idea's the same in Java
glDrawElements(mode, 5, GL_UNSIGNED_INT, idxs);

So instead of specifying a range of elements to draw from an array, you specify exact indices of those elements.

And then you can introduce primitive restarting by using such array:

GLuint PRIMITIVE_RESTART = 12345; // magic value

glEnable(GL_PRIMITIVE_RESTART);
glPrimitiveRestartIndex(PRIMITIVE_RESTART);
GLuint idxs[] = {0, 1, 2, 3, PRIMITIVE_RESTART, 4, 5, 6, 7};
glDrawElements(mode, 9, GL_UNSIGNED_INT, idxs);

This will draw a fan from the first 4 vertices, then will encounter the "sign" to restart the primitive, and then it will draw another fan of the last 4 vertices.

The indices passed to DrawElements don't have to be a consecutive range! They can be in any order and can be repeated as you desire - that's the whole best part of this function. In fact, it's best to reuse one index as often as possible, as it will get processed by vertex shader only once if the result's cached. So you're free to make buffers like:

GLuint idxs[] = {0, 6, 3, 4, 6, 2, PRIMITIVE_RESTART, 2, 6, 3, 3, 5, 2}; // etc.

MultiDrawElements


In your case, you might want to use glMultiDrawElements instead.

If you have, say, 20 vertices and you want to draw one fan of 8 vertices starting from the first and one fan of 10 vertices starting from the 10th, you can do something like this:

// assuming glVertexPointer is already set
GLuint startingElements[] = {0, 9};
GLuint counts[] = {8, 10};
glMultiDrawArrays(GL_TRIANGLE_FAN, startingElements, counts, 2); // 2 fans

Thus you have a bit less work to do.


Pick the technique you find more useful. I'll leave it to you to rewrite that in Java/JOGL, the principle is the same but you'll have to use the Buffer class for all those, I guess.

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