load: load.html

<!DOCTYPE html>

<html>
<head>

<title>Comp 86 example: Load external object</title>

<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.156.0/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@0.156.0/examples/jsm/"
    }
  }
</script>

<script type="module">

class SceneGraph extends THREE.Scene {
    constructor () {
	super()

	let loader = new OBJLoader () //*1 Load it, get callback when loaded

	// NB downloaded from http://artist-3d.com/free_3d_models/dnm/model_disp.php?uid=4587
	loader.load ("Beethoven.obj", //*1
		(obj) => { //*1
			// Move it to where we want it
			obj.position.set (0, -5, -10) //*2 Move it and add to scene
			this.add (obj); //*2
	})
    }
}

/*
 * An object to hold the lights, same as previous
 */
class Lights {
    constructor (scene) {
	// Uses typical lighting setup, like portrait or TV studio...

	// Main (key) light, directional, 
	// from 45 deg. user's right, above, bright white
	this.mainLight = new THREE.DirectionalLight ("white", 1 * 2*Math.PI)
	this.mainLight.position.set (1, 0.5, 1)
	scene.add (this.mainLight)

	// Fill light, directional, from 45deg. user's left,
	// white, half as bright
	this.fillLight = new THREE.DirectionalLight ("white", 0.5 * 2*Math.PI)
	this.fillLight.position.set (-1, 0, 1 )
	scene.add (this.fillLight)

	// Ambient light, white, still less bright
	this.ambientLight = new THREE.AmbientLight ("white", 0.05 * 2*Math.PI)
	scene.add (this.ambientLight);
    }
}

/*
 * The rest of this is the same boilerplate as previously,
 * except for the additional import
 */

import * as THREE from "three";
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js'; //*1

class Main {
	constructor () {
		// Set up window for 3D
		this.renderer = new THREE.WebGLRenderer( { antialias: true } );
		this.renderer.setClearColor( new THREE.Color ("lightgrey"))
		this.renderer.setSize( window.innerWidth, window.innerHeight );
		document.body.appendChild( this.renderer.domElement );

		// Create our scene
		this.scene = new SceneGraph();

		// Add our lights to the scene, we keep in a separate class 
		new Lights(this.scene); 

		// Create the camera
		this.camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
		this.camera.position.z = 5;

		// Create a camera contol
		new OrbitControls( this.camera, this.renderer.domElement );

		// Start animation loop
		this.animate()

		// In case window is resized
		// use () form of function definition cause need "this"
		// but don't need "event" arg
		window.onresize = () => this.onResize()
	}

	/*
	 * Render the scene
	 */
	render() {
		this.renderer.render( this.scene, this.camera );
	}

	/*
	 * Animation loop
	 */
	animate () {
		requestAnimationFrame (() => {this.animate()});
		this.render()
	}

	// In case window is resized
	onResize () {
		this.renderer.setSize( window.innerWidth, window.innerHeight );

		this.camera.aspect = window.innerWidth / window.innerHeight;
		this.camera.updateProjectionMatrix();

		this.render()
	}
}

window.onload = () => new Main ()

</script>
</head>
</html>
[download file]