• <


    这里主要讨论 Bloom效果引发的各种问题,及其解决方案。

    记录几个高斯模糊的做法:

    https://www.shadertoy.com/view/XdfGDH

    https://www.shadertoy.com/view/ltScRG

    https://gamedev.stackexchange.com/questions/166182/my-single-pass-gaussian-blur-looks-awful

    https://github.com/Jam3/glsl-fast-gaussian-blur

    原作者的做法这样的:

    注意原作者的贴图从头到尾都不是抗锯齿(MSAA),所以操作起来一路顺手。而且场景也简单就几个贴图。

    梁大大已经告诉我MSAA是废品,让我考虑FXAA。

    而我的做法是:

    hdrFBO里的纹理是多重采样纹理。我一开始想的是直接用FBO一步传递到一个postprocessing的buffer中处理。

    也就是渲染只分2部分,一部分渲染场景,第二部分把这个渲染的2个buffer传递到postprocessing先测试。

    遇到的问题就是:

    1,hdrFBO多重采样纹理FBO渲染场景完成之后必须拷贝到post processing 的FBO.

    2,hdrFBO多重采样FBO的第一个场景纹理复制过去到post processing没问题。

    3,hdrFBO多重采样的第二个Texture(也就是第二个color attachment)是个多重采样纹理,要传递到post的材质,需要这么传:

    4,顺便认识到MSAA的这种设计,直接限制了代码,让代码可以写的更烂

    vec4 textureMSAA(sampler2DMS tex,vec2 TexCoords){
    
        ivec2 texSize = textureSize(tex);
        vec4 mtex=vec4(1);
        for(int i = 0; i < 32; ++i)
        {
            mtex += texelFetch(tex, ivec2(TexCoords*texSize ), i);
        }
        mtex = mtex / 32.0f;
        return mtex;
    }
    textureMSAA函数
    #version 450 core
    #extension GL_ARB_shading_language_include : require
    #include "/shaders/common/utils.glsl"
    #include "/shaders/common/postprocess.glsl"
    out vec4 FragColor;
    in vec2 TexCoords;
    uniform sampler2D sceneImage;
    uniform sampler2DMS brightImage;
    uniform float exposure;
    void main()
    {
        vec4 scene = texture(sceneImage,TexCoords);
        vec4 mtex = textureMSAA(brightImage,TexCoords);
        vec3 result = toneMapping(scene.rgb, exposure);
        FragColor = vec4(result,1.0f);
    
    }

    到这里顺便复习下以前做过的相关的Framebuffer和这个Quad post processing的关系。为什么有时候postprocessing需要个framebuffer?为什么有时候不要:

    接下来现在用2中方案实现:思路如下:

    实际中别用第一个方案,比较垃圾,直接第二个,把multisample color attachment 转换成普通的GL_TEXTURE_2D。然后就各种后期效果就行。 

    多采样代码,注意里面的32 samplers,是在一开始设置framebuffer,renderbuffer就要提前设置好的,平常应该用unifrom int samplers从C++传入:

    vec4 textureMSAA(sampler2DMS tex,vec2 TexCoords){
    
        ivec2 texSize = textureSize(tex);
        vec4 mtex=vec4(1);
        for(int i = 0; i < 32; ++i)
        {
            mtex += texelFetch(tex, ivec2(TexCoords*texSize ), i);
        }
        mtex = mtex / 32.0f;
        return mtex;
    }

    转换的伪代码就是:

    // 2020 4 6
    // This shader for convert multisampled buffer with multi attachements
    // to basis GL_TEXTURE_2D
    // frag file export two attachents, and input sampler2dMS texture
    
    
    #version 450 core
    #extension GL_ARB_shading_language_include : require
    #include "/shaders/common/utils.glsl"
    
    
    in vec2 TexCoords;
    
    layout (location = 0 ) out vec4 colorAttament0;
    layout (location = 1 ) out vec4 colorAttament1;
    layout (location = 2 ) out vec4 colorAttament2;
    layout (location = 3 ) out vec4 colorAttament3;
    layout (location = 4 ) out vec4 colorAttament4;
    layout (location = 5 ) out vec4 colorAttament5;
    layout (location = 6 ) out vec4 colorAttament6;
    
    // ... and you can export more texture , C++ code need:
    // static FrameBufferAttachments<GL_RGBA16F,6> convertFBO;
    
    
    
    
    // for study opengl, writing with hard code
    // for best should use a uniform texture count : uniform int texCount;
    // and: uniform sampler2dMS mtexs[texCount]
    
    uniform sampler2DMS mtex0;
    uniform sampler2DMS mtex1;
    uniform sampler2DMS mtex2;
    uniform sampler2DMS mtex3;
    uniform sampler2DMS mtex4;
    uniform sampler2DMS mtex5;
    uniform sampler2DMS mtex6;
    
    void main()
    {
    
        colorAttament0 = textureMSAA(mtex0, TexCoords);
        colorAttament1 = textureMSAA(mtex1, TexCoords);
        colorAttament2 = textureMSAA(mtex2, TexCoords);
        colorAttament3 = textureMSAA(mtex3, TexCoords);
        colorAttament4 = textureMSAA(mtex4, TexCoords);
        colorAttament5 = textureMSAA(mtex5, TexCoords);
        colorAttament6 = textureMSAA(mtex6, TexCoords);
    
    
    }

    CP36:

    逻辑:

       int display_w, display_h;
        glfwGetFramebufferSize(frameWindow->getWindow(), &display_w, &display_h);
    
        glm::mat4 view = camera->GetViewMatrix();
        glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f,  1000.0f);
        // object world transformation
        glm::mat4 model = glm::mat4(1.0f);
    
        // per-frame time logic
                // --------------------
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
    
    
    
        ImGui::Begin("Distance Light Params");
        ImGui::ColorEdit3("color", color);
        ImGui::SliderFloat("lightIntensity",&intensity,0,10.0f);
        ImGui::SliderFloat("shadowNear",&shadowNear,1,10.0f);
        ImGui::SliderFloat("shadowFar",&shadowFar,100,800.0f);
        distanceLight.setShadowNearFarPlane(shadowNear,shadowFar);
        // ----------------------------------- RENDER SHADOW MAP -----------------------------------
        // 1. render depth of scene to texture (from light's perspective)
    
        glViewport(0, 0, distanceLight.shadowPtr->width, distanceLight.shadowPtr->height);
        glBindFramebuffer(GL_FRAMEBUFFER, distanceLight.shadowPtr->fbo);
        glClear(GL_DEPTH_BUFFER_BIT);
        //distanceLight.setDir(glm::vec3())
        distanceLight.renderUseDepthShader();
    
        // Render SceneAssembly in depth shadow shader
        RenderScene(model,distanceLight.shadowPtr->lightView,distanceLight.shadowPtr->lightProjection,&distanceLight.shadowPtr->shader);
        // ----------------------------------- RENDER SHADOW MAP -----------------------------------
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        ImGui::End();
    
    
        // 2.---------------render scene as normal ,draw scene as normal in multisampled buffers---------------
        glViewport(0, 0, display_w, display_w/2);
        hdrMultiSamplerFBO.update(display_w,display_w/2);
        // update render buffer
        UpdateMultiSampledRenderBufferObject(display_w, display_w/2,multiRBO,samplers);
        glBindFramebuffer(GL_FRAMEBUFFER, hdrMultiSamplerFBO.fbo);       // BIND TO MULTI sampled fbo
        hdrMultiSamplerFBO.drawBuffers();
        ClearAllBufferColor();
        glEnable(GL_DEPTH_TEST);
        RenderScene(model,view,projection);
        RenderGridAndGnomon(view,projection);
        // render distance light in multiFBO
        distanceLight.setLightIntensity(intensity);
        distanceLight.shader.use();
        distanceLight.shader.setMatrix(view,projection);
        distanceLight.setLightColor(glm::vec3(color[0] ,color[1],color[2] ));
        distanceLight.draw();
         // 2.---------------render scene as normal ,draw scene as normal in multisampled buffers---------------
    
    
    
    
    
        // 3----------------------------- Render Scene to ConvertFBO ------------------------
    
        glViewport(0, 0, display_w, display_w/2);
        convertFBO.update(display_w, display_w/2);
        convertPostProcess.update(display_w,display_w/2);
        convertFBO.drawBuffers();
        glBindFramebuffer(GL_FRAMEBUFFER, convertFBO.fbo);; // render quad in convert FBO
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        convertPostProcess.shader.use();
    
        glActiveTexture(hdrMultiSamplerFBO.texChannels[0]);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, hdrMultiSamplerFBO.textures[0]);
        glActiveTexture(hdrMultiSamplerFBO.texChannels[1]);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, hdrMultiSamplerFBO.textures[1]);
        convertPostProcess.shader.setInt("tex0",hdrMultiSamplerFBO.texUnits[0]);
        convertPostProcess.shader.setInt("tex1",hdrMultiSamplerFBO.texUnits[1]);
        /*
        // This code verty simple, and it's do not use texture unit
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, hdrMultiSamplerFBO.textures[0]);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, hdrMultiSamplerFBO.textures[1]);
        convertPostProcess.shader.setInt("tex0",0);
        convertPostProcess.shader.setInt("tex1",1);
        */
    
        convertPostProcess.draw();
    
        // 3----------------------------- Render Scene to ConvertFBO ------------------------
    
    
    
    
        // 4 ------------- RENDER TO Post processing FBO -----------------
    
    #if 1
        // use the convert FBO texture for final processing FBO
        toneMapping.update(display_w,display_w/2);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        toneMapping.shader.use();
        /*
        // // This code use texture unit
        glActiveTexture(convertFBO.texChannels[0]);
        glBindTexture(GL_TEXTURE_2D,convertFBO.textures[0]);
        toneMapping.shader.setInt("sceneImage", convertFBO.texUnits[0]);
    
        glActiveTexture(convertFBO.texChannels[1]);
        glBindTexture(GL_TEXTURE_2D,convertFBO.textures[1]);
        toneMapping.shader.setInt("brightImage", convertFBO.texUnits[1]);
        */
    
        //This code very simple, and it's do not use texture unit
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D,convertFBO.textures[0]);
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D,convertFBO.textures[1]);
        toneMapping.shader.setInt("sceneImage", 0);
        toneMapping.shader.setInt("brightImage", 1);
        toneMapping.shader.setFloat("exposure",4.0f);
        toneMapping.draw();
    
    #else
        toneMapping.update(display_w,display_w/2);
        CopyFrameBuffer(hdrMultiSamplerFBO.fbo, toneMapping.FBO, display_w, display_w / 2);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
        ClearAllBufferColor();
        toneMapping.shader.use();
    
    
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D,toneMapping.FBOTexture);
        toneMapping.shader.setInt("sceneImage", 0);
    
        glActiveTexture(hdrMultiSamplerFBO.texChannels[1]);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE,hdrMultiSamplerFBO.textures[1]);
        toneMapping.shader.setInt("brightImage", hdrMultiSamplerFBO.texUnits[1]);
    
        toneMapping.shader.setFloat("exposure",4.0f);
        toneMapping.draw();
    #endif
    View Code

    init:

    // framebuffer
    static MultiSampledFrameBufferAttachments<GL_RGBA16F,2> hdrMultiSamplerFBO;  // multisampler with two attachment
    static GLuint multiRBO; // renderbuffer
    static DrawPostProcessingQuad convertPostProcess;
    static FrameBufferAttachments<GL_RGBA16F,2> convertFBO;  // multisampler convert to GL_TEXTURE_2D two attachment
    //
        cout << "---------------- STARTING HDR Sampled FrameBuffer -----------
     ";
        // Create MultiSampler Framebuffer with two attached texture
        hdrMultiSamplerFBO.initialize(SRC_WIDTH,SRC_HEIGHT,samplers);
        hdrMultiSamplerFBO.setUpTexChannels(SceneAssembly::currentActiveTextureChannel,SceneAssembly::currentTextureLoaderIndex);
        hdrMultiSamplerFBO.drawBuffers();
        hdrMultiSamplerFBO.debug();
        cout << "---------------- ENDING HDR Sampled FrameBuffer -----------
     ";
    
    
        CreateMultiSampledRenderBufferObject(SRC_WIDTH, SRC_HEIGHT, multiRBO, samplers);
    
    
    
        cout << "
    ---------------- STARTING Convert FrameBuffer -----------
     ";
        // Create Convert Framebuffer with two attached texture
        convertFBO.initialize(SRC_WIDTH,SRC_HEIGHT);
        convertFBO.setUpTexChannels(SceneAssembly::currentActiveTextureChannel,SceneAssembly::currentTextureLoaderIndex);
        convertFBO.drawBuffers();
        convertFBO.debug();
        cout << "next
    ";
        cout << "---------------- ENDING Convert FrameBuffer -----------
     ";

    CP_37:

    接下来就是one pass的高斯模糊 bloom。

    vec3 toneMapping(vec3 hdrColor ,float exposure){
        const float gamma = 2.2;
        // 曝光色调映射
        vec3 mapped = vec3(1.0) - exp(-hdrColor * exposure);
        // Gamma校正
        mapped = pow(mapped, vec3(1.0 / gamma));
        return mapped;
    }
    // https://www.youtube.com/watch?v=01xAJ5giuu0
    // https://zhuanlan.zhihu.com/p/21983679
    vec3 ReinhardMapping(vec3 hdrColor)
    {
        vec3 mapped = hdrColor / (1.0f +hdrColor);
        mapped = pow(mapped, vec3(1.0 / 2.2f));
        return mapped;
    }
    
    
    
    
    vec3 ACESToneMapping(vec3 color,float exposure)
    {
        const float gamma = 2.2;
        const float A = 2.51f;
        const float B = 0.03f;
        const float C = 2.43f;
        const float D = 0.59f;
        const float E = 0.14f;
        color *= exposure;
        vec3 mapped =  (color * (A * color + B)) / (color * (C * color + D) + E);
        mapped = pow(mapped, vec3(1.0/gamma));
        return mapped;
    }
    
    
    //precision mediump float;
    float normpdf(in float x, in float sigma)
    {
        return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;
    }
    
    
    
    vec3 gaussianBlur(sampler2D tex, vec2 texCoords){
        //https://www.shadertoy.com/view/XdfGDH
        //declare stuff
        const int mSize = 30;
        const int kSize = (mSize-1)/2;
        float kernel[mSize];
        vec3 final_colour = vec3(0.0);
    
        //create the 1-D kernel
        float sigma = 7.0;
        float Z = 0.0;
        for (int j = 0; j <= kSize; ++j)
        {
            kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j), sigma);
        }
    
        //get the normalization factor (as the gaussian has been clamped)
        for (int j = 0; j < mSize; ++j)
        {
            Z += kernel[j];
        }
    
        //read out the texels
        for (int i=-kSize; i <= kSize; ++i)
        {
            for (int j=-kSize; j <= kSize; ++j)
            {
                //https://gamedev.stackexchange.com/questions/166182/my-single-pass-gaussian-blur-looks-awful
                final_colour += kernel[kSize+j]*kernel[kSize+i]* texture(tex, (texCoords+vec2(float(i),float(j))/textureSize(tex, 0).xy)  ).rgb;
    
            }
        }
    
        return final_colour/(Z*Z);
    }
    单层高斯模糊.glsl
    #version 450 core
    #extension GL_ARB_shading_language_include : require
    #include "/shaders/common/utils.glsl"
    #include "/shaders/common/postprocess.glsl"
    
    out vec4 FragColor;
    in vec2 TexCoords;
    
    uniform sampler2D sceneImage;
    uniform sampler2D brightImage;
    uniform float exposure;
    
    void main()
    {
        vec3 scene = texture(sceneImage,TexCoords).rgb;
        vec3 brightColor = texture(brightImage,TexCoords).rgb;
        vec3 blur = gaussianBlur(brightImage,TexCoords).rgb;
    
        scene+= blur*3.0;
    
        //scene = toneMapping(scene, exposure) ;
        scene = ACESToneMapping(scene,exposure);
        FragColor = vec4( scene , 1.0f);
    }

    CP_38:

    two pass blur:

     bool horizontal = true, first_iteration = true;
        unsigned int amount = 400;
        pingpongBlurShader.use();
        for (unsigned int i = 0; i < amount; i++)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, pingpongPost[horizontal].FBO);
            pingpongBlurShader.setInt("horizontal", 1);
            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, first_iteration ? convertFBO.textures[1] : pingpongPost[!horizontal].FBOTexture);  // bind texture of other framebuffer (or scene if first iteration)
            pingpongPost[0].draw(pingpongBlurShader);
            horizontal = !horizontal;
            if (first_iteration)
              first_iteration = false;
        }

  • 相关阅读:
    event对象之与onmouse相关的事件触发
    对文档树进行导航
    event对象的onkeydown使用
    event的onchange方法
    函数名-函数参数坑-迭代器
    函数进阶-名称空间
    初识函数
    文件管理
    基础数据类型补充-编码进阶
    集合-缓存机制-深浅copy
  • 原文地址:https://www.cnblogs.com/gearslogy/p/12623553.html
Copyright © 2020-2023  润新知