mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
101.59k stars 35.29k forks source link

Unreal Bloom and Renderer Transparency issue #14104

Closed fire67 closed 1 year ago

fire67 commented 6 years ago
Description of the problem

I am currently using the Unreal Bloom post with a transparent renderer.

renderer = new THREE.WebGLRenderer({ alpha: true });
renderer.setClearColor(0xFF0000, 0);

Unfortunately, the Unreal Bloom pass doesn't seem to take in account the alpha channel of the coming texture when doing the blur and it apparently comes from getSeperableBlurMaterial in js\postprocessing\UnrealBloomPass.js.

The fragment's alpha channel is always set to 1.0 which results in a complete removal of the previous alpha values when doing the additive blending at the end.

This is happening in the latest version of Three.js r92 and you can experiment about this issue using the Unreal Bloom example

johnnyshankman commented 1 year ago

+1 Why haven't we fixed this? What is the final solution? @mrdoob let's get something merged we have plenty of PRs and Gists in this thread but nothing someone can just import and use right now.

johnnyshankman commented 1 year ago

Also what is up with the breaking changes from 127 to 128? Codepen: https://codepen.io/johnnyshankman/pen/MWGMqYZ I can't seem to figure out how to upgrade to 128 successfully.

donmccurdy commented 1 year ago

This remains open because no working, stable fix has been found. You might try https://github.com/pmndrs/postprocessing/, it may support bloom + canvas transparency.

I'd recommend using the forums (https://discourse.threejs.org/) for help with the upgrade to r128.

Mugen87 commented 1 year ago

Voting again for closing this issue since I don't think it can be fixed, see https://github.com/mrdoob/three.js/issues/14104#issuecomment-1180499097.

xiaohaook commented 1 year ago
//fragmentShader
 void main() {
                vec2 invSize = 1.0 / texSize;
                float fSigma = float(SIGMA);
                float alphaNum = 0.0; 
                float weightSum = gaussianPdf(0.0, fSigma);
                vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;
                for( int i = 1; i < KERNEL_RADIUS; i ++ ) {
                    float x = float(i);
                    float w = gaussianPdf(x, fSigma);
                    vec2 uvOffset = direction * invSize * x;
                    vec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;
                    vec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;
                    diffuseSum += (sample1 + sample2) * w;
                    weightSum += 2.0 * w;
                    alphaNum += (texture2D( colorTexture, vUv + uvOffset).a + texture2D( colorTexture, vUv - uvOffset).a) * w;
                }

                gl_FragColor = vec4(diffuseSum/weightSum, alphaNum/weightSum);
            }

//212 line
render( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {

    renderer.getClearColor( this._oldClearColor );
    this.oldClearAlpha = renderer.getClearAlpha();
    const oldAutoClear = renderer.autoClear;
    renderer.autoClear = false;

    renderer.setClearColor( this.clearColor, 0 );

    if ( maskActive ) renderer.state.buffers.stencil.setTest( false );

    if ( this.renderToScreen ) {

        this.fsQuad.material = this.basic;
        this.basic.map = readBuffer.texture;

        renderer.setRenderTarget( null );
        //Todo
        renderer.clear(false,true,true);
        //this.fsQuad.render( renderer );

    }

AA769955-450E-4208-B62A-4EFF16B62B96 52E94636-F8DA-4000-BE2F-64B40A67F526

The three version is 0.146.0 This is the effect before I changed UnrealBloomPass.js. The background is opaque. To make the background transparent, I modified the code of the slice source shader in UnrealBloomPass.js, but it cannot make my scene transparent. So I changed renderer. clear() to renderer clear(false,true,true); And commented out this.fsQuad render( renderer ); The display is as follows. The background is transparent, but the display is very false. I need official help

ButzYung commented 1 year ago

@Mugen87 Recently I tried to implement UnrealBloom in my app but encountered the same transparency problem. I came across this thread, seeing all attempts to modify the blur pass in the middle but none seemed to yield favorable results. After trying some experiments by myself, I suggest a new approach which basically doesn't need to modify UnrealBloom.js.

I use the selective bloom example as a base. In the fragment shader of the final pass where the bloom texture and the screen texture is merged,

gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0 ) * texture2D( bloomTexture, vUv ) );

which is practically a simple additive operation, I replace it with the following.

vec4 base_color = texture2D(baseTexture, vUv);
vec4 bloom_color = texture2D(bloomTexture, vUv);

float lum = 0.21 * bloom_color.r + 0.71 * bloom_color.g + 0.07 * bloom_color.b;
gl_FragColor = vec4(base_color.rgb + bloom_color.rgb, max(base_color.a, lum));

The concept is fairly simple. I generate an alpha value for the final bloom texture by using its luminosity as a base (it can be something else other than luminosity, which is open for discussion). The final result is the original base_color + bloom_color as color, plus the max of base_color.a and the new bloom alpha as the final alpha. For fully opaque parts, the result is completely the same as the default approach.

The actual result is fairly decent, at least according to my testings. Below are some screenshots using the same bloom parameters. As you can see, the default one with no transparency (i.e. black background) looks almost identical with the new approach using a HTML black background.

_bloom00 _bloom01

The new approach also looks fairly decent on a pure white background, as well as a complex background.

_bloom02 _bloom03

Of course, this is not a perfect solution. There is no perfect solution when there is no way to actually mix WebGL with HTML background with additive blending. At least, this is a fairly reasonable solution for those who really needs a transparent background.

simongloor commented 1 year ago

Wow, the result is amazing, congratz!