<!DOCTYPE html>
<html>
<head>
<title>CS 86 example: Scene</title>
<!-- This is like my Java3d Example2 -->
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.181.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.181.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 { //*1 Instantiate our own SceneGraph, and plug it in
constructor () { //*1
// 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(); //*1
// 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>