-
-
Notifications
You must be signed in to change notification settings - Fork 36.1k
add equiangular EXR IBL (Image based lighting) example #13693
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
add equiangular EXR IBL (Image based lighting) example #13693
Conversation
|
Live version. Looks amazing btw 😍 Is there a reason why PNG seems so overexposed compared to EXR? |
|
@looeee Without getting super into the details, perhaps suffice to say the PNG version is using LDR (low dynamic range) so its never going to look correct, you can mess with the exposure a bit to adjust, but the primary goal here is to establish the correct pipeline using HDR (high dynamic range) light probes as the basis of the IBL (image base lighting) pipeline. |
|
|
||
| standardMaterial = new THREE.MeshStandardMaterial( { | ||
| map: null, | ||
| color: 0x000000, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why black? I suggest white -- and reduce the default exposure, accordingly
| scene.add( torusMesh1 ); | ||
| objects.push( torusMesh1 ); | ||
|
|
||
| floorMaterial = new THREE.MeshStandardMaterial( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think MeshBasicMaterial is more appropriate, here, as the purpose is only to display the mips.
|
Sweet! For a future PR, if you have any ideas on how to reduce the memory stats, that would be great. |
|
@WestLangley Thank you for your comments! I've made the changes you recommended and I think it even slightly improves the visual quality. Good call with the MeshBasicMaterial, its unlit rendering is exactly what we needed for the debug texture. |
|
@looeee I took the liberty of editing your temporary live link as it was not accommodating the additional commits. :) |
|
@WestLangley Thanks! The new link looks much better indeed! |
| ]; | ||
|
|
||
| this.camera = new THREE.PerspectiveCamera( 90, 1, 0.1, 10 ); | ||
| this.planeMesh = new THREE.Mesh( new THREE.BoxGeometry( 1, 1, 1 ), this.getShader() ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would choose BoxBufferGeometry here.
| envMapIntensity: 1.0 | ||
| } ); | ||
|
|
||
| var geometry = new THREE.TorusKnotGeometry( 18, 8, 150, 20 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here: TorusKnotBufferGeometry
|
I have a black screen and the following warnings in the console. Tested with Chromium 64.0.3282.167 on Ubuntu 16.04. FF 59.0.1 shows a black screen, too (with similar warnings). Other HDR examples (like https://threejs.org/examples/webgl_materials_envmaps_hdr.html) seem to work on my machine: |
|
@Mugen87 Thank you for your review. I have made the following changes, based upon your suggestions:
Would it be possible for you to please confirm that's working for you too now? Thanks! |
|
Great 👍 . The example now works in Chrome and FF on my machine. |
| \n\ | ||
| gl_FragColor = vec4( color, 1.0 );\n\ | ||
| }", | ||
| blending: THREE.CustomBlending, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain the reason for the custom blending?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @WestLangley , I'm not specifically familiar with the THREE.ShaderMaterial so I just took that from an example. If its an option, this could probably just be left as the defaults.
|
|
||
| this.camera = new THREE.PerspectiveCamera( 90, 1, 0.1, 10 ); | ||
| this.planeMesh = new THREE.Mesh( new THREE.BoxBufferGeometry( 1, 1, 1 ), this.getShader() ); | ||
| this.planeMesh.material.side = THREE.DoubleSide; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it planeMesh and why is it double-sided?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
planeMesh should be renamed to boxMesh, it's double sided because the camera is inside the box, i.e. it needs to render and not be backface culled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
side: THREE.BackSide;
As you know, users copy code, so let's make it clear. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍(btw, appreciate you taking the time to work through the code with me!)
| this.planeMesh.material.side = THREE.DoubleSide; | ||
| this.scene = new THREE.Scene(); | ||
| this.scene.add( this.planeMesh ); | ||
| this.scene.add( this.camera ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think adding the camera to the scene is required.
|
|
||
| this.camera.position.set(0, 0, 0); | ||
| this.camera.up.set(v.u[0], v.u[1], v.u[2]); | ||
| this.camera.lookAt(new THREE.Vector3(v.t[0], v.t[1], v.t[2])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] );
|
How are you handing the encoding? Are you assuming |
|
EXR is in linear, yes. |
Likely the encoding. Can you explicitly set the proper encodings in your example? |
|
Unrelated to this PR, but I think there is something wrong with the pmrem code. By changing the roughness of the material we can see that the levels are not aligned (the lights in the reflection changes position). /cc @bhouston |
https://github.com/mrdoob/three.js/blob/dev/examples/js/pmrem/PMREMGenerator.js#L103 That's something I am looking at in my next PR... 😄 |
Sweet! I think this PR only needs @WestLangley last comment addressed and it's ready to go. |
|
@WestLangley I've explicitly set the proper encodings as you suggested and things have come even further into line 👍 Left: Low dynamic range / PNG, Right: High dynamic range / EXR You'll notice when adjusting exposure (especially where the EXR has more detail in the shadows) that the EXR / high dynamic range version works better, but there isn't the strange visual difference anymore 👌 |
|
Yes, the rendering is looking more reasonable now. :) What I don't yet understand is why /ping @bhouston |
Actually it isn't because of EXR or PNG but rather RGBE can not be linearly interpolated as it isn't a monotonic encoding, where as RGBM is a relatively monotonic encoding. |
This is caused by the sample pattern not being fully symmetric. |
|
If the PNG in this example is truly LDR and there is no encoding (e.g. RGBE, RGBM, RGBD, etc.) then it can be linear interp as well like the EXR HDR. There is no need to work around non-monotonic RGBA8 encodings for RGB HDR values. |
I've got some ideas about using a low discrepancy sampler, such as a Hammersley, to improve quality as well, for a follow up PR. |
Okay. I'm interested. I think that the issue is the current reliance on a GPU-based random number generator which is not uniform, nor is it consistent across different GPU families. I once had hope that there could be a reliable, high quality GPU-based "random" number generator -- test cases here https://threejs.org/examples/#webgl_postprocessing_procedural -- but I have since given up hope. I think a Hammersley distribution or a 2D Poisson disk would work great here. You also hint that you can improve the theoretical foundation of this convolver, that would be really amazing. The problem with this one is that it uses the result of the previous level to create the next to get speed and reduce the number of samples required, thus it is a little tricky. |
|
I would rename this example to webgl_materials_envmaps_exr.html so that it is beside the existing weblg_materials_envmaps_hdr.html and weblg_materials_envmaps.html as they are all related. |
…l_materials_envmaps_exr.html
|
Thanks! |
|
This was a great PR and work @richardmonette, very impressive. |

Fixes #13574
Summary
This PR adds an example of an IBL (Image based lighting) pipeline based around an equiangular formatted EXR.
Since we already have a nice
PMREMGenerator, I have taken the approach of adding aEquiangularToCubeGeneratorwhich uses the GPU to convert an equiangular format texture into a cube map. The highlight here is the equiangular EXR workflow, but I have also included in the example using a PNG equiangular map, just to demonstrate theEquiangularToCubeGeneratorconversion is also possible in a low dynamic range context.Performance
Test
Result
@mrdoob @WestLangley