Почему существуют разные варианты glVertexAttribPointer?

Есть

glVertexAttribPointer()
glVertexAttribIPointer()
glVertexAttribLPointer()

Насколько я знаю, glVertexAttribPointer можно использовать вместо двух других.

Если так, почему существуют вариации I и L?

Ответ 1

Я читал об этом в 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.

Ответ 2

Нет, они не могут использоваться вместо друг друга.

Традиционно все атрибуты вершин GL являются плавающей точкой. Тот факт, что вы можете вводить целочисленные данные, не изменяется, поскольку данные преобразуются в плавающую точку "на лету". Параметр normalized управляет тем, как выполняется преобразование, если оно включено, диапазон типа ввода отображается в нормализованный [0,1] (для неподписанных типов, также называемых UNORM ing GL) или [-1, 1] (для подписанных типов, также называемых SNORM), если он отключен, значение напрямую преобразуется в ближайшее значение с плавающей запятой входного целого.

Так как это был оригинальный API, он должен был быть расширен, когда были введены разные типы данных атрибутов (целые числа и парные). Также обратите внимание, что указатели на атрибуты не зависят от шейдеров, поэтому целевое значение не может быть определено привязанным в данный момент шейдером (если есть), поскольку позже это может быть использовано с разными шейдерами. Таким образом, идентификатор вариантов L для атрибутов double/dvec, а вариант I - для атрибутов int/uint/ivec/uvec.

Ответ 3

Пройдите тест, и вы поймете разницу.

Предположим, вы выполняете преобразование обратной связи с помощью следующего вершинного шейдера:

#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().)