2012-05-12 13 views
6

¿Cómo presento correctamente un ID entero de un objeto a un buffer de textura entero?glsl fragmentshader render objectID

Digamos que tengo una texture2D con formato interno GL_LUMINANCE16 y la adjunto como adjunto de color a mi FBO.

Al renderizar un objeto, paso una ID entera al sombreador y me gustaría convertir esta identificación en mi textura entera.

La salida fragmentshader es del tipo vec4 sin embargo. ¿Cómo transformo correctamente mi identificación en flotante de cuatro componentes y evito las imprecisiones de conversión de tal manera que al final el valor entero en mi objetivo de textura entera corresponde a la ID entera que quería representar?

Respuesta

4

Hay varios problemas con su pregunta.

Primero, GL_LUMINANCE16 es no un "integer texture." Es una textura que contiene normalizados valores enteros sin signo. Utiliza números enteros para representar flotantes en el rango [0, 1]. Si desea almacenar enteros reales, debe usar un integer image format real.

En segundo lugar, no puede renderizar a una textura de luminancia; no son formatos de colores que puedan renderizarse. Si realmente desea renderizar a una textura de un solo canal, debe crear un formato de imagen de un solo canal. Por lo tanto, en lugar de GL_LUMINANCE16, usa GL_R16UI, que es un formato de imagen integral sin firmar de un solo canal de 16 bits.

Ahora que tiene esta configuración correctamente, es bastante trivial. Defina un resultado de sombreador de fragmentos uint y haga que su sombreador de fragmentos escriba su valor uint. Este uint podría provenir del sombreador de vértices o de un uniforme; como quieras hacerlo

Obviamente también necesitarás adjuntar tu textura o renderbuffer a un FBO, pero estoy bastante seguro de que lo sabes.

Una última cosa: no utilice la frase "buffer de textura" a menos que se refiera a one of these. De lo contrario, se vuelve confuso.

+0

suena bien - aunque lo tengo trabajando con GL_LUMINANCE16 ya dividiendo mi ... por algunas razones que pueden hacer que en él - tal vez es sólo mi tarjeta de gráficos compatible con él? Si utilizo el formato de textura integral, ¿cómo puedo definir la salida int para un solo objetivo de renderizado? Utilizo adjuntos de 5 colores en mi sombreador, los primeros 4 representan otras cosas con texturas de flotante flotantes, y el 5to renderiza el ID de objeto. funciona ahora (usando GL_LUMINANCE16) pero tal vez solo estoy usando un comportamiento indefinido? Tengo un contexto OpenGL 4.2 – Mat

+0

@Mat: Debe declarar que la salida es 'int' para escribir en las salidas' int'. Además, teniendo en cuenta que esto funciona, supongo que tienes una tarjeta NVIDIA. –

+0

sí, tengo una tarjeta nvidia. pero ¿cómo puedo declarar un único componente de salida como int? Tengo la variable de salida de mi fragmentshader declarada como 'out vec4 out_colors [5]' – Mat

0

Supongo que su ID entero es un identificador para un conjunto de primitivas; de hecho, se puede definir como un uniforme de shader:

uniform int vertedObjectId; 

Una vez que rinda, que desea almacenar el procesamiento fragmento en una integer texture. Tenga en cuenta que las texturas enteras se muestrearán con números enteros (isampler2D), que devuelve vectores enteros (es decir, ivec3).

Esta textura se puede unir a un objeto framebuffer (tenga en cuenta framebuffer completeness). El uso de este dispositivo de fijación puede ser bound a un número entero variable de salida:

out int fragmentObjectId; 

void main() { 
    fragmentObjectId = vertedObjectId; 
} 

Es necesario unos pocos extensión es compatible, o una versión avanzada de OpenGL (3.2?).

5

Todavía no creo que haya una respuesta clara aquí.Así que aquí es lo que me hizo trabajar a través de una textura 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); 

En el lado GLSL el fragment shader debería tener (código de perfil 4.3 núcleo aquí):

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. 

} 

puedes leer los valores de el lado del host:

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); 
+1

Creo que la respuesta aceptada es un poco vaga. ¡Después de incontables horas, esto realmente me salvó el día! Muchas gracias señor –