Bezdepbonusu7Программирование: статьи и ответы

Вопрос

OpenGL/JOGL: несколько вееров треугольников в массиве вершин

Автор вопроса: dimo414Ответов: 1

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

Статья Википедии Полоса треугольника описывает нечто, называемое примитивным перезапуском, но Спецификация вершин заставляет меня думать, что это не работает с массивами вершин.

Как правильно нарисовать несколько треугольных вееров? Вот мой текущий метод рисования:

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 - длина этого вентилятора.

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

  • Пожалуйста, никогда не забывайте указывать вашу целевую версию OpenGL. :) Kos 08.12.2010
  • Достаточно честно - я считаю, что мы используем 2.1, если я правильно помню, но мы хотели бы, чтобы это было как можно более независимым от платформы (и, следовательно, независимым от версии OpenGL?). dimo414 08.12.2010
  • Это больше зависит от того, на какие графические процессоры вы ориентируетесь. Описанные здесь функции должны быть доступны в GL 2.1, IIRC, так что все готово :). Kos 08.12.2010

polygonopengljoglvertex-array

Ответы

Ответ 1 · рейтинг 17 · Kos

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

Однако это правда, что это бесполезно в сочетании с 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 для всех них, я думаю.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы