Есть
glVertexAttribPointer()
glVertexAttribIPointer()
glVertexAttribLPointer()
Насколько я знаю, glVertexAttribPointer
можно использовать вместо двух других.
Если так, почему существуют вариации I
и L
?
Есть
glVertexAttribPointer()
glVertexAttribIPointer()
glVertexAttribLPointer()
Насколько я знаю, glVertexAttribPointer
можно использовать вместо двух других.
Если так, почему существуют вариации I
и L
?
Я читал об этом в OpenGL Insights
При использовании glVertexAttribPointer()
все становится отличным для float. Хотя glVertexAttribIPointer()
может выставлять только массивы вершин, которые хранят целые числа, а glVertexAttribLPointer()
- только для удвоений.
Как подтверждается цитатой на этой странице OpenGL.org:
Для glVertexAttribPointer, если для нормализованного значения установлено значение GL_TRUE, оно указывает, что значения, хранящиеся в целочисленном формате, должны быть сопоставлены диапазон [-1,1] (для знаковых значений) или [0,1] (для неподписанных значений) при их доступе и преобразовании в плавающую точку. В противном случае, значения будут преобразованы в поплавки непосредственно без нормализации.
Для glVertexAttribIPointer используются только целые типы GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT принимаются. Значения всегда остаются целыми значения.
glVertexAttribLPointer задает состояние для общего атрибута вершины массив, связанный с переменной атрибута шейдера, объявленной с 64-битным компоненты двойной точности. тип должен быть GL_DOUBLE. индекс, размер, и stride ведут себя так, как описано для glVertexAttribPointer и glVertexAttribIPointer.
Нет, они не могут использоваться вместо друг друга.
Традиционно все атрибуты вершин GL являются плавающей точкой. Тот факт, что вы можете вводить целочисленные данные, не изменяется, поскольку данные преобразуются в плавающую точку "на лету". Параметр normalized
управляет тем, как выполняется преобразование, если оно включено, диапазон типа ввода отображается в нормализованный [0,1] (для неподписанных типов, также называемых UNORM ing GL) или [-1, 1] (для подписанных типов, также называемых SNORM), если он отключен, значение напрямую преобразуется в ближайшее значение с плавающей запятой входного целого.
Так как это был оригинальный API, он должен был быть расширен, когда были введены разные типы данных атрибутов (целые числа и парные). Также обратите внимание, что указатели на атрибуты не зависят от шейдеров, поэтому целевое значение не может быть определено привязанным в данный момент шейдером (если есть), поскольку позже это может быть использовано с разными шейдерами. Таким образом, идентификатор вариантов L
для атрибутов double/dvec
, а вариант I
- для атрибутов int/uint/ivec/uvec
.
Пройдите тест, и вы поймете разницу.
Предположим, вы выполняете преобразование обратной связи с помощью следующего вершинного шейдера:
#version 450 core
layout(location = 0) in int input;
layout(xfb_offset = 0) out float output;
void main()
{
output = sqrt(input);
}
И это ваши "данные вершины":
GLint data[] = { 1, 2, 3, 4, 5 };
Затем, если вы настроите атрибуты вершины, как это:
glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr);
Вы получите неправильные и странные результаты.
Если вы измените эту строку в вершинном шейдере
output = sqrt(input);
в
output = sqrt(intBitsToFloat(input));
ИЛИ ЖЕ
измените эту строку в коде C++:
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
^^^^^^^^
does not match the real input type
but stops glVertexAttribPointer() converting them
Это будет работать. Но это не естественный путь.
Теперь в glVertexAttribIPointer()
приходит glVertexAttribIPointer()
:
--- glVertexAttribPointer(0, 1, GL_INT, GL_FALSE, 0, nullptr);
+++ glVertexAttribIPointer(0, 1, GL_INT, 0, nullptr);
Тогда вы получите правильные результаты.
(Я боролся за это целый день, пока не нашел glVertexAttribIPointer()
.)