|
1 | 1 | import "./style.css";
|
2 | 2 | import * as THREE from "three";
|
3 |
| -import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader"; |
4 | 3 | import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
5 | 4 | import { gsap } from "gsap";
|
6 |
| -import { Object3D, SpotLightHelper } from "three"; |
| 5 | + |
| 6 | +let experience = { |
| 7 | + canvas: document.getElementById("webgl"), |
| 8 | + clock: new THREE.Clock(), |
| 9 | + scene: new THREE.Scene(), |
| 10 | + camera: new THREE.PerspectiveCamera( |
| 11 | + 45, |
| 12 | + window.innerWidth / window.innerHeight, |
| 13 | + 0.1, |
| 14 | + 30000 |
| 15 | + ), |
| 16 | + colors: [ |
| 17 | + // an array of some of my fave colors for randomly coloring objects |
| 18 | + "deeppink", |
| 19 | + "cyan", |
| 20 | + "yellow", |
| 21 | + "white", |
| 22 | + "tomato", |
| 23 | + "chartreuse", |
| 24 | + "crimson", |
| 25 | + "cornflowerblue", |
| 26 | + "coral", |
| 27 | + ], |
| 28 | + |
| 29 | + dims: { |
| 30 | + width: window.innerWidth, |
| 31 | + height: window.innerHeight, |
| 32 | + }, |
| 33 | + |
| 34 | + texture: new THREE.TextureLoader(), |
| 35 | + isPlaying: false, |
| 36 | + mixer: new THREE.AnimationMixer(), |
| 37 | + heart: new THREE.Object3D(), |
| 38 | + monster: new THREE.Object3D(), |
| 39 | + playIcon: '<ion-icon name="pause-outline"></ion-icon>', |
| 40 | + pauseIcon: '<ion-icon name="play-outline"></ion-icon>', |
| 41 | + |
| 42 | + // instantiate, load textures, objects, etc |
| 43 | + boot: function () { |
| 44 | + // create the renderer |
| 45 | + experience.renderer = new THREE.WebGLRenderer({ |
| 46 | + canvas: experience.canvas, |
| 47 | + antialias: true, |
| 48 | + }); |
| 49 | + experience.renderer.setSize(experience.dims.width, experience.dims.height); |
| 50 | + experience.renderer.shadowMap.enabled = true; |
| 51 | + experience.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); |
| 52 | + experience.renderer.setClearColor(0x000000, 0); |
| 53 | + |
| 54 | + // make it foggy, now |
| 55 | + experience.scene.fog = new THREE.Fog(0xcccccc, 1000, 10000); |
| 56 | + // add cam to scene |
| 57 | + experience.scene.add(experience.camera); |
| 58 | + }, |
| 59 | + |
| 60 | + _createPathStrings: function (filename) { |
| 61 | + const basePath = "./skybox/images/"; |
| 62 | + const baseFilename = basePath + filename; |
| 63 | + const fileType = ".jpg"; |
| 64 | + const sides = ["FRONT", "BACK", "UP", "DOWN", "LEFT", "RIGHT"]; |
| 65 | + const pathStrings = sides.map((side) => { |
| 66 | + return baseFilename + "_" + side + fileType; |
| 67 | + }); |
| 68 | + |
| 69 | + return pathStrings; |
| 70 | + }, |
| 71 | + |
| 72 | + _createMaterialArray: function (filename) { |
| 73 | + const skyboxImagePaths = experience._createPathStrings(filename); |
| 74 | + const materialArray = skyboxImagePaths.map((image) => { |
| 75 | + let texture = experience.texture.load(image); |
| 76 | + return new THREE.MeshBasicMaterial({ |
| 77 | + map: texture, |
| 78 | + side: THREE.BackSide, |
| 79 | + }); |
| 80 | + }); |
| 81 | + return materialArray; |
| 82 | + }, |
| 83 | + |
| 84 | + // create all lights and objects for your scene |
| 85 | + create: function () { |
| 86 | + // make a skybox for the scene |
| 87 | + // const materialArray = experience._createMaterialArray("ocean"); // load forest skybox |
| 88 | + // add a gigantic skybox cube to the scene |
| 89 | + experience.cube = new THREE.Mesh( |
| 90 | + new THREE.BoxGeometry(10000, 10000, 10000), |
| 91 | + // materialArray |
| 92 | + new THREE.MeshBasicMaterial({ |
| 93 | + color: |
| 94 | + experience.colors[ |
| 95 | + Math.floor(Math.random() * experience.colors.length) |
| 96 | + ], |
| 97 | + side: THREE.BackSide, |
| 98 | + }) |
| 99 | + ); |
| 100 | + // add the skybox to the scene |
| 101 | + experience.scene.add(experience.cube); |
| 102 | + |
| 103 | + // ambient light |
| 104 | + let ambi = new THREE.AmbientLight("white", 0.65); |
| 105 | + ambi.position.set(0, 1000, 0); |
| 106 | + experience.scene.add(ambi); |
| 107 | + |
| 108 | + // directional light |
| 109 | + let dirLight = new THREE.DirectionalLight(0xffffff, 1); |
| 110 | + // dirLight.position.set(0,2000,-1000); // Default position |
| 111 | + dirLight.position.set(0, 2000, 0); // High Noon |
| 112 | + dirLight.castShadow = true; |
| 113 | + experience.scene.add(dirLight); |
| 114 | + |
| 115 | + // add a point light to the camera |
| 116 | + let point = new THREE.PointLight("aliceblue", 1, 800); |
| 117 | + point.castShadow = true; |
| 118 | + point.lookAt(experience.monster.position); |
| 119 | + |
| 120 | + experience.camera.add(point); |
| 121 | + |
| 122 | + // add a spotlight to point at monster |
| 123 | + let spot = new THREE.SpotLight("gold", 0.75); |
| 124 | + spot.castShadow = true; |
| 125 | + spot.position.set(0, 100, 0); |
| 126 | + experience.scene.add(spot); |
| 127 | + |
| 128 | + // debug only obvs |
| 129 | + let lightHelper = new THREE.SpotLightHelper(spot); |
| 130 | + experience.scene.add(lightHelper); |
| 131 | + |
| 132 | + // create a floor |
| 133 | + // let txtr = experience.texture.load("./textures/concrete3-albedo.png"); |
| 134 | + // txtr.wrapS = THREE.RepeatWrapping; |
| 135 | + // txtr.wrapT = THREE.RepeatWrapping; |
| 136 | + // txtr.repeat.set(4, 4); |
| 137 | + let geo = new THREE.PlaneGeometry(100, 100, 10, 10); |
| 138 | + let mat = new THREE.MeshBasicMaterial({ |
| 139 | + // map: txtr, |
| 140 | + wireframe: false, |
| 141 | + color: "silver", |
| 142 | + }); |
| 143 | + experience.floor = new THREE.Mesh(geo, mat); |
| 144 | + experience.floor.receiveShadow = true; |
| 145 | + experience.floor.rotation.x = Math.PI / 2; |
| 146 | + experience.floor.rotation.y = Math.PI; |
| 147 | + experience.floor.rotation.z = Math.PI / 2; |
| 148 | + experience.floor.position.y = -5; |
| 149 | + experience.scene.add(experience.floor); |
| 150 | + |
| 151 | + // load your objects |
| 152 | + |
| 153 | + // position the camera where you want it |
| 154 | + // experience.camera.position.set(0, -980.636, 1500); |
| 155 | + //experience.camera.lookAt(experience.floor.position); |
| 156 | + }, |
| 157 | + |
| 158 | + _triggerAnimation: function () {}, |
| 159 | + |
| 160 | + controls: function () { |
| 161 | + // init and add OrbitControls |
| 162 | + experience.orbit = new OrbitControls( |
| 163 | + experience.camera, |
| 164 | + experience.renderer.domElement |
| 165 | + ); |
| 166 | + experience.orbit.enableDamping = true; |
| 167 | + experience.orbit.autoRotate = false; |
| 168 | + // experience.orbit.target = experience.monster.position; |
| 169 | + experience.orbit.enabled = true; |
| 170 | + experience.orbit.update(); |
| 171 | + |
| 172 | + // DEBUG: enable for debugging camera location |
| 173 | + window.addEventListener("wheel", function (evt) { |
| 174 | + console.log(experience.camera.position); |
| 175 | + }); |
| 176 | + |
| 177 | + window.addEventListener("resize", () => { |
| 178 | + // update dims |
| 179 | + experience.dims.width = window.innerWidth; |
| 180 | + experience.dims.height = window.innerHeight; |
| 181 | + |
| 182 | + // update cam |
| 183 | + experience.camera.aspect = experience.dims.width / experience.dims.height; |
| 184 | + experience.camera.updateProjectionMatrix(); |
| 185 | + |
| 186 | + // update the renderer |
| 187 | + experience.renderer.setSize( |
| 188 | + experience.dims.width, |
| 189 | + experience.dims.height |
| 190 | + ); |
| 191 | + experience.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); |
| 192 | + }); |
| 193 | + }, |
| 194 | + |
| 195 | + render: function () { |
| 196 | + // game loop |
| 197 | + const elapsedTime = experience.clock.getElapsedTime(); |
| 198 | + //const audioPlayHead = experience.audio.currentTime / experience.audio.duration; |
| 199 | + //document.querySelector(".play-head").style.width = |
| 200 | + // audioPlayHead * 100 + "%"; |
| 201 | + |
| 202 | + // update controls because damping |
| 203 | + experience.orbit.update(); |
| 204 | + |
| 205 | + // update objects |
| 206 | + experience.cube.rotation.set(elapsedTime, elapsedTime, elapsedTime); |
| 207 | + |
| 208 | + // do the render |
| 209 | + experience.renderer.render(experience.scene, experience.camera); |
| 210 | + // call this method again next frame |
| 211 | + window.requestAnimationFrame(experience.render); |
| 212 | + }, |
| 213 | +}; |
| 214 | + |
| 215 | +experience.boot(); |
| 216 | +experience.create(); |
| 217 | +experience.controls(); |
| 218 | +experience.render(); |
0 commit comments