Не удается получить целочисленные атрибуты вершины, работающие в GLSL 1.5 - PullRequest
16 голосов
/ 05 июля 2011

Я использую контекст OpenGL 3.2 с GLSL 1.5, и по некоторым причинам целочисленные атрибуты (типа int, uint, ivecX или uvecX) всегда читаются как 0 в вершинном шейдере.Я объявляю их, используя:

in int name;

, и я связываю атрибуты, используя glVertexAttribIPointer (обратите внимание на I), а не glVertexAttribPointer (но это тоже не работает).Если я изменю их на плавающие, они будут работать отлично - единственное отличие кода - это тип в структуре вершин, тип в GLSL и вызов функции IPointer вместо просто Pointer.Я не получаю никаких ошибок или чего-то подобного, они просто равны 0. Если я жестко кодирую целочисленные значения, это работает нормально, а целочисленные формы работают нормально.Кроме того, встроенные целые числа, такие как gl_VertexID, работают отлично, просто пользовательские - нет.Я использую ATI Mobility Radeon HD 5870. Я попробовал на другом компьютере с другим графическим процессором (к сожалению, я не уверен, какой графический процессор, но он отличался от моего) с теми же результатами.Любые идеи, почему это может иметь место?Спасибо.

РЕДАКТИРОВАТЬ: На самом деле похоже, что они не равны 0, скорее всего, они случайные большие неинициализированные значения ... трудно сказать, так как я не могу найти какие-либо способы отладки шейдеров GLSL.Во всяком случае, еще немного информации.Вот моя структура вершин:

struct TileVertex {
    float pos[2];
    float uv[2];
    float width;
    float pad;
    int animFrames;
    int animFrameLength;
};

animFrames и animFrameLength - это два целочисленных значения, которые я пытаюсь отправить в шейдер.Мой призыв к glVertexAttribIPointer for animFrames следующий:

glVertexAttribIPointer( attribute.location, attribute.typeSize, attribute.baseType, (GLsizei)stride, bufferOffset( bufOffset + attribOffset ) );

где:

attribute.location = 1 (as determined by OpenGL)
attribute.typeSize = 1 (since it's a single int, not a vector)
attribute.baseType = 5124, which is GL_INT
stride = 32, which is sizeof( TileVertex )
bufferOffset() converts to a void pointer relative to NULL
bufOffset = 0 (my vertices start at the beginning of the VBO), and
attribOffset = 24, which is the offset of animFrames in the TileVertex struct

РЕДАКТИРОВАТЬ: Спасибо за помощь, ребята.Поэтому я попытался использовать обратную связь с преобразованием, и теперь все становится более понятным.Если я установлю значение int attrib равным 1, в шейдере это будет:

1065353216 = 0x3F800000 = 1.0 in floating point

Если я установлю его на 10, в шейдере я получу:

1092616192 = 0x41200000 = 10.0 in floating point

Так оно и появляетсячто int attrib преобразуется в float, тогда эти биты интерпретируются как int в шейдере, хотя я указываю GL_INT и использую IPointer вместо Pointer!Насколько я понимаю, IPointer должен просто оставлять данные в целочисленной форме, а не преобразовывать их в число с плавающей точкой.

РЕДАКТИРОВАТЬ:

Вот еще несколько тестов.Для каждого теста я пытаюсь передать целочисленное значение 1 на целочисленный ввод в шейдере:

glVertexAttribIPointer with GL_INT: shader values are 0x3F800000, which is 1.0 in floating point

, кажется, указывает, что целое число 1 преобразуется в число с плавающей запятой 1.0, а затем интерпретируется как целое число.Это означает, что OpenGL либо думает, что исходные данные находятся в форме с плавающей запятой (когда они на самом деле находятся в целочисленной форме), либо думает, что входные данные шейдера являются плавающей запятой (когда они на самом деле являются целыми числами).

glVertexAttribIPointer with GL_FLOAT: shader values are valid but weird floating point values, such as 0.0, 1.0, 4.0, 36.0... what the hell!?

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

glVertexAttribPointer with GL_INT: same result as glVertexAttribIPointer with GL_INT

- это ожидаемый результат.OpenGL преобразует целые числа в плавающие, а затем передает их шейдеру.Это то, что должно произойти, так как я не использовал версию I.

glVertexAttribPointer with GL_FLOAT: integer values 1 (the correct result)

это работает, потому что OpenGL 1) думает, что исходные данные находятся в форме с плавающей запятой, и 2) думает, что входы шейдеров такжев форме с плавающей точкой (на самом деле это int и int), поэтому не применяет никакого преобразования, оставляя int как int (или float как float, как он думает).Это работает, но кажется очень хакерским и ненадежным, поскольку я не думаю, что есть гарантия того, что процесс с плавающей запятой процессора не будет нуждаться в преобразовании (разве некоторые графические процессоры не используют 16-битные операции с плавающей запятой? Может быть, это всего лишь pre-OpenGL 3, новсе еще) - это просто не на моем GPU.

Ответы [ 2 ]

4 голосов
/ 01 сентября 2014

Я знаю, что этот вопрос старый, но, возможно, эта информация все еще полезна:

GLint определено как имеющий размер 32 бита, но ваш int в Cможет быть и 64 бит.

Это заставило меня отладить слишком долго.

4 голосов
/ 05 июля 2011

Для одного из шейдеров (не помню, какой именно) вам нужно использовать ключевое слово varying. Или, может быть, ключевое слово attribute. Более поздние версии GLSL используют in и out.

Я думаю, вам нужно:

attribute int name;

для данных, идущих в вершинный шейдер, и

varying int name;

для данных, идущих от вершинного шейдера к фрагментному шейдеру.

Также обязательно включите атрибут шейдера с помощью glEnableVertexAttribArray.


У меня возникли проблемы с работой атрибутов int, но я обнаружил, что поле type (GL_INT или GL_FLOAT, переданное glVertexAttribPointer, соответствует данным, переданным ему, а не данным введите шейдер). В итоге я использовал glVertexAttribPointer и GL_INT, которые преобразовали int на моем хосте в float в моем шейдере, что хорошо для меня, потому что мой атрибут был данными о положении и должен был быть преобразован с плавающей точкой vec2 все равно.

Возможно, вам нужно glVertexAttribIPointerEXT, чтобы соответствовать атрибуту вашего шейдера int, а затем также GL_INT, если хост предоставляет данные в виде int массива.

...