Bekommen Sie eine Textur aus einem Renderbuffer in OpenGL?

13

Ich habe einen Renderbuffer (DepthStencil) in einem FBO und muss eine Textur daraus erhalten. Es scheint, dass ich im FBO nicht sowohl eine DepthComponent-Textur als auch einen DepthStencil-Renderbuffer haben kann. Ich brauche also eine Möglichkeit, den Renderbuffer in eine DepthComponent-Textur umzuwandeln, nachdem ich ihn für die spätere Verwendung in der Pipeline fertiggestellt habe.

Ich habe wochenlang viele Techniken ausprobiert, um die Tiefenkomponente aus dem Renderbuffer zu holen, aber ich komme immer mit Junk raus. Alles, was ich am Ende möchte, ist die gleiche Textur, die ich von einem FBO erhalten würde, wenn ich keinen Renderbuffer verwenden würde. Kann jemand eine umfassende Anleitung oder einen Code veröffentlichen, der diese scheinbar einfache Operation behandelt?

BEARBEITEN:

Link zu einer Extraktversion des Codes http://dl.dropbox.com/u/9279501/fbo.cs

Screeny des Tiefenschärfeeffekts + FBO - ohne Tiefenschärfe (!) Http://i.stack.imgur.com/Hj9Oe.jpg

Screeny ohne Schärfentiefeeffekt + FBO - Schärfentiefe funktioniert einwandfrei http://i.stack.imgur.com/boOm1.jpg

Rushyo
quelle

Antworten:

2

Alternativ können Sie einfach von einem FBO zu einem anderen wechseln, z. B. von einem Renderbuffer-basierten zu einem Textur-basierten. Ich mache es so:

glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_renderBufferSurface->m_fbo);
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_textureSurface->m_fbo);
glBlitFramebufferEXT(0, 0, m_renderBufferSurface->m_width, m_renderBufferSurface->m_height, 0, 0, m_textureSurface->m_width, m_textureSurface->m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

(In Ihrem Fall, in dem Sie den Puffer vertiefen möchten, können Sie GL_DEPTH_BUFFER_BIT anstelle von GL_COLOR_BUFFER_BIT verwenden.)

Nach dem Einblenden in den texturbasierten Renderbuffer können Sie die Textur wie gewohnt verwenden. Weitergabe an Shader als Uniform oder was auch immer Sie möchten.

Trevor Powell
quelle
1

Nein, das geht nicht. Sie können die Daten höchstens in glReadPixels auf die CPU übertragen und daraus eine Textur erstellen. Dies ist jedoch umständlich und langsam. Renderbuffer sind nicht dafür gedacht, dass Funktionalität nur durch Texturen bereitgestellt wird.

Matias Valdenegro
quelle
Was ist angesichts dessen die Alternative? Wie können Sie die Tiefe in Ihrem Zeichenpuffer beibehalten und auch die Tiefenkomponente als Textur erfassen?
Rushyo
@Rushyo: Eine Alternative könnte sein, den Schablonenpuffer loszuwerden (wenn möglich!) Und den Tiefenrenderbuffer zu einer Tiefenstruktur zu machen. Warum benutzt du eine Schablone?
Calvin1602
Grundsätzlich brechen meine Tiefentests immer dann, wenn ich die Tiefenstruktur erhalte. Wenn ich meinem FBO einen Tiefenvorsatz anhänge, schreibt der FBO keine Tiefeninformationen an eine andere Stelle. Wenn ich also versuche, den Farbvorsatz abzurufen, werden keine Tiefenprüfungen durchgeführt (was normalerweise der Fall ist, wenn ich keinen Tiefenvorsatz habe) ). Ich habe jede mir in den Sinn kommende Kombination ausprobiert, einschließlich der oben erwähnten "umständlichen und langsamen" Methode. Was auch immer ich tue, ich kann nicht sowohl ein "typisches" Rendering meiner Szene in einer Textur als auch nur die Tiefe in einer anderen bekommen.
Rushyo
@ Calvin1602 Als ich mit dem Renderbuffer experimentierte, stellte ich fest, dass die Verwendung des Tiefenvorsatzes ohne den Schablonenvorsatz zu unerwünschten Ergebnissen führte.
Rushyo
@ Rushyo Ich wette, Sie richten die Textur nicht richtig ein, die Postleitzahl wird es uns ermöglichen, zu helfen :)
Matias Valdenegro
1

Was Sie fragen, ist in OpenGL 3.2 möglich. Mein FBO spuckt diffuse Farbe auf eine Farbtextur aus, Normalen auf eine andere Farbtextur und Tiefe auf eine Tiefentextur - es werden keine Renderbuffer benötigt. Tatsächlich stellen Renderbuffer nur ein Problem dar, da Sie keine Samples daraus erstellen können. Sie müssten also glReadPixels(...)die Daten aus dem RBO in eine Textur auf der CPU kopieren oder anderweitig verwenden, anstatt nur alles im GPU-Speicher zu behalten. So...

Wenn Sie wirklich wollen, können Sie Code in Ihren First-Pass-Shader schreiben, um Inhalte wie die Tiefe manuell in einem separaten Farbtextur-Anhang in Ihrem FBO auszugeben. Das wäre für Sie in Ihren Post-Pass-Shadern von Nutzen . Für die Verwendung von OpenGL beim internen Tiefentest benötigen Sie zusätzlich entweder einen RBO oder ein Textur-Set als GL_DEPTH_ATTACHMENT Ihres FBO. Sie können jedoch eine einzige Textur einrichten, um beide zu bedienen - dies ist effizienter und einfacher zu handhaben.

Mein Setup-Code für die Tiefenstruktur sieht folgendermaßen aus (Java, ignoriere einfach das ByteBuffer-Zeug ... und beachte, dass ich "id" verwende, um auf ganzzahlige Handles / Zeiger zu verweisen, da dieses Konzept in Java nicht wirklich gut funktioniert):

        gBufferDepthTexture = new Texture();
        gBufferDepthTexture.id = glGenTextures();
        gBufferDepthTexture.unit = 2;
        gBufferDepthTexture.width = Display.getWidth();
        gBufferDepthTexture.height = Display.getHeight();
        gBufferDepthTexture.bytes = ByteBuffer.allocateDirect(Display.getWidth()*Display.getHeight() * 4);
        glActiveTexture(gBufferDepthTexture.unit + GL_TEXTURE0); //eg. 0 + 33984 = GL_TEXTURE0, while 31 + 33984 = GL_TEXTURE31.
        glBindTexture(GL_TEXTURE_2D, gBufferDepthTexture.id);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, gBufferDepthTexture.width, gBufferDepthTexture.height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, gBufferDepthTexture.bytes);
        //...GL_UNSIGNED_INT or GL_UNSIGNED_BYTE may work better for you, instead... YMMV.

        //glPixelStorei(GL_PACK_ALIGNMENT, 4);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

Und später:

        glBindFrameBuffer(GL_DRAW_FRAMEBUFFER, fbo.id);
        //your existing glFramebufferTexture2D(...) calls here
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gBufferDepthTexture.id, 0);

Sie können jetzt gBufferDepthTexture(oder was haben Sie) als Uniform an Ihre Fragment-Shader des zweiten und dritten Durchgangs übergeben. Ich denke, wir können davon ausgehen, dass Sie mit dem Schablonenpuffer genau dasselbe tun können.

Ingenieur
quelle
0

Sie sollten in der Lage sein, eine Textur (anstelle eines RenderBuffers) im Format GL_DEPTH_STENCIL zu erstellen. Ich bin mir nicht sicher, wie genau die Tiefe einer solchen Textur in einem Shader-Programm verwendet werden soll (was Sie vermutlich verwenden, da Sie FBOs verwenden), aber in der OpenGL-Spezifikation sollte angegeben werden, welche Farbkanäle welche Werte erhalten ( Ich schätze, dass R, G und B alle auf Tiefe und A auf Schablone gesetzt werden.

Ich arbeite derzeit mit OpenGL 3.2, daher müssen Sie möglicherweise überprüfen, ob das Texturformat für Sie geeignet ist. Ich kann mich nie erinnern, welche Versionen unterschiedliche Funktionen bieten.

Branan
quelle
Das Problem besteht dann nicht darin, die GL_DEPTH_STENCIL-Komponente in einer Textur zu erfassen, sondern darin, dass alle Tiefeninformationen im FBO verloren gehen, wenn Sie dies tun. Der FBO wird für das Rendern der Szene in den Zeichenpuffer unbrauchbar. Daher habe ich einen Renderbuffer verwendet, um dieses Problem zu umgehen. Ich denke, im Moment habe ich keine andere Wahl, als zwei Durchgänge zu machen, um die Tiefe zu erfassen + Informationen separat zu zeichnen = (teurer als je zuvor, bis ich einen Ausweg finden kann.
Rushyo
@ Rushyo Ich habe eine Antwort auf diese alte Frage gepostet :) Vielleicht möchten Sie einen Blick darauf werfen, obwohl Sie dies wahrscheinlich vor Jahren gelöst haben.
Ingenieur
@ NickWiggill Ich wünschte! Fudged etwas und ging mit meinem Leben weiter. Ich kann Ihre Antwort erst testen, wenn ich die in diesem Prototyp verwendeten Assets neu erstellt habe.
Könnte sich