OpenGL / JOGL: несколько веерных треугольников в массиве вершин - PullRequest
10 голосов
/ 08 декабря 2010

Я работаю над созданием некоторых умеренно простых фигур с массивами вершин, и у меня неплохой прогресс, но теперь я хочу нарисовать 2 (или более) треугольных веерных объекта. Есть ли способ сделать только один звонок на gl.glDrawArrays(GL.GL_TRIANGLE_FAN,... или мне нужно сделать отдельный звонок для каждого поклонника?

Статья Wikipedia Triangle strip описывает нечто, называемое примитивным перезапуском, но 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 - длина этого вентилятора.

Кажется, это работает, и это хорошо, но все же, это правильный способ сделать это? Есть ли лучший способ?

1 Ответ

17 голосов
/ 08 декабря 2010

Примитивный перезапуск работает с массивами вершин и буферами вершин - это было бы не очень полезно, если бы этого не произошло.

Однако это правда, что это бесполезно в сочетании с 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);

Таким образом, вместо указания диапазона элементов для рисования из массива, вы указываете точные индексы этих элементов.

И тогда вы можете ввести перезапуск примитива, используя такой массив:

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.

...