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
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
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.
326 changes: 326 additions & 0 deletions examples/webgl_loader_gainmap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
<!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.5/dist/decode.js"
}
}
</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, HDRJPGLoader } from '@monogrid/gainmap-js';

const params = {
envMap: 'HDR JPG',
roughness: 0.0,
metalness: 0.0,
exposure: 1.0,
debug: false
};

let container, stats;
let camera, scene, renderer, controls;
let torusMesh, planeMesh;
let hdrJpg, hdrJpgPMREMRenderTarget, hdrJpgEquirectangularMap;
let gainMap, gainMapPMREMRenderTarget, gainMapBackground;
let hdrPMREMRenderTarget, hdrEquirectangularMap;


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.compileEquirectangularShader();

THREE.DefaultLoadingManager.onLoad = function ( ) {

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

};



hdrJpg = new HDRJPGLoader( renderer )
.load( 'textures/gainmap/spruit_sunrise_4k.jpg', function ( ) {

resolutions[ 'HDR JPG' ] = hdrJpg.width + 'x' + hdrJpg.height;
displayStats( 'HDR JPG' );

hdrJpgPMREMRenderTarget = pmremGenerator.fromEquirectangular( hdrJpg.renderTarget.texture );

hdrJpgEquirectangularMap = hdrJpg.toDataTexture();
hdrJpgEquirectangularMap.mapping = THREE.EquirectangularReflectionMapping;
hdrJpgEquirectangularMap.minFilter = THREE.LinearFilter;
hdrJpgEquirectangularMap.magFilter = THREE.LinearFilter;
hdrJpgEquirectangularMap.generateMipmaps = false;

hdrJpgEquirectangularMap.needsUpdate = true;

}, function ( progress ) {

fileSizes[ 'HDR JPG' ] = humanFileSize( progress.total );

} );

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

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

gainMapPMREMRenderTarget = pmremGenerator.fromEquirectangular( gainMap.renderTarget.texture );

gainMapBackground = gainMap.toDataTexture();
gainMapBackground.mapping = THREE.EquirectangularReflectionMapping;
gainMapBackground.minFilter = THREE.LinearFilter;
gainMapBackground.magFilter = THREE.LinearFilter;
gainMapBackground.generateMipmaps = false;

gainMapBackground.needsUpdate = true;

}, function ( progress ) {

fileSizes[ 'Webp Gain map (separate)' ] = humanFileSize( progress.total );

} );

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

resolutions[ 'HDR' ] = hdrEquirectangularMap.image.width + 'x' + hdrEquirectangularMap.image.height;

hdrPMREMRenderTarget = pmremGenerator.fromEquirectangular( hdrEquirectangularMap );

hdrEquirectangularMap.mapping = THREE.EquirectangularReflectionMapping;
hdrEquirectangularMap.minFilter = THREE.LinearFilter;
hdrEquirectangularMap.magFilter = THREE.LinearFilter;
hdrEquirectangularMap.needsUpdate = true;

}, function ( progress ) {

fileSizes[ 'HDR' ] = humanFileSize( progress.total );

} );

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', [ 'HDR JPG', '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 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 pmremRenderTarget, equirectangularMap;

switch ( params.envMap ) {

case 'HDR JPG':
pmremRenderTarget = hdrJpgPMREMRenderTarget;
equirectangularMap = hdrJpgEquirectangularMap || hdrJpg.renderTarget.texture;
break;
case 'Webp Gain map (separate)':
pmremRenderTarget = gainMapPMREMRenderTarget;
equirectangularMap = gainMapBackground || gainMap.renderTarget.texture;
break;
case 'HDR':
pmremRenderTarget = hdrPMREMRenderTarget;
equirectangularMap = hdrEquirectangularMap;
break;

}

const newEnvMap = pmremRenderTarget ? pmremRenderTarget.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 = equirectangularMap;
renderer.toneMappingExposure = params.exposure;

renderer.render( scene, camera );

}

</script>

</body>
</html>