OpenGL.Shader: 10-Shadow implementation-FBO génère un bitmap de profondeur

OpenGL.Shader: bitmap de profondeur d'implémentation 10-Shadow-FBO

 

J'ai l'impression de ne pas avoir publié d'article depuis un moment, il y a plusieurs raisons. La raison principale est que je suis un peu occupé récemment, et le contenu du nouvel article est un peu trop nombreux et difficile, et il faut du temps pour se préparer complètement.

Tout d'abord, passons en revue le FBO. Notre pratique simple précédente dans OpenGL.ES sur Android: l'enregistrement 23-filigrane a  présenté ce qu'est FBO. À l'époque, nous l'avons utilisé pour le rendu hors écran à l'aide de son espace colorimétrique de tampon personnalisé Résolvez le problème des conflits de transparence. Je ne répéterai pas la discussion sur ce qu'est un FBO ici.Il faut souligner qu'un FBO n'est qu'un conteneur, qui peut monter de nombreux types d'objets de rendu. Cette fois, nous devons utiliser un autre nouveau tampon de profondeur d'objet de rendu.

Ne dites pas de bêtises, accédez directement à 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

Le code de base est comme ci-dessus. Selon la situation courante, j'ai divisé FBO en deux types, FBO_DEPTH (mode de texture de profondeur) et FBO_RGBA (mode de texture de couleur). Littéralement, FBO_RGBA est le type d'utilisation introduit auparavant. La différence est que le RenderBuffer du point d'attachement de profondeur (GL_DEPTH_ATTACHMENT) est ajouté cette fois. C'est parce que nous sommes dans le modèle 3D cette fois et que les informations de profondeur ne peuvent pas être ignorées. Une fois que nous les avons générées au FBO, nous avons besoin d'un tampon pour conserver ces informations de profondeur. Un tel fbo peut conserver complètement toutes les informations dont nous avons besoin.

Pour les étudiants qui ne comprennent pas, j'essaie de commenter le code lié à la profondeur —— renderbuffer. L'effet est le suivant (dessinez d'abord le cube puis le sol):

C'est l'effet de l'absence de données de test de profondeur, vous pouvez imaginer à quel point ce tampon de rendu de profondeur est important. Voici une brève introduction à l'objet de rendu RenderBuffer. Il s'agit en fait du même type de chose que l'objet Texture. Ils sont tous deux un objet conteneur utilisé pour enregistrer la sortie dans OpenGL. L'objet Texture Texture est plus flexible et peut être transmis au shader pour utilisation, mais Parfois, la texture n'est pas une panacée. Tout comme l'exemple actuel, vous devez stocker des informations de couleur ainsi que des informations de profondeur. Pour le moment, Renderbuffer est très pratique.

 

Alors, qu'est-ce qu'un bitmap de profondeur? Regardons le code ci-dessus. En mode FBO_DEPTH, la seule différence entre le bitmap de profondeur créé par la fonction createDepthTexture et createRgbaTexture est les paramètres de glTexImage2D. Ne regardez pas ces paramètres. J'ai vraiment marché sur ces paramètres. Ces fosses ne sont pas des fosses. J'ai parcouru l'ensemble du réseau, y compris Google, et je n'ai pas trouvé de réponse claire. Je vais vous dire ce que j'en pense. Si vous pouvez le comprendre correctement, veuillez laisser un message à titre indicatif.

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 ("erreur de vérification de createDepthTexture 4: 0x% 08x \ n", glGetError ()); }








Dans le Wiki OpenGL ( https://www.khronos.org/opengl/wiki/GLAPI/glTexImage2D ), la description du paramètre de glTexImage2D, le troisième paramètre internalFormat est décrit comme suit:

internalFormat
Spécifie le nombre de composants de couleur dans la texture. Doit être l'un des formats internes de base indiqués dans le tableau 1, l'un des formats internes dimensionnés indiqués dans le tableau 2, ou l'un des formats internes compressés indiqués dans le tableau 3 ci-dessous.

Puis pointez vers les trois tableaux ci-dessous et lisez attentivement les trois tableaux. Le point important est que les tableaux 2 et 3 sont en fait des formats internes de base qui pointent vers le tableau 1. Sous le découpage GL ES du terminal mobile, seul le GL_DEPTH_COMPONENT final est conservé, et le reste GL_DEPTH_COMPONENT16 / GL_DEPTH_COMPONENT24 / GL_DEPTH_COMPONENT32F ne sont pas applicables, quel que soit le nombre de profondeurs de bits prises en charge par le GPU actuel (requête via glGetIntegerv (GL_DEPTH_BITS, & depth_bits)), combien de profondeurs de bits sont toujours configurées pour EGPOM_THPONTH_GL_DEPOM (Eglore)

Ensuite, l'avant-dernier paramètre Type consiste à déterminer ce qu'il faut utiliser en fonction de la profondeur de bits définie par EGL, 8 bits = GL_UNSIGNED_BYTE, 16 bits = GL_UNSIGNED_SHORT;

Eh bien, après la configuration correcte de depth_texture, nous pouvons enregistrer le test de profondeur de sortie dans la texture et le sortir en tant que texture à l'écran.

Tout le monde fait attention au bitmap de profondeur dans le coin supérieur gauche. Au début, nous sommes près du sol du point de vue. Plus nous sommes près de l'avant, plus la valeur de profondeur est proche de 0. Ensuite, j'ai vu le contour du cube et le sol derrière le cube montrait également de la profondeur. (Regardez attentivement, le gris est très clair) Ensuite, relâchez d'autres parties du code pour une compréhension facile.

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 est une sorte d'objet qui utilise la projection orthogonale pour dessiner une texture sur l'écran, c'est très simple et simple. Code de référence  https://github.com/MrZhaozhirong/NativeCppApp  -> ShadowFBORender.cpp / FrameBufferObject.hpp / PIPicture.hpp

Dans le chapitre suivant, nous verrons comment utiliser les bitmaps de profondeur pour obtenir des ombres claires.

Je suppose que tu aimes

Origine blog.csdn.net/a360940265a/article/details/100096152
conseillé
Classement