Я работаю над созданием умеренно простых фигур с массивами вершин, и у меня неплохо получается, но теперь я хочу нарисовать 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 - длина этого вентилятора.
Кажется, это работает, и это хорошо, но все же, это правильный способ сделать это? Есть ли способ лучше?
Ответ 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 для всех них, я думаю.