OpenGL.Shader: 10-Shadow Implementation-FBO generiert eine Tiefenbitmap

OpenGL.Shader: 10-Shadow-Implementierung-FBO-Tiefenbitmap

 

Ich habe das Gefühl, dass ich seit einiger Zeit keinen Artikel mehr veröffentlicht habe. Es gibt viele Gründe. Der Hauptgrund ist, dass ich in letzter Zeit etwas beschäftigt bin und der Inhalt des neuen Artikels etwas zu zahlreich und schwierig ist und die Vorbereitung einige Zeit in Anspruch nimmt.

Lassen Sie uns zunächst den FBO überprüfen. Unsere bisherige einfache Vorgehensweise in OpenGL.ES unter Android: 23-Watermark Recording  hat das FBO vorgestellt. Zu diesem Zeitpunkt haben wir es mithilfe des benutzerdefinierten Pufferfarbraums für das Rendern außerhalb des Bildschirms verwendet. Lösen Sie das Problem der Transparenzkonflikte. Ich werde die Diskussion hier nicht wiederholen, was ein FBO ist. Es muss betont werden, dass ein FBO nur ein Container ist, der viele Arten von Rendering-Objekten bereitstellen kann. Dieses Mal müssen wir einen weiteren neuen Rendering-Objekttiefenpuffer verwenden.

Sprechen Sie keinen Unsinn, gehen Sie direkt zu FrameBufferObject.hpp

#pragma once
#ifndef FRAME_BUFFER_OBJECT_HPP
#define FRAME_BUFFER_OBJECT_HPP

#define FBO_NONE  0x0000
#define FBO_RGBA  0x0001
#define FBO_DEPTH 0x0002

#include <GLES3/gl3.h>
#include "zzr_common.h"

class   FrameBufferObject
{

public:
    unsigned int   _width;
    unsigned int   _height;
    unsigned int   _fboID;
    unsigned int   _rgbaTexId;
    unsigned int   _depthTexId;
    unsigned int   _depthRboId;
    unsigned int   _type;

public:
    FrameBufferObject()
    {
        _width  = 0;
        _height = 0;
        _fboID  = 0;
        _rgbaTexId = 0;
        _depthTexId = 0;
        _depthRboId = 0;
        _type   = FBO_NONE;
    }

    int getDepthTexId() {
        return _depthTexId;
    }
    int getRgbaTexId() {
        return _rgbaTexId;
    }
    bool    setup(int w, int h, int type)
    {
        _type = static_cast<unsigned int>(type);
        _width = static_cast<unsigned int>(w);
        _height = static_cast<unsigned int>(h);

        glGenFramebuffers(1, &_fboID);
        glBindFramebuffer(GL_FRAMEBUFFER, _fboID);

        if(_type == FBO_DEPTH) {
            createDepthTexture();
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexId, 0);
        }
        if(_type == FBO_RGBA) {
            createRgbaTexture();
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _rgbaTexId, 0);
            createDepthRenderBuffer();
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRboId);
        }

        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        GLenum err = glGetError();
        while(err!=GL_NO_ERROR) {
            LOGE("fbo.setup.glTexImage2D : 0x%08x\n", err);
            err = glGetError();
        }
        return  true;
    }

    void    begin()
    {
        GLenum err = glGetError();
        while(err!=GL_NO_ERROR) {
            LOGE("fbo.begin : 0x%08x\n", err);
            err = glGetError();
        }
        glBindFramebuffer(GL_FRAMEBUFFER, _fboID);

        if(_type == FBO_DEPTH) {
            glDrawBuffers(0, GL_NONE);
            glReadBuffer(GL_NONE);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexId, 0);
        }
        if(_type == FBO_RGBA) {
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _rgbaTexId, 0);
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRboId);
        }

        GLenum fbo_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        if(fbo_status!=GL_FRAMEBUFFER_COMPLETE) {
            LOGE("glCheckFramebufferStatus check err : 0x%08x\n", fbo_status);
        }
    }

    void    end()
    {
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }


private:
    void    createDepthTexture()
    {
        glGenTextures(1, &_depthTexId);
        glBindTexture(GL_TEXTURE_2D, _depthTexId);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _width, _height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0);
    }

    void    createRgbaTexture()
    {
        glGenTextures(1, &_rgbaTexId);
        glBindTexture(GL_TEXTURE_2D, _rgbaTexId);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, _width, _height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    }

    void    createDepthRenderBuffer()
    {
        glGenRenderbuffers( 1, &_depthRboId );
        glBindRenderbuffer( GL_RENDERBUFFER, _depthRboId );
        glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, _width, _height );
    }
};
#endif // FRAME_BUFFER_OBJECT_HPP

Der Basiscode ist wie oben. Entsprechend der allgemeinen Situation teile ich FBO in zwei Typen ein, FBO_DEPTH (Tiefenstrukturmodus) und FBO_RGBA (Farbtexturmodus). FBO_RGBA ist buchstäblich die zuvor eingeführte Art der Verwendung. Der Unterschied besteht darin, dass der RenderBuffer des Tiefenanhangspunkts (GL_DEPTH_ATTACHMENT) dieses Mal hinzugefügt wird. Dies liegt daran, dass wir uns diesmal im 3D-Modell befinden und die Tiefeninformationen nicht ignoriert werden können. Nach der Ausgabe an den FBO benötigen wir einen Puffer, um diese Tiefeninformationen beizubehalten. Ein solches fbo kann alle Informationen, die wir benötigen, vollständig speichern.

Für Schüler, die es nicht verstehen, versuche ich, den Code in Bezug auf die Tiefe zu kommentieren - Renderbuffer. Der Effekt ist wie folgt (zuerst den Würfel und dann den Boden zeichnen):

Dies ist der Effekt ohne Tiefentestdaten. Sie können sich vorstellen, wie wichtig dieser Tiefen-Renderpuffer ist. Hier ist eine kurze Einführung in das RenderBuffer-Rendering-Objekt. Es ist tatsächlich dieselbe Art von Dingen wie das Texture-Objekt. Beide sind Containerobjekte, die zum Speichern der Ausgabe in OpenGL verwendet werden. Das Texture-Objekt ist flexibler und kann zur Verwendung an den Shader übergeben werden Manchmal ist Textur kein Allheilmittel. Genau wie im aktuellen Beispiel müssen Sie sowohl Farbinformationen als auch Tiefeninformationen speichern. Zu diesem Zeitpunkt ist Renderbuffer praktisch.

 

Was ist eine Tiefenbitmap? Schauen wir uns den obigen Code an. In der Tiefenbitmap, die von der Funktion createDepthTexture im FBO_DEPTH-Modus erstellt wurde, liegt der einzige Unterschied zu createRgbaTexture in den Parametern von glTexImage2D. Sehen Sie sich diese Parameter nicht an. Ich habe das gesamte Netzwerk durchsucht, einschließlich Google, und es gab keine eindeutige Antwort. Ich werde Ihnen sagen, was ich denke. Wenn Sie es richtig verstehen können, hinterlassen Sie bitte eine Nachricht zur Orientierung.

void createDepthTexture ()
{         glGenTextures (1, & _depthTexId);         glBindTexture (GL_TEXTURE_2D, _depthTexId);         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);         glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);         glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, _width, _height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 0);         // LOGE ("createDepthTexture check err 4: 0x% 08x \ n", glGetError ()); }}








Im OpenGL-Wiki ( https://www.khronos.org/opengl/wiki/GLAPI/glTexImage2D ) wird die Parameterbeschreibung von glTexImage2D, dem dritten Parameter internalFormat, wie folgt beschrieben:

internalFormat
Gibt die Anzahl der Farbkomponenten in der Textur an. Muss eines der in Tabelle 1 angegebenen internen Basisformate, eines der in Tabelle 2 angegebenen internen Formate oder eines der in Tabelle 3 angegebenen komprimierten internen Formate sein.

Zeigen Sie dann auf die drei folgenden Tabellen und lesen Sie die drei Tabellen sorgfältig durch. Der wichtige Punkt ist, dass die Tabellen 2 und 3 tatsächlich interne Basisformate sind, die auf Tabelle 1 verweisen. Unter dem GL ES-Clipping auf dem mobilen Endgerät bleibt nur der endgültige GL_DEPTH_COMPONENT und der Rest erhalten GL_DEPTH_COMPONENT16 / GL_DEPTH_COMPONENT24 / GL_DEPTH_COMPONENT32F sind nicht anwendbar, unabhängig davon, wie viele Bittiefen die aktuelle GPU unterstützt (Abfrage über glGetIntegerv (GL_DEPTH_BITS, & depth_bits)), wie viele Bittiefen für EGLON_P werden

Dann bestimmt der vorletzte Parameter Typ, was gemäß der von EGL festgelegten Bittiefe verwendet werden soll: 8 Bit = GL_UNSIGNED_BYTE, 16 Bit = GL_UNSIGNED_SHORT;

Nun, nach der korrekten Konfiguration von depth_texture können wir den Ausgabetiefen-Test in der Textur speichern und als Textur auf dem Bildschirm ausgeben.

Jeder achtet auf die Tiefenbitmap in der oberen linken Ecke. Zu Beginn befinden wir uns aus der Perspektive nahe am Boden. Je näher wir an der Vorderseite sind, desto näher ist der Tiefenwert an 0. Dann sah ich den Umriss des Würfels und der Boden hinter dem Würfel zeigte auch Tiefe. (Schauen Sie genau hin, das Grau ist sehr hell.) Lassen Sie dann andere Teile des Codes los, um das Verständnis zu erleichtern.

void ShadowFBORender::renderOnDraw(double elpasedInMilliSec)
{
    if (mEglCore == NULL || mWindowSurface == NULL) {
        LOGW("Skipping drawFrame after shutdown");
        return;
    }
    mWindowSurface->makeCurrent();

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    glViewport(0,0, mViewWidth, mViewHeight);
    lightCube.render(mCamera3D);
    land.render(mCamera3D);

    renderDepthFBO();

    mWindowSurface->swapBuffers();
}

void ShadowFBORender::renderDepthFBO() {
    depthFBO.begin();
    {
        glEnable(GL_DEPTH_TEST);
        glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
        glClearDepthf(1.0f);
        lightCube.render(mCamera3D);
        land.render(mCamera3D);
    }
    depthFBO.end();

    pip.setTextureId(depthFBO.getDepthTexId()); // 深度纹理
    //pip.setTextureId(depthFBO.getRgbaTexId());// 彩色纹理
    pip.render();
}

pip-> PIPicture ist eine Art Objekt, das eine orthogonale Projektion verwendet, um Texturen auf dem Bildschirm zu zeichnen. Es ist sehr einfach und unkompliziert. Referenzcode  https://github.com/MrZhaozhirong/NativeCppApp  -> ShadowFBORender.cpp / FrameBufferObject.hpp / PIPicture.hpp

Im nächsten Kapitel werden wir diskutieren, wie Tiefenbitmaps verwendet werden, um Lichtschatten zu erzielen.

Ich denke du magst

Origin blog.csdn.net/a360940265a/article/details/100096152
Empfohlen
Rangfolge