2012-05-12 16 views
6

Wie richte ich richtig eine Integer-ID eines Objekts zu einem Integer-Textur-Puffer?glsl fragmentshader render objectID

Angenommen, ich habe ein texture2D mit dem internen Format GL_LUMINANCE16 und ich füge es als Farbanhang an meinen FBO an.

Beim Rendern eines Objekts gebe ich eine Integer-ID an den Shader und möchte diese ID in meine Integer-Textur rendern.

Fragmentshader-Ausgabe ist jedoch vom Typ Vec4. Wie kann ich meine ID korrekt in vier Komponenten float umwandeln und Konvertierungsungenauigkeiten vermeiden, so dass der Ganzzahlwert in meinem ganzzahligen Texturziel letztendlich der Ganzzahl-ID entspricht, die ich rendern wollte?

Antwort

4

Es gibt einige Probleme mit Ihrer Frage.

Zuerst ist GL_LUMINANCE16nicht eine "Integer-Textur." Es ist eine Textur, die normalisierte vorzeichenlose Ganzzahlwerte enthält. Es verwendet Integer, um Floats im Bereich [0, 1] darzustellen. Wenn Sie tatsächliche Ganzzahlen speichern möchten, müssen Sie eine tatsächliche integer image format verwenden.

Zweitens können Sie nicht zu einer Luminanztextur rendern; Sie sind keine farbwiedergabefähigen Formate. Wenn Sie tatsächlich zu einer einkanaligen Textur rendern möchten, müssen Sie ein einkanaliges Bildformat erstellen. Anstatt GL_LUMINANCE16 verwenden Sie GL_R16UI, das ist ein 16-Bit-Single-Channel-vorzeichenloses integrales Bildformat.

Jetzt, da Sie diese Einrichtung korrekt eingerichtet haben, ist es ziemlich trivial. Definieren Sie eine uint Fragment-Shader-Ausgabe und lassen Sie Ihren Fragment-Shader Ihren uint-Wert darauf schreiben. Diese uint könnte aus dem Vertex-Shader oder aus einer Uniform kommen; wie auch immer du es machen willst.

Natürlich müssen Sie auch Ihre Textur oder renderbuffer zu einem FBO, aber ich bin mir ziemlich sicher, dass Sie das wissen.

Eine letzte Sache: Verwenden Sie nicht den Ausdruck "Textur-Puffer", wenn Sie nicht meinen, one of these. Ansonsten wird es verwirrend.

+0

klingt gut - obwohl ich es mit GL_LUMINANCE16 Arbeit bekam bereits durch Dividieren meine ... für einige Gründe, warum ich in sie machen kann - vielleicht ist es nur meine Grafikkarte, die es unterstützt? Wenn ich das integrale Texturformat verwende, wie kann ich die int-Ausgabe für nur ein Renderziel definieren? Ich verwende 5 Farbanhänge in meinem Shader, die ersten 4 rendere andere Dinge in Fließkomma-Texturen, die 5. rendere die objectId. Es funktioniert jetzt (mit GL_LUMINANCE16), aber vielleicht verwende ich nur undefiniertes Verhalten? Ich habe einen OpenGL 4.2 Kontext – Mat

+0

@Mat: Sie müssen die Ausgabe zu einem 'int' deklarieren, um auf' int' Ausgaben zu schreiben. Wenn man bedenkt, dass dies funktioniert, nehme ich an, dass Sie eine NVIDIA-Karte haben. –

+0

ja ich habe eine nvidia-karte. aber wie kann ich eine einzelne Ausgabekomponente als int deklarieren? Ich habe die out-Variable von meinem fragmentshader deklariert als 'out vec4 out_colors [5] ' – Mat

0

Ich nehme an, dass Ihre Ganzzahl-ID eine Kennung für eine Reihe von Primitiven ist; in der Tat kann es als Shader einheitlich definiert werden:

uniform int vertedObjectId; 

Sobald Sie machen, können Sie das Fragment Verarbeitung in eine integer texture speichern möchten. Man beachte, dass Integer-Texturen mit Integer Samplern (isampler2D), die ganze Zahlen Vektoren (d. H. ivec3) zurückgibt, abgetastet werden.

Diese Textur kann an ein Framebuffer-Objekt angehängt werden (beachten Sie framebuffer completeness). Die Framebuffer-Befestigung kann bound auf eine ganzzahligen Ausgangsgröße sein:

out int fragmentObjectId; 

void main() { 
    fragmentObjectId = vertedObjectId; 
} 

Sie benötigen ein paar Erweiterung unterstützt, oder eine erweiterte OpenGL-Version (3.2?).

5

Ich glaube immer noch nicht, dass es hier eine klare Antwort gibt.Also hier ist, wie ich habe es durch eine 2D-Textur arbeiten:

// 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); 

Auf der GLSL Seite sollte das Fragment-Shader (4.3 Kernprofil Code hier) haben:

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. 

} 

Sie können die Werte weiter lesen die Host-Seite:

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

Ich denke, akzeptierte Antwort ist ein bisschen vage. Nach unzähligen Stunden hat das meinen Tag gerettet! Danke, mein guter Herr –