mrdoob / three.js

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

bloompass bug:flashing black block #27878

Closed wajjforever1314 closed 7 months ago

wajjforever1314 commented 7 months ago

Description

After use the bloompass, the shader and some models with transparent pass will frequently flash black blocks. Example: https://github.com/mrdoob/three.js/assets/28917209/c003d339-9b19-474e-9d07-486afb69996a

Reproduction steps

  1. use shader exmaple:webgl_shader.
  2. change bloom example:webgl_postprocessing_unreal_bloom code, add mesh with ShaderMaterial

Code

                         const geometry = new THREE.CircleGeometry(.5, 32);

            uniforms = {
                time: { value: 2. }
            };

            const material = new THREE.ShaderMaterial({
                transparent: false,
                opacity: 0,
                uniforms: uniforms,
                vertexShader: document.getElementById('vertexShader').textContent,
                fragmentShader: document.getElementById('fragmentShader').textContent

            });

            const mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);

                        animate() {
                                  ...
                                  uniforms['time'].value = performance.now() / 1000
                        }

Live example

https://github.com/mrdoob/three.js/assets/28917209/1c47eacb-22be-4e0d-8d14-263330e45c2b

Screenshots

https://github.com/mrdoob/three.js/assets/28917209/b23ebc0e-bbf0-4761-89a3-87f9325a7119

Version

"version": "0.160.0"

Device

Desktop

Browser

Chrome

OS

Windows, MacOS

wajjforever1314 commented 7 months ago

sometime, I use some other models with very much triangle face, and the material's tranparent is true. this problem will also appear

Mugen87 commented 7 months ago

I can reproduce the issue on macOS with Chrome, Firefox and Safari.

Live example for testing: https://jsfiddle.net/jqe7mu43/1/

What I find super strange: If you do not animate the time uniform in the animation loop, the flickering is gone.

Besides, are more simple fragment shader for the custom shader material doesn't trigger the issue as well: https://jsfiddle.net/mxoac23r/

Mugen87 commented 7 months ago

On a Pixel 4a there is no flashing with Chrome. So this seems to be a device specific issue. Potentially an issue in the browsers or GPU drivers.

@wajjforever1314 Can you please type chrome://gpu/ in your Chrome's address bar and share the content as a txt file in this issue?

Mugen87 commented 7 months ago

@wajjforever1314 Can you still reproduce the issue with the following updated live example? https://jsfiddle.net/mpszaf03/

Mugen87 commented 7 months ago

Made another test on a Window 10 system with a Nvidia 2070 RTX GPU. Unable to reproduce the issue.

So the only system I could reproduce so far was a macMini (M2 Pro) on macOS 14.3.1 with Chrome, Firefox and Safari.

wajjforever1314 commented 7 months ago

在 Pixel 4a 上,Chrome 不会闪烁。所以这似乎是一个设备特定的问题。浏览器或 GPU 驱动程序可能存在问题。

@wajjforever1314您能否chrome://gpu/在本期中输入您的 Chrome 地址栏并将内容以 txt 文件形式分享?

Of course: about-gpu-2024-03-08T06-36-09-118Z.txt

wajjforever1314 commented 7 months ago

我可以在 macOS 上使用 Chrome、Firefox 和 Safari 重现该问题。

用于测试的实时示例: https: //jsfiddle.net/2tahdqcs/1/

我觉得超级奇怪的是:如果你不在time动画循环中为制服设置动画,闪烁就会消失。

此外,用于自定义着色器材质的更简单的片段着色器也不会触发该问题: https: //jsfiddle.net/mxoac23r/

It's not the reason for the implementation, it's the reason for the value of the uniform parameter type

I can reproduce the issue on macOS with Chrome, Firefox and Safari.

Live example for testing: https://jsfiddle.net/2tahdqcs/1/

What I find super strange: If you do not animate the time uniform in the animation loop, the flickering is gone.

Besides, are more simple fragment shader for the custom shader material doesn't trigger the issue as well: https://jsfiddle.net/mxoac23r/

It's not the reason for the animation loop, it's the reason for the value of the uniform parameter, you can try: uniforms = { time: { value: 2.0 } }; and do not animate the time uniform in the animation loop, you will find that the problem is still there.

wajjforever1314 commented 7 months ago

@wajjforever1314您仍然可以使用以下更新的实时示例重现该问题吗?https://jsfiddle.net/mpszaf03/

So it's solved, but why, just delete part of the algorithm?

Mugen87 commented 7 months ago

So it's solved, but why, just delete part of the algorithm?

Yes. I've just deleted the term tan( r * g + h ) * from the effect. It's really strange that something like that fixes the issue.

and do not animate the time uniform in the animation loop, you will find that the problem is still there.

Indeed, the issue is unrelated to the animation loop. Depending on the computations in the fragment shader, the black quads appear at different locations and in different numbers.

Here is a more strip-down version of the above fiddle that renders only a single frame but shows two overlaying black quads on my system: https://jsfiddle.net/dv1opbg3/

Depending on the time uniform, the glitch disappears (with a value of 1) or appears at different location.

We can can not fix this issue on our side. I'll report it to the Chrome bug tracker.

wajjforever1314 commented 7 months ago

So it's solved, but why, just delete part of the algorithm?

Yes. I've just deleted the term tan( r * g + h ) * from the effect. It's really strange that something like that fixes the issue.

and do not animate the time uniform in the animation loop, you will find that the problem is still there.

Indeed, the issue is unrelated to the animation loop. Depending on the computations in the fragment shader, the black quads appear at different locations and in different numbers.

Here is a more strip-down version of the above fiddle that renders only a single frame but shows two overlaying black quads on my system: https://jsfiddle.net/rh3dqbgp/

Depending on the time uniform, the glitch disappears (with a value of 1) or appears at different location.

We can can not fix this issue on our side. I'll report it to the Chrome bug tracker.

Okay, got it, thanks

wajjforever1314 commented 7 months ago

So it's solved, but why, just delete part of the algorithm?

Yes. I've just deleted the term tan( r * g + h ) * from the effect. It's really strange that something like that fixes the issue.

and do not animate the time uniform in the animation loop, you will find that the problem is still there.

Indeed, the issue is unrelated to the animation loop. Depending on the computations in the fragment shader, the black quads appear at different locations and in different numbers. Here is a more strip-down version of the above fiddle that renders only a single frame but shows two overlaying black quads on my system: https://jsfiddle.net/rh3dqbgp/ Depending on the time uniform, the glitch disappears (with a value of 1) or appears at different location. We can can not fix this issue on our side. I'll report it to the Chrome bug tracker.

Okay, got it, thanks

this version on my system is ok

image
Mugen87 commented 7 months ago

Sorry, I've saved the fiddle with the wrong uniform value. Try it with: https://jsfiddle.net/dv1opbg3/

wajjforever1314 commented 7 months ago

Sorry, I've saved the fiddle with the wrong uniform value. Try it with: https://jsfiddle.net/dv1opbg3/

it is also ok =.=

image
Mugen87 commented 7 months ago

Not sure what's going on then. On my system, I can see the mentioned artifacts.

In any event, I've filed a bug report at the Chromium bug tracker: https://issues.chromium.org/issues/328681369

What is also interesting, an iPad (8. generation) does not show the glitch as well so I assume this is related to M processors.

wajjforever1314 commented 7 months ago

Not sure what's going on then. On my system, I can see the mentioned artifacts.

In any event, I've filed a bug report at the Chromium bug tracker: https://issues.chromium.org/issues/328681369

What is also interesting, an iPad (8. generation) does not show the glitch as well so I assume this is related to M processors.

Haha, I can understand it this way for the time being. I will continue to track and explore this issue and update it to you simultaneously.

gkjohnson commented 7 months ago

There's no BloomPass bug here - this is just exposing a problem in the custom shader where NaN values are produced which are then propagated during the bloom effect. Different hardware handle NaN differently possibly depending on floating point calculations etc so it may or may not show up depending on what machine you're trying to reproduce this on.

Adding this to the end of the custom shader produces red flashes instead of black ones:

if ( any( isnan( gl_FragColor ) ) ) {

  gl_FragColor = vec4( 100000000, 0, 0, 1 );

}

On hardware my hardware (M1 macbook) you can create a NaN value with 0.0 / 0.0.

Mugen87 commented 7 months ago

Interesting! I'll redirect this finding to the Chromium bug tracker. It would be great if a WebGL implementation could ensure NaN is treated uniformly.

gkjohnson commented 7 months ago

I don't expect this to be fixable by browsers or three.js. Floating point operations are defined ambiguously in the spec - presumably by design so hardware manufacturers can optimize at their own discretion. See section 2.1.1 on floating point operations in the OpenGL ES 3.0 specification upon which WebGL2 is defined. Specifically:

the representation of such floating-point numbers, and the details of how operations on them are performed, is not specified. ... The special values Inf and −Inf encode values with magnitudes too large to be represented; the special value NaN encodes “Not A Number” values resulting from undefined arithmetic operations such as 0 / 0. Implementations are permitted, but not required, to support Inf s and NaN s in their floating-point computations.

Perhaps this is different in more modern graphics APIs or WebGPU but I believe this is just the nature of graphics programming. It's something the developer has to be aware of when writing shaders.

wajjforever1314 commented 7 months ago

I don't expect this to be fixable by browsers or three.js. Floating point operations are defined ambiguously in the spec - presumably by design so hardware manufacturers can optimize at their own discretion. See section 2.1.1 on floating point operations in the OpenGL ES 3.0 specification upon which WebGL2 is defined. Specifically:

the representation of such floating-point numbers, and the details of how operations on them are performed, is not specified. ... The special values Inf and −Inf encode values with magnitudes too large to be represented; the special value NaN encodes “Not A Number” values resulting from undefined arithmetic operations such as 0 / 0. Implementations are permitted, but not required, to support Inf s and NaN s in their floating-point computations.

Perhaps this is different in more modern graphics APIs or WebGPU but I believe this is just the nature of graphics programming. It's something the developer has to be aware of when writing shaders.

But for some models, after turning on the bloom pass, still flashing, how to fix it?

gkjohnson commented 7 months ago

But for some models, after turning on the bloom pass, still flashing, how to fix it?

Your custom shader needs to not perform calculations that result in NaN values or check for them and handle them gracefully.

wajjforever1314 commented 7 months ago

But for some models, after turning on the bloom pass, still flashing, how to fix it?

Your custom shader needs to not perform calculations that result in NaN values or check for them and handle them gracefully.

thanks a lot

Mugen87 commented 7 months ago

@gkjohnson As you have already mentioned, the issue can't be fixed on the browser side. Here is the response at the Chromium bug tracker:

It's not possible to enforce uniform behavior across GPU types for NaN values produced in shaders. Some shading languages on top of which WebGL is implemented do not have universally available primitives to even query whether values are NaN. Even if this were universally supported, interposing upon every arithmetic operation in the shader would be prohibitively expensive at run time. If there appears to be some other issue causing this problem, please feel free to comment here and I'll reopen this bug, but in the meantime I'm closing it as infeasible.

So at least we have an official browser dev statement that this issue needs to be fixed on app level by avoiding NaN values in shaders whenever possible.