scene: scene.html

<!DOCTYPE html>

<html>
<head>

<title>Comp 86 example: Scene</title>
<!-- This is like my Java3d Example2 -->

<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">

/*
 * Our stuff goes here
 * Do the scene as an object, subclass of THREE.Object3D 
 * but kind of a silly object, cause no state or behavior, just constructor 
 */
class SceneGraph extends THREE.Scene {
    constructor () {
	// Call the superclass' constructor
	super()

	// First item = a box, rotated and translated
	let box = new THREE.Mesh ( //*2 Tall box
		new THREE.BoxGeometry (1, 3, 1), //*2
		new THREE.MeshPhongMaterial()) //*2

	// Move it back from origin and to the right
	box.position.set (5, 0, -4) //*2

	// Rotate it in X and Y
	box.rotation.set (45 * Math.PI/180, 30 * Math.PI/180, 0) //*2

	// Plug it in to our scene
	this.add (box) //*2

	// A sphere, in a different location
	let sphere = new THREE.Mesh ( //*3 Sphere
		new THREE.SphereGeometry(1, 32, 32), //*3
		new THREE.MeshPhongMaterial()) //*3
	sphere.position.set (-5, 0, -3) //*3
	this.add (sphere) //*3

	// A pyramid, using our class below
	let pyramid = new Pyramid () //*4 Pyramid
	pyramid.position.set (0, 0, -6) //*4
	pyramid.rotation.set (0, 45 * Math.PI/180, 0) //*4
	this.add (pyramid) //*4
    }
}

/*
 * Make a pyramid out of other objects (3 Box's stacked up)
 * as a new mini scene graph that contains it
 */
class Pyramid extends THREE.Object3D { //*4
    constructor () {
	super()

	// Bottom Box, located slightly down
	// (relative to origin of the pyramid)
	let bot = new THREE.Mesh ( //*5 Pyramid bottom box
		new THREE.BoxGeometry (3, 3, 3), //*5
		new THREE.MeshPhongMaterial()) //*5
	bot.position.set (0, -3/2, 0) //*5
	this.add (bot) //*5

	// Middle Box, slightly up
	let mid = new THREE.Mesh ( //*6 Pyramid middle box
		new THREE.BoxGeometry (2, 2, 2), //*6
		new THREE.MeshPhongMaterial()) //*6
	mid.position.set (0, 2/2, 0) //*6
	this.add (mid) //*6

	// Top box, further up
	let top = new THREE.Mesh ( //*7 Pyramid top box
		new THREE.BoxGeometry (1, 1, 1), //*7
		new THREE.MeshPhongMaterial()) //*7
	top.position.set (0, 2 + 1/2, 0) //*7
	this.add (top) //*7
    }
}

/*
 * The rest of this is boilerplate
 */

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

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

		// 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]