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

Add: "Extended" range HDR support for supported displays #29656

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build/three.cjs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions build/three.module.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion build/three.module.min.js

Large diffs are not rendered by default.

25 changes: 18 additions & 7 deletions build/three.webgpu.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion build/three.webgpu.min.js

Large diffs are not rendered by default.

25 changes: 18 additions & 7 deletions build/three.webgpu.nodes.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion build/three.webgpu.nodes.min.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion examples/webgpu_loader_gltf.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@

scene.background = texture;
scene.environment = texture;
scene.environmentIntensity = 3;

render();

Expand All @@ -79,7 +80,7 @@
renderer = new THREE.WebGPURenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.toneMapping = THREE.ACESFilmicToneMapping;
// renderer.toneMapping = THREE.ACESFilmicToneMapping;
Comment on lines -82 to +83
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important note – omission of tone mapping is an error in the PlayCanvas implementation, and others I've seen so far. We do still need tone mapping, for SDR as well as HDR, as we are still forming an image for a display. The display is of course brighter than before, and will require adaptations to the tone mappers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm aware, good point! – added to the DRAFT reasons above.

I did some testing on this as well: Mac displays are supposed to be ~3x brighter in HDR mode (1600 nits instead of 500 for SDR content), from my limited testing the practical range ("how far can I crank emissiveIntensity or environmentIntensity") seems to be ~20-30x brighter though. So there might already be tonemapping on the hardware side as well.

This image also behaves kind of suspicious: https://www.instagram.com/p/C_Byx6jRfuX/
When adjusting screen brightness while it's open, there are noticeable "steps" where the display goes into different modes (for a lack of better term: "tonemapping modes") with somewhat different relative feel.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, ouch! I was aware that adjusting screen brightness changed the available “HDR” headroom, and that this would be a problem with the current WebGPU HDR implementation, but I hadn't seen a clear demo of the issue like that. Really helpful illustration — thanks.

container.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );
Expand Down
65 changes: 60 additions & 5 deletions examples/webgpu_loader_gltf_anisotropy.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@

<body>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js webgpu</a> - glTF + <a href="https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_anisotropy" target="_blank" rel="noopener">KHR_materials_anisotropy</a><br />
Anisotropy Barn Lamp from <a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/AnisotropyBarnLamp" target="_blank" rel="noopener">glTF-Sample-Models</a><br />
<a href="https://hdrihaven.com/hdri/?h=royal_esplanade" target="_blank" rel="noopener">Royal Esplanade</a> from <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
<a href="https://threejs.org" target="_blank" rel="noopener">three.js webgpu</a> Extended Range (HDR)<br />
</div>

<script type="importmap">
Expand All @@ -32,7 +30,8 @@
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';

let renderer, scene, camera, controls;
let renderer, scene, camera, controls, lastContent;
const spheres = [];

init();

Expand All @@ -42,8 +41,10 @@
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( render );
/*
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.35;
*/
document.body.appendChild( renderer.domElement );

scene = new THREE.Scene();
Expand Down Expand Up @@ -71,17 +72,64 @@
texture.mapping = THREE.EquirectangularReflectionMapping;

scene.background = texture;
scene.backgroundBlurriness = 0.5;
scene.backgroundBlurriness = 0.0;
scene.environment = texture;
scene.environmentIntensity = 5;

// model


scene.add( gltf.scene );
lastContent = gltf.scene;

window.addEventListener( 'resize', onWindowResize );

// drop listener for GLB

renderer.domElement.addEventListener( 'dragover', event => {

event.preventDefault();

} );

renderer.domElement.addEventListener( 'drop', async event => {

event.preventDefault();
const file = event.dataTransfer.files[ 0 ];
if ( file !== undefined && file.name.endsWith( '.glb' ) ) {

// convert to blob
const blob = new Blob( [ await file.arrayBuffer() ], { type: 'application/octet-stream' } );
gltfLoader.setPath( '' );
const gltf = await gltfLoader.loadAsync( URL.createObjectURL( blob ) );


scene.add( gltf.scene );
scene.remove( lastContent );
lastContent = gltf.scene;

}

} );

// add random moving glowing spheres

const sphereGeometry = new THREE.SphereGeometry( 0.02, 32, 32 );

for ( let i = 0; i < 20; i ++ ) {

const sphereMaterial = new THREE.MeshPhysicalMaterial( { color: 0x000000, emissive: Math.random() * 0xffffff, emissiveIntensity: 30 } );
const sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
sphere.position.set( Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5 ).normalize().multiplyScalar( 0.5 );
scene.add( sphere );

spheres.push( sphere );

}

}


function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
Expand All @@ -96,6 +144,13 @@

renderer.renderAsync( scene, camera );

for ( let i = 0; i < spheres.length; i ++ ) {

const sphere = spheres[ i ];
sphere.position.y = Math.sin( performance.now() * 0.0003 + i ) * 0.5;

}

}

</script>
Expand Down
15 changes: 12 additions & 3 deletions src/renderers/webgpu/WebGPUBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,21 @@ class WebGPUBackend extends Backend {

this.trackTimestamp = this.trackTimestamp && this.hasFeature( GPUFeatureName.TimestampQuery );

this.context.configure( {
let useHdr = false; // this should become an option
const hdrMediaQuery = window.matchMedia( '(dynamic-range: high)' );
if ( hdrMediaQuery && hdrMediaQuery.matches )
useHdr = true;

const options = {
device: this.device,
format: this.utils.getPreferredCanvasFormat(),
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
alphaMode: alphaMode
} );
alphaMode: alphaMode,
toneMapping: { mode: useHdr ? 'extended' : 'standard' },
viewFormats: useHdr ? [ 'rgba16float' ] : [],
};

this.context.configure( options );

this.updateSize();

Expand Down
5 changes: 5 additions & 0 deletions src/renderers/webgpu/utils/WebGPUUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ class WebGPUUtils {

} else {

// this should probably be cached
const hdrMediaQuery = window.matchMedia( '(dynamic-range: high)' );
if ( hdrMediaQuery && hdrMediaQuery.matches )
return 'rgba16float';

return navigator.gpu.getPreferredCanvasFormat();

}
Expand Down
Loading