OpenGL.Shader: implementação de 10 sombras - FBO gera bitmap de profundidade

OpenGL.Shader: bitmap de profundidade FBO de implementação de 10 sombras

 

Sinto que não publico um artigo há um tempo, por vários motivos. A principal razão é que recentemente estou um pouco ocupado e o conteúdo do novo artigo é um pouco excessivo e difícil, e leva tempo para ser preparado.

Em primeiro lugar, vamos revisar o FBO. Nossa prática simples anterior em OpenGL.ES no Android: 23-Gravação de marca d'água  apresentou o que é o FBO. Naquela época, nós o usamos para renderização fora da tela, com a ajuda de seu espaço de cor de buffer personalizado Resolva o problema de conflitos de transparência. Não vou repetir aqui a discussão sobre o que é um FBO. Deve-se enfatizar que um FBO é apenas um contêiner, que pode montar muitos tipos de objetos de renderização. Desta vez, precisamos usar outro novo buffer de profundidade de objeto de renderização.

Não fale bobagem, vá diretamente para 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

O código básico é o anterior. De acordo com a situação comum, eu dividi o FBO em dois tipos, FBO_DEPTH (modo de textura de profundidade) e FBO_RGBA (modo de textura de cor). Literalmente, FBO_RGBA é o tipo de uso introduzido antes. A diferença é que o RenderBuffer do ponto de fixação de profundidade (GL_DEPTH_ATTACHMENT) é adicionado desta vez. Isso ocorre porque estamos no modelo 3D desta vez e as informações de profundidade não podem ser ignoradas. Depois de enviarmos para o FBO, precisamos de um buffer para reter essas informações de profundidade. Esse fbo pode reter completamente todas as informações de que precisamos.

Para alunos que não entendem, tento comentar o código relacionado à profundidade —— renderbuffer. O efeito é o seguinte (desenhe o cubo primeiro e depois o chão):

Este é o efeito de nenhum dado de teste de profundidade, você pode imaginar o quão importante é esse buffer de renderização de profundidade. Aqui está uma breve introdução ao objeto de renderização RenderBuffer. Na verdade, é o mesmo tipo de objeto do Texture. Ambos são um objeto de contêiner usado para salvar a saída em OpenGL. O objeto de textura Texture é mais flexível e pode ser passado para o shader para uso, mas Às vezes, a textura não é uma panacéia. Assim como no exemplo atual, você precisa armazenar informações de cor, bem como informações de profundidade. Neste momento, Renderbuffer é útil.

 

Então, o que é um bitmap de profundidade? Vejamos o código acima. No modo FBO_DEPTH, a única diferença entre o bitmap de profundidade criado pela função createDepthTexture e createRgbaTexture são os parâmetros de glTexImage2D. Não olhe para esses parâmetros. Eu realmente pisei nesses parâmetros. Esses poços não são poços. Pesquisei em toda a rede, inclusive no google, e não tenho uma resposta clara. Vou te dizer o que acho. Se você entendeu bem, deixe uma mensagem de orientação.

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 ()); }








No OpenGL Wiki ( https://www.khronos.org/opengl/wiki/GLAPI/glTexImage2D ), a descrição do parâmetro de glTexImage2D, o terceiro parâmetro internalFormat é descrito da seguinte maneira:

internalFormat
Especifica o número de componentes de cor na textura. Deve ser um dos formatos internos de base fornecidos na Tabela 1, um dos formatos internos de tamanho fornecidos na Tabela 2, ou um dos formatos internos compactados fornecidos na Tabela 3, abaixo.

Em seguida, aponte para as três tabelas abaixo e leia as três tabelas com atenção. O ponto importante é que as tabelas 2 e 3 são na verdade Formatos internos de base que apontam para a Tabela 1. Sob o recorte GL ES no terminal móvel, apenas o GL_DEPTH_COMPONENT final é retido, e o resto GL_DEPTH_COMPONENT16 / GL_DEPTH_COMPONENT24 / GL_DEPTH_COMPONENT32F não são aplicáveis, mesmo se a GPU atual suportar quantas profundidades de bits (por meio de glGetIntegerv (GL_DEPTH_BITS, & depth_bits) consulta), configuração de profundidade de bits de configuração EGLDETH_CONTH_COMPENT_ (inicialização de GLOCHONTHONPOMPENT), use sempre a profundidade de bit de configuração EGLDETH_COMPENT_ONTH_CONTHON

Então, o penúltimo parâmetro Type é para determinar o que usar de acordo com a profundidade de bits definida por EGL, 8 bits = GL_UNSIGNED_BYTE, 16 bits = GL_UNSIGNED_SHORT;

Bem, após a configuração correta de depth_texture, podemos salvar o teste de profundidade de saída para a textura e enviá-lo como uma textura para a tela.

Todos prestam atenção ao bitmap de profundidade no canto superior esquerdo. No início, estamos perto do chão da perspectiva. Quanto mais perto estamos da frente, mais próximo o valor da profundidade está de 0. Então eu vi o contorno do cubo, e o chão atrás do cubo também mostrava profundidade. (Observe com atenção, o cinza é muito claro) Em seguida, libere outras partes do código para facilitar o entendimento.

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 é um tipo de objeto que utiliza projeção ortogonal para desenhar textura na tela, de forma muito simples e simples. Código de referência  https://github.com/MrZhaozhirong/NativeCppApp  -> ShadowFBORender.cpp / FrameBufferObject.hpp / PIPicture.hpp

No próximo capítulo, discutiremos como usar bitmaps de profundidade para obter sombras claras.

Acho que você gosta

Origin blog.csdn.net/a360940265a/article/details/100096152
Recomendado
Clasificación