Подтвердить что ты не робот

Как я могу указать цвета для каждого лица при использовании индексированных вершинных массивов в OpenGL 3.x?

Я пытаюсь отобразить куб, используя массив из 8 вершин и индексный массив из 24 (4 * 6) индексов в массив вершин. Но как я могу указать переменные на лицо, такие как цвета и нормали, без использования устаревших функций? Для этого мне нужен отдельный набор индексов, но когда я укажу два массива индексов (GL_ELEMENT_ARRAY_BUFFERs) и укажу их на разные шейдерные переменные (с двумя вызовами glVertexAttribPointer), что-то пойдет не так, и оно ничего не отображает ( но также не сообщает об ошибках - проверяется с помощью glGetError). Должен ли я использовать разные вызовы для glDrawElements для каждого лица, с цветом и нормальной загрузкой в ​​однородные переменные?

Чтобы уточнить, проблема возникает, когда каждая из 8 вершин является частью разных граней и нуждается в разных значениях для цвета и нормальной.

4b9b3361

Ответ 1

Фактический ответ сначала:
См. Ответ Goz. Храните 24 отдельных вершины.

Некоторая номенклатура вторая:
Вершина - это набор атрибутов вершин. Пожалуйста, придерживайтесь этого различия при чтении следующего:

У вас есть неправильное представление о том, что использование устаревших API поможет вам решить проблему. Это не тот случай. OpenGL обрабатывает (и всегда обрабатывает) каждую вершину как уникальный набор атрибутов. Если вы внимательно прочитаете оригинальную спецификацию, вы заметите, что при выполнении:

glNormal()
glVertex()
glVertex()
glVertex()

В спецификации четко указано, что glNormal устанавливает current normal state, а glVertex вызывает новую вершину, копируя по всем всем current state, включая current normal state. То есть, хотя вы прошли только один Normal, GL все еще видит 3.

Таким образом, GL не имеет атрибутов "per-face".

Кроме того, вы смешиваете массивы индексов GL_ELEMENT_ARRAY_BUFFER, которые используются из glDrawElements(..., pointer), где pointer - смещение внутри массива индексов и массивы атрибутов vertex GL_ARRAY_BUFFER, которые используются из glVertexAttribPointer (и все устаревшие glVertexPointer/glNormalPointer...

Каждый индекс, который находится в буфере индекса, будет использоваться как индекс в каждом из атрибутов, но вы можете указать только один индекс для каждой вершины. Таким образом, установка GL_ELEMENT_ARRAY_BUFFER, а затем вызов glVertexAttribPointer, вовсе не делает того, что вы думаете. Он либо использует последний массив, который вы установили для GL_ARRAY_BUFFER для определения атрибутов вершин, либо если вы не сохранили одну привязку, интерпретирует ваше смещение как указатель (и, скорее всего, произойдет сбой).

То, что вы пытались сделать, задав индексный массив для каждого атрибута вершины, не поддерживается GL. Позвольте мне повторить это: у вас есть только 1 индексный массив за ничью.

Некоторые дополнительные лакомые кусочки для истории:

glVertex является немного неправильным. Он определяет только позицию вершины. Но, и это то, от чего оно получает свое имя, оно также вызывает вершину, которая должна быть передана GL. Чтобы API был полностью чистым, вы могли подумать, что нужно сделать 2 вызова:

// not valid code
glPosition(1,2,3); // specifies the current vertex position
glProvoke(); // pass the current vertex to GL

Однако, когда GL был указан первым, позиция всегда была обязательной, поэтому слияние этих 2 спровоцировало правильность вершины (хотя бы для уменьшения количества вызовов API).

Перейдите к vertex_program_arb: попытка уйти от модели с фиксированной функцией, оставаясь при этом совместимой, означает, что особый характер glVertex пришлось переносить. Это было достигнуто путем создания vertex attribute 0 провокации и синонимов glVertex.

Перейдите к GL3.2: модель Begin/End исчезла, и вся эта спецификация того, что вызывает вершину, может, наконец, уйти вместе с управлением current state. Таким образом, все семантические API (glVertex *, glNormal *...), поскольку все входы теперь являются только вершинными атрибутами.

Ответ 2

Люди, заинтересованные в том, следует ли использовать индексы массива или нет, могут найти некоторую полезность на диаграмме, которую я создал, чтобы графически суммировать поведение различных вызовов OpenGL, чтобы вы могли видеть, например, какие из них вызывают непрерывные блоки данных вершин, по сравнению с теми, которые "пропускают" с использованием индексов.

OpenGL нарисовать вызовы http://tartley.com/wp-content/uploads/2010/03/opengl-draw-calls.png.

Я опубликовал это изображение в Creative Commons BY-SA, как указано в этом источнике.

Ответ 3

Вам нужно больше 8 вершин. Verts может делиться позициями, но если все остальное в вершине не уникально, это не уникальная вершина. Нормы - еще одна классическая причина для того, чтобы в определении куба было больше 8 вершин.

Ответ 4

Интересные объяснения, но они, похоже, скрывают тот факт, что исходный вопрос содержит свой собственный ответ: "Должен ли я использовать разные вызовы glDrawElements для каждого лица, с цветом и нормалью, загружаемыми в однородные переменные?" - Если вам нужно передавать одни и те же данные о вершинах в графический процессор три раза, когда один раз должно быть достаточно, оскорбляет один эстетический смысл (и он должен), тогда это да к этому.

Оригинальный вопросник не хочет знать, что OpenGL не может делать то, что он пытается сделать, и что ему нужно поддерживать двадцать четыре вершины для куба, о которых говорят как стандартные математические, так и здравые рассуждения, нужно только восемь, Он уже знает, что МОЖЕТ делать то, что он хочет, и он даже знает, как это сделать. Он просто хочет подтверждения, что его предлагаемый подход действительно имеет смысл, и что нет лучшего способа сделать это, о котором он забыл.

Выполнение вызовов для каждого лица добавляет собственные накладные расходы, но это вряд ли важно при рисовании всего одного куба. При рисовании многих поверхностей все одинаковые атрибуты могут быть собраны вместе, например. все на юг, а затем весь Запад, или все красное, а затем все зеленые или что-то еще.

Ответ 5

В OpenGL 3.x у вас есть доступ к типу квалификаторы интерполяции. Используя квалификатор flat, вы вынуждены использовать переменную, переданную только вызывающей вершиной. В некоторых случаях этого должно быть достаточно, чтобы делать то, что вы хотите, но имеет недостаток, что вам нужно уделять очень пристальное внимание порядку, в котором вы рисуете вершины.