用于流体模拟的双边过滤器

时间:2014-12-26 22:10:16

标签: java opengl glsl lwjgl

所以我进行了流体模拟,我尝试应用双边滤镜,以便在保留边缘的同时模糊表面。我的方法基于此演示文稿(特别是幻灯片26)http://developer.download.nvidia.com/presentations/2010/gdc/Direct3D_Effects.pdf

我遇到的问题是我的边缘根本没有保留。即使我渲染出单个粒子,它也会变得模糊,正如您在下面的图像中看到的那样,模糊不正确。

另外,如pdf中详细说明的那样,虽然通常不能将双边滤波器分开,但在流体的情况下,这样做是合理的,因为只有很小的伪像。这就是下面两次传球的原因,但这不应该导致边缘模糊。

Blur Shader:

#version 400

in vec2 coord;

uniform sampler2D depthMap;
uniform vec2 screenSize;
uniform mat4 projection;
uniform vec2 blurDir;

const float filterRadius = 10;
const float blurScale = .1;
const float blurDepthFalloff = 1000;

 void main() {
     float depth = texture(depthMap, coord).x;

     float sum = 0.0f;
     float wsum = 0.0f;

     for (float x = -filterRadius; x <= filterRadius; x += 1.0f) {
        float s = texture(depthMap, coord + x*blurDir).x;

        float r = x * blurScale;
        float w = exp(-r*r);

        float r2 = (s - depth) * blurDepthFalloff;
        float g = exp(-r2*r2);

        sum += s * w * g;
        wsum += w * g;
    }

    if (wsum > 0.0f) {
        sum /= wsum;
    }

    gl_FragDepth = sum;
}

绘图代码:

//--------------------Particle Blur-------------------------
        {
            glUseProgram(blurShader.program);

            //Vertical blur
            glBindFramebuffer(GL_FRAMEBUFFER, blurShader.fboV);
            glDrawBuffer(GL_NONE);
            glReadBuffer(GL_NONE);

            glClear(GL_DEPTH_BUFFER_BIT);

            blurShader.blurDepthVAO();

            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, depthShader.tex);
            glUniform1i(blurShader.depthMap, 0);

            RenderUtility.setVector2(blurShader, screenSize, "screenSize");
            RenderUtility.setMatrix(blurShader, projection, "projection");
            RenderUtility.setVector2(blurShader, new Vector2(0.0f, 1.0f / screenSize.y), "blurDir");

            glEnable(GL_DEPTH_TEST);

            glBindVertexArray(blurShader.vao);

            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

            //Horizontal Blur
            glBindFramebuffer(GL_FRAMEBUFFER, blurShader.fboH);
            glDrawBuffer(GL_NONE);
            glReadBuffer(GL_NONE);

            glClear(GL_DEPTH_BUFFER_BIT);

            glActiveTexture(GL_TEXTURE0);
            glBindTexture(GL_TEXTURE_2D, blurShader.texV);
            glUniform1i(blurShader.depthMap, 0);

            RenderUtility.setVector2(blurShader, screenSize, "screenSize");
            RenderUtility.setMatrix(blurShader, projection, "projection");
            RenderUtility.setVector2(blurShader, new Vector2(1.0f / screenSize.x, 0.0f), "blurDir");

            glEnable(GL_DEPTH_TEST);

            glBindVertexArray(blurShader.vao);

            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
        }

当前状态图片: Depth rendered out to the screen after applying blur

1 个答案:

答案 0 :(得分:1)

终于明白了。缺少的部分是需要丢弃深度大于.9999(或其他一些最大深度数)的像素,这样您就不会模糊不属于模拟的像素。回想起来很明显,但我花了很长时间才意识到这一点。

所以正确的着色器如下所示:

uniform sampler2D depthMap;
uniform vec2 screenSize;
uniform mat4 projection;
uniform vec2 blurDir;

const float filterRadius = 10;
const float blurScale = .1;
const float blurDepthFalloff = 1000;

void main() {
    float depth = texture(depthMap, coord).x;
    if (depth == 1.0f) {
       discard;
    }

    float sum = 0.0f;
    float wsum = 0.0f;

    for (float x = -filterRadius; x <= filterRadius; x += 1.0f) {
        float s = texture(depthMap, coord + x*blurDir).x;

        float r = x * blurScale;
        float w = exp(-r*r);

        float r2 = (s - depth) * blurDepthFalloff;
        float g = exp(-r2*r2);

        sum += s * w * g;
        wsum += w * g;
    }

    if (wsum > 0.0f) {
        sum /= wsum;
    }

    gl_FragDepth = sum;
}