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

Examples: Add webgl_loader_texture_hdrjpg #27183

Merged
merged 9 commits into from
Nov 19, 2023
1 change: 1 addition & 0 deletions examples/files.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"webgl_loader_collada_skinning",
"webgl_loader_draco",
"webgl_loader_fbx",
"webgl_loader_gainmap",
"webgl_loader_fbx_nurbs",
"webgl_loader_gcode",
"webgl_loader_gltf",
Expand Down
Binary file added examples/screenshots/webgl_loader_gainmap.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/tags.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"webgl_lines_fat": [ "gpu", "stats", "panel" ],
"webgl_lines_fat_raycasting": [ "gpu", "stats", "panel", "raycast" ],
"webgl_loader_ttf": [ "text", "font" ],
"webgl_loader_gainmap": [ "external", "hdr", "gainmap", "ultrahdr" ],
"webgl_loader_pdb": [ "molecules", "css2d" ],
"webgl_loader_ldraw": [ "lego" ],
"webgl_loader_ifc": [ "external" ],
Expand Down
Binary file added examples/textures/gainmap/spruit_sunrise_1k.hdr
Binary file not shown.
Binary file not shown.
Binary file added examples/textures/gainmap/spruit_sunrise_4k.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions examples/textures/gainmap/spruit_sunrise_4k.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"gainMapMax": [
15.99929538702341,
15.99929538702341,
15.99929538702341
],
"gainMapMin": [
0,
0,
0
],
"gamma": [
1,
1,
1
],
"hdrCapacityMax": 15.99929538702341,
"hdrCapacityMin": 0,
"offsetHdr": [
0.015625,
0.015625,
0.015625
],
"offsetSdr": [
0.015625,
0.015625,
0.015625
]
}
Binary file added examples/textures/gainmap/spruit_sunrise_4k.webp
Binary file not shown.
352 changes: 352 additions & 0 deletions examples/webgl_loader_gainmap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - gainmap hdr</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">
<style>
.lbl {
color: #fff;
font-size: 16px;
font-weight: bold;
position: absolute;
bottom: 0px;
z-index: 100;
text-shadow: #000 1px 1px 1px;
background-color: rgba(0,0,0,0.85);
padding: 1em;
}

#lbl_left {
text-align:left;
left:0px;
}
</style>
</head>

<body>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - gain map (ultra hdr) loader <br/>
Gain map images converted from hdr with <a href="https://gainmap-creator.mono-grid.com/" target="_blank" rel="noopener">Gain map converter</a>. <br />
See external <a href="https://github.com/MONOGRID/gainmap-js" target="_blank" rel="noopener">gainmap-js</a> for more information on how to use and create gain map images.
</div>

<div id="lbl_left" class="lbl"></div>

<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/",
"@monogrid/gainmap-js": "https://unpkg.com/@monogrid/gainmap-js@2.0.0/dist/decode.js"
Mugen87 marked this conversation as resolved.
Show resolved Hide resolved
}
}
</script>

<script type="module">

import * as THREE from 'three';

import Stats from 'three/addons/libs/stats.module.js';

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';

import { GainMapLoader, JPEGRLoader } from '@monogrid/gainmap-js';

const params = {
envMap: 'JPEG Gain map',
roughness: 0.0,
metalness: 0.0,
exposure: 1.0,
debug: false
};

let container, stats;
let camera, scene, renderer, controls;
let torusMesh, planeMesh;
let hdrCubeRenderTarget, hdrCubeMap;
let gainMap, gainmapRenderTarget, gainmapBackground;
let separateGainMap, separateGainmapRenderTarget, separateGainmapBackground;


const fileSizes = {};
const resolutions = {};

init();
animate();

function init() {

const lbl = document.getElementById( 'lbl_left' );

container = document.createElement( 'div' );
document.body.appendChild( container );

camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 0, 0, 120 );

scene = new THREE.Scene();
scene.background = new THREE.Color( 0x000000 );

renderer = new THREE.WebGLRenderer();
renderer.toneMapping = THREE.ACESFilmicToneMapping;

//

let geometry = new THREE.TorusKnotGeometry( 18, 8, 150, 20 );
// let geometry = new THREE.SphereGeometry( 26, 64, 32 );
let material = new THREE.MeshStandardMaterial( {
color: 0xffffff,
metalness: params.metalness,
roughness: params.roughness
} );

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


geometry = new THREE.PlaneGeometry( 200, 200 );
material = new THREE.MeshBasicMaterial();

planeMesh = new THREE.Mesh( geometry, material );
planeMesh.position.y = - 50;
planeMesh.rotation.x = - Math.PI * 0.5;
scene.add( planeMesh );


const pmremGenerator = new THREE.PMREMGenerator( renderer );
pmremGenerator.compileCubemapShader();
pmremGenerator.compileEquirectangularShader();

THREE.DefaultLoadingManager.onLoad = function ( ) {

pmremGenerator.dispose();
mrdoob marked this conversation as resolved.
Show resolved Hide resolved

};



gainMap = new JPEGRLoader( renderer )
.load( 'textures/gainmap/spruit_sunrise_4k.jpg', function ( response ) {

gainmapRenderTarget = pmremGenerator.fromEquirectangular( response.renderTarget.texture );

gainmapBackground = response.toDataTexture();
resolutions[ 'JPEG Gain map' ] = response.width + 'x' + response.height;
fetchFileSize( 'textures/gainmap/spruit_sunrise_4k.jpg' ).then( function ( size ) {

fileSizes[ 'JPEG Gain map' ] = humanFileSize( size );
displayStats( 'JPEG Gain map' );

} );


gainmapBackground.mapping = THREE.EquirectangularReflectionMapping;
gainmapBackground.minFilter = THREE.LinearFilter;
gainmapBackground.magFilter = THREE.LinearFilter;
gainmapBackground.generateMipmaps = false;

gainmapBackground.needsUpdate = true;

} );

separateGainMap = new GainMapLoader( renderer )
.load( [ 'textures/gainmap/spruit_sunrise_4k.webp', 'textures/gainmap/spruit_sunrise_4k-gainmap.webp', 'textures/gainmap/spruit_sunrise_4k.json' ], function ( response ) {

separateGainmapRenderTarget = pmremGenerator.fromEquirectangular( response.renderTarget.texture );

separateGainmapBackground = response.toDataTexture();
fetchFileSize( 'textures/gainmap/spruit_sunrise_4k.webp' )
.then( function ( sdrSize ) {

fetchFileSize( 'textures/gainmap/spruit_sunrise_4k-gainmap.webp' ).then( function ( gainMapSize ) {

fetchFileSize( 'textures/gainmap/spruit_sunrise_4k.json' ).then( function ( metadataSize ) {

fileSizes[ 'Webp Gain map (separate)' ] = humanFileSize( sdrSize + gainMapSize + metadataSize );

} );

} );

} );
resolutions[ 'Webp Gain map (separate)' ] = response.width + 'x' + response.height;

separateGainmapBackground.mapping = THREE.EquirectangularReflectionMapping;
separateGainmapBackground.minFilter = THREE.LinearFilter;
separateGainmapBackground.magFilter = THREE.LinearFilter;
separateGainmapBackground.generateMipmaps = false;

separateGainmapBackground.needsUpdate = true;

} );

hdrCubeMap = new RGBELoader()
.load( 'textures/gainmap/spruit_sunrise_1k.hdr', function ( response ) {

fetchFileSize( 'textures/gainmap/spruit_sunrise_1k.hdr' )
.then( function ( size ) {

fileSizes[ 'HDR' ] = humanFileSize( size );

} );

resolutions[ 'HDR' ] = response.image.width + 'x' + response.image.height;
hdrCubeRenderTarget = pmremGenerator.fromEquirectangular( response );

response.mapping = THREE.EquirectangularReflectionMapping;
response.minFilter = THREE.LinearFilter;
response.magFilter = THREE.LinearFilter;
response.needsUpdate = true;
Mugen87 marked this conversation as resolved.
Show resolved Hide resolved

} );

renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );

stats = new Stats();
container.appendChild( stats.dom );

controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 50;
controls.maxDistance = 300;

window.addEventListener( 'resize', onWindowResize );

const gui = new GUI();

gui.add( params, 'envMap', [ 'JPEG Gain map', 'Webp Gain map (separate)', 'HDR' ] ).onChange( displayStats );
gui.add( params, 'roughness', 0, 1, 0.01 );
gui.add( params, 'metalness', 0, 1, 0.01 );
gui.add( params, 'exposure', 0, 2, 0.01 );
gui.add( params, 'debug' );
gui.open();

function displayStats( value ) {

lbl.innerHTML = value + ' size : ' + fileSizes[ value ] + ', Resolution: ' + resolutions[ value ];

}

}

function fetchFileSize( url, key ) {

return new Promise( function ( resolve, reject ) {

fetch( url, { method: 'HEAD' } )
.then( function ( response ) {

resolve( parseInt( response.headers.get( 'Content-Length' ) ) );

} )
.catch( reject );

} );

}

function humanFileSize( bytes, si = true, dp = 1 ) {

const thresh = si ? 1000 : 1024;

if ( Math.abs( bytes ) < thresh ) {

return bytes + ' B';

}

const units = si
? [ 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ]
: [ 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB' ];
let u = - 1;
const r = 10 ** dp;

do {

bytes /= thresh;
++ u;

} while ( Math.round( Math.abs( bytes ) * r ) / r >= thresh && u < units.length - 1 );

return bytes.toFixed( dp ) + ' ' + units[ u ];

}


function onWindowResize() {

const width = window.innerWidth;
const height = window.innerHeight;

camera.aspect = width / height;
camera.updateProjectionMatrix();

renderer.setSize( width, height );

}

function animate() {

requestAnimationFrame( animate );

stats.begin();
render();
stats.end();

}

function render() {

torusMesh.material.roughness = params.roughness;
torusMesh.material.metalness = params.metalness;

let renderTarget, cubeMap;

switch ( params.envMap ) {

case 'JPEG Gain map':
renderTarget = gainmapRenderTarget;
cubeMap = gainmapBackground || gainMap.renderTarget.texture;
break;
case 'Webp Gain map (separate)':
renderTarget = separateGainmapRenderTarget;
cubeMap = separateGainmapBackground || separateGainMap.renderTarget.texture;
break;
case 'HDR':
renderTarget = hdrCubeRenderTarget;
cubeMap = hdrCubeMap;
break;

}

const newEnvMap = renderTarget ? renderTarget.texture : null;

if ( newEnvMap && newEnvMap !== torusMesh.material.envMap ) {

torusMesh.material.envMap = newEnvMap;
torusMesh.material.needsUpdate = true;

planeMesh.material.map = newEnvMap;
planeMesh.material.needsUpdate = true;

}

torusMesh.rotation.y += 0.005;
planeMesh.visible = params.debug;

scene.background = cubeMap;
renderer.toneMappingExposure = params.exposure;

renderer.render( scene, camera );

}

</script>

</body>
</html>
Loading