glsl fragmentshader рендеринга objectID
Как правильно отобразить целочисленный идентификатор объекта в буфер целочисленной текстуры?
скажем, у меня есть texture2D с внутренним форматом GL_LUMINANCE16, и я прикрепляю его как цветовое вложение к моему FBO.
при рендеринге объекта я передаю шейдеру целочисленный идентификатор и хотел бы отобразить этот идентификатор в мою целочисленную текстуру.
вывод fragmentshader имеет тип vec4, однако. Как правильно преобразовать мой ID в четырехкомпонентный float и избежать преобразования неточности такие, что в конце концов integervalue в моей целочисленной текстуре соответствует целочисленному идентификатору, который я хотел отобразить?
3 ответов
есть несколько проблем с вашим вопросом.
во-первых,GL_LUMINANCE16
is не " целочисленная текстура.- Это текстура, которая содержит нормированный целочисленные значения без знака. Он использует целые числа для представления поплавков в диапазоне [0, 1]. Если вы хотите сохранить фактические целые числа, вы должны использовать фактическое целочисленный формат изображения.
во-вторых, вы не можете визуализировать текстуру яркости; они не являются форматами цветопередачи. Если вы на самом деле, чтобы отобразить одноканальную текстуру, необходимо создать одноканальный формат изображения. Так вместо GL_LUMINANCE16
, вы используете GL_R16UI
, который представляет собой 16-разрядный одноканальный беззнаковый интегральный формат изображения.
теперь, когда у вас это настроено правильно, это довольно тривиально. Определить uint
вывод шейдера фрагментов и пусть ваш шейдер фрагментов напишет ваш uint
значение. Это uint
может исходить из вершинного шейдера или из униформы; однако вы хотите это сделать он.
очевидно, вам также нужно будет прикрепить текстуру или рендербуфер к FBO, но я уверен, что вы это знаете.
и последнее: не используйте фразу "буфер текстуры", Если вы не имеете в виду один из этих. В противном случае это сбивает с толку.
Я все еще не думаю, что здесь есть четкий ответ. Итак, вот как я заставил его работать через 2D-текстуру:
// First, create a frame buffer:
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Then generate your texture and define an unsigned int array:
glGenTextures(1, &textureid);
glBindTexture(GL_TEXTURE_2D, textureid);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, w, h, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Attach it to the frame buffer object:
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, textureid, 0);
// Before rendering
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
GLuint buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; // this assumes that there is another texture that is for the render buffer. Color attachment1 is preserved for the element ids.
glDrawBuffers(2, buffers);
// Clear and render here
glFlush(); // Flush after just in case
glBindFramebuffer(GL_FRAMEBUFFER, 0);
на стороне GLSL шейдер фрагментов должен иметь (код профиля ядра 4.3 здесь):
layout(location = 0) out vec4 colorOut; // The first element in 'buffers' so location 0
layout(location = 1) out uvec4 elementID; // The second element in 'buffers' so location 1. unsigned int vector as color
// ...
void main()
{
//...
elementID = uvec4( elementid, 0, 0, 0 ); // Write the element id as integer to the red channel.
}
вы можете прочитать значения на принимающей стороне:
unsigned int* ids = new unsigned int[ w*h ];
glBindTexture(GL_TEXTURE_2D, textureid);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, ids);
Я полагаю, что ваш целочисленный идентификатор является идентификатором для набора примитивов; действительно, его можно определить как форму шейдера:
uniform int vertedObjectId;
после рендеринга вы хотите сохранить обработку фрагмента в целое число текстуры. Обратите внимание, что целочисленные текстуры должны быть выбраны с помощью целое пробоотборники (isampler2D
), которая возвращает целое векторы (т. е. ivec3
).
эта текстура может быть прикреплена к объекту framebuffer (имейте в виду фреймбуфер полноты). Приложение framebuffer может быть привязан к целочисленной переменной вывода:
out int fragmentObjectId;
void main() {
fragmentObjectId = vertedObjectId;
}
вам нужна поддержка нескольких расширений или расширенная версия OpenGL (3.2?).