Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blurred Environment Map #19736

Closed
2 of 12 tasks
ManishJu opened this issue Jun 25, 2020 · 13 comments
Closed
2 of 12 tasks

Blurred Environment Map #19736

ManishJu opened this issue Jun 25, 2020 · 13 comments

Comments

@ManishJu
Copy link
Contributor

ManishJu commented Jun 25, 2020

On using HDR loader and PMREMGenerator as in the example https://threejs.org/examples/?q=tone#webgl_tonemapping
you will always get the scene background blurred no matter what the size of the HDR you are using. I tried 1k,4k and 8k hdr texture from https://hdrihaven.com/hdri/?h=small_cathedral, I still get the same blurred background.

Three.js version
  • Dev
  • [x ] r118
  • ...
Browser
  • All of them
  • Chrome
  • Firefox
  • Internet Explorer
OS
  • All of them
  • Windows
  • macOS
  • Linux
  • Android
  • iOS
@ManishJu ManishJu changed the title Blurred Environment map Blurred Environment Map Jun 25, 2020
@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 26, 2020

So you are expecting a sharp background?

@ManishJu
Copy link
Contributor Author

ManishJu commented Jun 26, 2020

Yes 4k and above used to give very sharp and clean background before in THREE version 110. Here is the comparison of a portion of the 4k hdr in each

Screenshot from 2020-06-26 11-18-15
Screenshot from 2020-06-26 11-00-54

@sciecode
Copy link
Contributor

sciecode commented Jun 26, 2020

@ManishJu This is a two fold problem.

The low res background happens because, in the example, we are setting the output of PMREMGenerator directly to the background. Currently, the highest MIP level of the generated texture is fixed and limited to 256px, so no matter how high quality the original texture is, the background will always be 256px. Good news is that I'm currently working on a solution to allow customizable resolution for the max MIP level, so we should have an out of the box solution for this very soon.

The other point of view, is that we should be setting the equirectangular original texture to the background, not the PMREM version. However, the internal shader does not know how to deal with equirectangular textures, but IMO it should.
I'll take a look at it, to see if there's something simple that can be done about that.

@Mugen87
Copy link
Collaborator

Mugen87 commented Jun 26, 2020

However, the internal shader does not know how to deal with equirectangular textures, but IMO it should.

Related #9733.

I also remember that @mrdoob lately mentioned the idea to introduce THREE.EquirectTexture (unfortunately I don't find the comment right now). I'm not sure @WestLangley is already experimenting in this context so it's maybe good to clarify this in order to avoid redundant work (and PRs).

@sciecode
Copy link
Contributor

However, the internal shader does not know how to deal with equirectangular textures, but IMO it should.

Related #9733.

I see, however, I find that the approaches suggested by that thread are no longer relevant in our current design. We wouldn't need to create a cube map from an equirectangular texture. It's really just a simple 2 liner fix.

if ( background && ( background.isCubeTexture || background.isWebGLCubeRenderTarget || background.mapping === CubeUVReflectionMapping ) ) {

We just add || background.mapping === EquirectangularReflectionMapping to this line, so that WebGLBackground understand that it can read an equirectangular texture. And, inside the shader, we also include #include <common>, so that it understands equirectUv. That's it.

Here's how it looks: https://rawcdn.githack.com/sciecode/three.js/0ac95becdc228f836b60caeffa41b3e84c39b7ea/examples/webgl_tonemapping.html

I don't see any seams, or any other problems exposed by that thread. What are your guys opinion on this temporary fix? @WestLangley @Mugen87 ?

I also remember that @mrdoob lately mentioned the idea to introduce THREE.EquirectTexture (unfortunately I don't find the comment right now).

In working on the CUBE_UV I find that it would also be beneficial to have a CubeUVTexture kind of class, because we would need to keep track of the max mip level allowed for the texture, which is not something we do in the current Texture class. I also would like to re-use maxMipLevel uniform for this purpose, however this uniform is usually set internally, so it's kind of tricky. I'll create a WIP PR later on to discuss these things, just giving more insights to support the idea of creating different texture classes for the different textures mappings.

@WestLangley
Copy link
Collaborator

@ManishJu See if #9733 (comment) works for you.

@mrdoob mrdoob added this to the rXXX milestone Jun 28, 2020
@ManishJu
Copy link
Contributor Author

ManishJu commented Jun 28, 2020

Thanks @WestLangley it worked fine. I changed the background precison from 512px to 4096px and it looks amazing.
One thing I noticed was that the minification filter THREE.LinearMipmapLinearFilter did not work properly and produced numerous pattern(s) (lighting bolt) on the hdr (white in this case) whereas the THREE.LinearFilter produced a smooth background as can be seen in the below images :
Screenshot_2020-06-28 ZEG ai(1)
Screenshot_2020-06-28 ZEG ai

I will just start another issue for this if you guys want.

@WestLangley
Copy link
Collaborator

@ManishJu See #19716 (comment) and try NearestFilter.

@ManishJu
Copy link
Contributor Author

ManishJu commented Jun 28, 2020

@WestLangley thanks for your input. Changing magnification filter has no effect for me. The minification filter introduces the artifacts. In short the first 2 code snippets below give results as that of image 1 posted above and the last 2 produces image 2 from above :

//displays correctly
 const cubeRenderOpts = {
        format: THREE.RGBAFormat,
        generateMipmaps: true,
        magFilter: THREE.LinearFilter,
        minFilter: THREE.LinearFilter 
    }
//displays correctly
const cubeRenderOpts = {
        format: THREE.RGBAFormat,
        generateMipmaps: true,
        magFilter: THREE.NearestFilter,
        minFilter: THREE.LinearFilter 
    }

//cause of  banding artifact
const cubeRenderOpts = {
        format: THREE.RGBAFormat,
        generateMipmaps: true,
        magFilter: THREE.NearestFilter,
        minFilter: THREE.LinearMipmapLinearFilter 
    }
//cause of  banding artifact
  const cubeRenderOpts = {
        format: THREE.RGBAFormat,
        generateMipmaps: true,
        magFilter: THREE.LinearFilter,
        minFilter: THREE.LinearMipMapLinearFilter 
    }

@WestLangley
Copy link
Collaborator

Please show all your code so it is clear what you are doing. A live example is preferable.

@ManishJu
Copy link
Contributor Author

ManishJu commented Jul 3, 2020

@WestLangley thanks for waiting, below is the complete code. It is directly modified version of example "webgl_tonemapping". You can change line 121 with the 4 options already present.

 <!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - tone mapping</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>

	<body>
		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - Tone Mapping<br />
			Battle Damaged Sci-fi Helmet by
			<a href="https://sketchfab.com/theblueturtle_" target="_blank" rel="noopener">theblueturtle_</a><br />
			<a href="https://hdrihaven.com/hdri/?h=royal_esplanade" target="_blank" rel="noopener">Royal Esplanade</a> by <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
		</div>

		<script type="module">

			import * as THREE from '../build/three.module.js';

			import { OrbitControls } from './jsm/controls/OrbitControls.js';
			import { RGBELoader } from './jsm/loaders/RGBELoader.js';

			var  renderer, scene, camera, controls;
			var gui, guiExposure = null;

			var params = {
				exposure: 1.0,
				toneMapping: 'ACESFilmic'
			};

			init();

			
			async function init() {

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				document.body.appendChild( renderer.domElement );

				renderer.toneMapping =THREE.ACESFilmicToneMapping;
				renderer.toneMappingExposure = params.exposure;

				renderer.outputEncoding = THREE.sRGBEncoding;

				// Set CustomToneMapping to Uncharted2
				// source: http://filmicworlds.com/blog/filmic-tonemapping-operators/

				THREE.ShaderChunk.tonemapping_pars_fragment = THREE.ShaderChunk.tonemapping_pars_fragment.replace(
					'vec3 CustomToneMapping( vec3 color ) { return color; }',
					`#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )
					float toneMappingWhitePoint = 1.0;
					vec3 CustomToneMapping( vec3 color ) {
						color *= toneMappingExposure;
						return saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );
					}`
				);

				scene = new THREE.Scene();

				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );
				camera.position.set( - 1.8, 0.6, 2.7 );

				controls = new OrbitControls( camera, renderer.domElement );
				controls.addEventListener( 'change', render ); // use if there is no animation loop
				controls.enableZoom = false;
				controls.enablePan = false;
				controls.target.set( 0, 0, - 0.2 );
				controls.update();

				var pmremGenerator = new THREE.PMREMGenerator( renderer );
				pmremGenerator.compileEquirectangularShader();

				var rgbeLoader = new RGBELoader()
					.setDataType( THREE.UnsignedByteType )
					.setPath( 'textures/equirectangular/' );


				var [ texture,  ] = await Promise.all( [
					rgbeLoader.loadAsync( 'small_cathedral_4k.hdr' ),
					
				] );

				// environment
				//displays correctly
				const cubeRenderOpts1 = {
						format: THREE.RGBAFormat,
						generateMipmaps: true,
						magFilter: THREE.LinearFilter,
						minFilter: THREE.LinearFilter 
					}

				//displays correctly
				const cubeRenderOpts2 = {
						format: THREE.RGBAFormat,
						generateMipmaps: true,
						magFilter: THREE.NearestFilter,
						minFilter: THREE.LinearFilter 
					}

				//cause of  banding artifact
				const cubeRenderOpts3 = {
						format: THREE.RGBAFormat,
						generateMipmaps: true,
						magFilter: THREE.NearestFilter,
						minFilter: THREE.LinearMipmapLinearFilter 
					}

				//cause of  banding artifact
				const cubeRenderOpts4 = {
						format: THREE.RGBAFormat,
						generateMipmaps: true,
						magFilter: THREE.LinearFilter,
						minFilter: THREE.LinearMipMapLinearFilter 
					}



				var envMap = new THREE.WebGLCubeRenderTarget( 4096, cubeRenderOpts2 ).fromEquirectangularTexture( renderer, texture );

				scene.background = envMap;
				scene.environment = envMap;

				texture.dispose();
				pmremGenerator.dispose();

		
				render();

				window.addEventListener( 'resize', onWindowResize, false );

			}


			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;

				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

				render();

			}

			function render() {

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>

@WestLangley
Copy link
Collaborator

WestLangley commented Jul 3, 2020

As I said, you will get artifacts applying linear filtering to RGBE-encoded textures.

The only reason linear filtering may work in your case is because you are setting the cube size to 4096, which is likely larger than the resolution of your monitor.

For rgbe-encoded textures, you should set

generateMipmaps: false
magFilter: THREE.NearestFilter
minFilter: THREE.NearestFilter

@Mugen87
Copy link
Collaborator

Mugen87 commented Jul 8, 2020

Closing. Let's track the support for equirectangular background textures in #9733.

The current workaround is the usage of WebGLCubeRenderTarget.fromEquirectangularTexture().

@Mugen87 Mugen87 closed this as completed Jul 8, 2020
@Mugen87 Mugen87 removed this from the rXXX milestone Jul 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants