mrdoob / three.js

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

WebGLRenderer: Difference between Scene.background and setClearColor() #22340

Open Mugen87 opened 3 years ago

Mugen87 commented 3 years ago

Using Scene.background and WebGLRenderer.setClearColor() produces the same output in the following demos:

Scene.background: https://jsfiddle.net/xkf3o8uw/5/ setClearColor(): https://jsfiddle.net/xkf3o8uw/4/

However, when setting autoClear to false, the behavior is different:

Scene.background: https://jsfiddle.net/0o38d67m/ setClearColor(): https://jsfiddle.net/xkf3o8uw/2/

Scene.background still works because of this line in Scene.background:

https://github.com/mrdoob/three.js/blob/a4f742c7d7b61f3efae147235efb0b5bc73e6e03/src/renderers/webgl/WebGLBackground.js#L52

What is the reason for this discrepancy? Does it just mean Scene.background used with a color should be decoupled of autoClear settings?

WestLangley commented 3 years ago

Does it just mean Scene.background used with a color should be decoupled of autoClear settings?

Yes -- for a host of reasons...

This will be a breaking change -- but for the better. I think scene background as a color should behave identically to scene background as a solid texture.

Setting the renderer's clear color has completely different behavior.

Mugen87 commented 3 years ago

I think scene background as a color should behave identically to scene background as a solid texture.

Do you mind explaining why you said that? It seems this is already the case, see https://jsfiddle.net/5j2uktdg/.

Yes -- for a host of reasons...

Do you mind mentioning them^^?

gkjohnson commented 3 years ago

My feeling is that the behavior of scene.background when set to a solid color should be consistent when scene.background is set to a texture. Looking at the code when using a cube texture with scene.background the depth and stencil buffers are not overwritten but the color is written to regardless of whether or not renderer.autoClear is set to true. My guess is the background was cleared when the background was a solid color in an effort to make the behavior between the two cases more consistent. Possibly just the color buffer should be cleared with the background color if it is set to a color rather than clearing the depth and stencil, as well:

https://github.com/mrdoob/three.js/blob/a4f742c7d7b61f3efae147235efb0b5bc73e6e03/src/renderers/webgl/WebGLBackground.js#L66-L78

Mugen87 commented 3 years ago

Thanks for clearing things up. Indeed, if you use a color for Scene.background a full clear is executed even when autoClear is set to false. If a texture is used, no clear happens but the color buffer is overwritten with the background mesh.

Possibly just the color buffer should be cleared with the background color if it is set to a color rather than clearing the depth and stencil, as well:

That sounds good to me!

WestLangley commented 3 years ago

Do you mind mentioning them^^?

Sure.

renderer.setClearColor( 0xff0000, 0.5 ); // the behavior is as-expected
scene.background = new THREE.Color( 0xff0000 ); // it currently behaves similar to clear color
scene.background = new THREE.DataTexture( new Uint8Array( [ 255, 0, 0 ] ), 1, 1, THREE.RGBFormat );

I think that is all correct....

And for consistency, the scene background color should be assumed to be in linear colorspace. Currently it is an unusual special case.

WestLangley commented 3 years ago

Be aware that In addition to clear color, fog-color is also currently in output color space. And it is not tonemapped.

See https://github.com/mrdoob/three.js/pull/11076#issuecomment-293567895.

wmcmurray commented 2 years ago

+1 That forceClear = true got me real confused this morning, I didn't expect Scene.background to still clear the color even if autoClear === false 😕 ! For that reason, I ended up not using Scene.background at all.

hybridherbst commented 4 months ago

Looking into this again, the behaviour is still rather unexpected.

scene.background = color, no effect composer is the only case that does not apply tonemapping to the color.

So it is an exception to all other cases – as soon as EffectComposer is used, scene.background will have toneMapping applied, same as when the background is a texture or something else.