From 63742730552f619d8102e972cc17ac0ceef40d10 Mon Sep 17 00:00:00 2001 From: Paul Graffam Date: Mon, 6 Jul 2020 17:29:08 -0400 Subject: [PATCH] Set up gltf loading, set up switching, fixed imports, fixed helpers, added model gui --- src/js/app/main.js | 17 +++-- src/js/app/managers/datGUI.js | 61 ++++++++++++++---- src/js/app/model/model.js | 113 ++++++++++++++++++++++++---------- src/js/data/config.js | 23 +++++-- 4 files changed, 159 insertions(+), 55 deletions(-) diff --git a/src/js/app/main.js b/src/js/app/main.js index b32f28a..150cd6e 100644 --- a/src/js/app/main.js +++ b/src/js/app/main.js @@ -1,6 +1,6 @@ // Global imports - import * as THREE from 'three'; -import TWEEN from 'tween.js'; +import TWEEN from '@tweenjs/tween.js'; // Local imports - // Components @@ -8,10 +8,11 @@ import Renderer from './components/renderer'; import Camera from './components/camera'; import Light from './components/light'; import Controls from './components/controls'; +import Geometry from './components/geometry'; // Helpers -import Geometry from './helpers/geometry'; import Stats from './helpers/stats'; +import MeshHelper from './helpers/meshHelper'; // Model import Texture from './model/texture'; @@ -66,6 +67,11 @@ export default class Main { this.stats.setUp(); } + // Set up gui + if (Config.isDev) { + this.gui = new DatGUI(this) + } + // Instantiate texture class this.texture = new Texture(); @@ -75,7 +81,7 @@ export default class Main { // Textures loaded, load model this.model = new Model(this.scene, this.manager, this.texture.textures); - this.model.load(); + this.model.load(Config.models[Config.model.selected].type); // onProgress callback this.manager.onProgress = (item, loaded, total) => { @@ -89,7 +95,10 @@ export default class Main { // Add dat.GUI controls if dev if(Config.isDev) { - new DatGUI(this, this.model.obj); + this.meshHelper = new MeshHelper(this.scene, this.model.obj); + if (Config.mesh.enableHelper) this.meshHelper.enable(); + + this.gui.load(this, this.model.obj); } // Everything is now fully loaded diff --git a/src/js/app/managers/datGUI.js b/src/js/app/managers/datGUI.js index cd7d430..e656923 100644 --- a/src/js/app/managers/datGUI.js +++ b/src/js/app/managers/datGUI.js @@ -2,18 +2,27 @@ import Config from '../../data/config'; // Manages all dat.GUI interactions export default class DatGUI { - constructor(main, mesh) { - const gui = new dat.GUI(); + constructor(main) { + this.gui = new dat.GUI(); this.camera = main.camera.threeCamera; this.controls = main.controls.threeControls; this.light = main.light; + this.scene = main.scene; + this.model = null; + this.meshHelper = null; + } + + load(main, mesh) { /* Global */ - //gui.close(); + //this.gui.close(); + + this.model = main.model; + this.meshHelper = main.meshHelper; /* Camera */ - const cameraFolder = gui.addFolder('Camera'); + const cameraFolder = this.gui.addFolder('Camera'); const cameraFOVGui = cameraFolder.add(Config.camera, 'fov', 0, 180).name('Camera FOV'); cameraFOVGui.onChange((value) => { this.controls.enableRotate = false; @@ -38,13 +47,13 @@ export default class DatGUI { }); const cameraFogColorGui = cameraFolder.addColor(Config.fog, 'color').name('Fog Color'); cameraFogColorGui.onChange((value) => { - main.scene.fog.color.setHex(value); + this.scene.fog.color.setHex(value); }); const cameraFogNearGui = cameraFolder.add(Config.fog, 'near', 0.000, 0.010).name('Fog Near'); cameraFogNearGui.onChange((value) => { this.controls.enableRotate = false; - main.scene.fog.density = value; + this.scene.fog.density = value; }); cameraFogNearGui.onFinishChange(() => { this.controls.enableRotate = true; @@ -52,7 +61,7 @@ export default class DatGUI { /* Controls */ - const controlsFolder = gui.addFolder('Controls'); + const controlsFolder = this.gui.addFolder('Controls'); controlsFolder.add(Config.controls, 'autoRotate').name('Auto Rotate').onChange((value) => { this.controls.autoRotate = value; }); @@ -66,8 +75,29 @@ export default class DatGUI { }); + /* Model */ + const modelFolder = this.gui.addFolder('Model'); + modelFolder.add(Config.model, 'type', [...Config.model.initialTypes]).name('Select Model').onChange((value) => { + if (value) { + if (Config.mesh.enableHelper) + this.meshHelper.disable(); + + Config.model.selected = Config.model.initialTypes.indexOf(value); + this.unload(); + this.model.unload(); + this.model.load(value); + } + }); + /* Mesh */ - const meshFolder = gui.addFolder('Mesh'); + const meshFolder = this.gui.addFolder('Mesh'); + meshFolder.add(Config.mesh, 'enableHelper', true).name('Enable Helpers').onChange((value) => { + if(value) { + this.meshHelper.enable(); + } else { + this.meshHelper.disable(); + } + }); meshFolder.add(Config.mesh, 'translucent', true).name('Translucent').onChange((value) => { if(value) { mesh.material.transparent = true; @@ -83,7 +113,7 @@ export default class DatGUI { /* Lights */ // Ambient Light - const ambientLightFolder = gui.addFolder('Ambient Light'); + const ambientLightFolder = this.gui.addFolder('Ambient Light'); ambientLightFolder.add(Config.ambientLight, 'enabled').name('Enabled').onChange((value) => { this.light.ambientLight.visible = value; }); @@ -93,7 +123,7 @@ export default class DatGUI { // Directional Light - const directionalLightFolder = gui.addFolder('Directional Light'); + const directionalLightFolder = this.gui.addFolder('Directional Light'); directionalLightFolder.add(Config.directionalLight, 'enabled').name('Enabled').onChange((value) => { this.light.directionalLight.visible = value; }); @@ -138,7 +168,7 @@ export default class DatGUI { }); // Shadow Map - const shadowFolder = gui.addFolder('Shadow Map'); + const shadowFolder = this.gui.addFolder('Shadow Map'); shadowFolder.add(Config.shadow, 'enabled').name('Enabled').onChange((value) => { this.light.directionalLight.castShadow = value; }); @@ -232,7 +262,7 @@ export default class DatGUI { // Point Light - const pointLightFolder = gui.addFolder('Point Light'); + const pointLightFolder = this.gui.addFolder('Point Light'); pointLightFolder.add(Config.pointLight, 'enabled').name('Enabled').onChange((value) => { this.light.pointLight.visible = value; }); @@ -287,7 +317,7 @@ export default class DatGUI { // Hemi Light - const hemiLightFolder = gui.addFolder('Hemi Light'); + const hemiLightFolder = this.gui.addFolder('Hemi Light'); hemiLightFolder.add(Config.hemiLight, 'enabled').name('Enabled').onChange((value) => { this.light.hemiLight.visible = value; }); @@ -334,4 +364,9 @@ export default class DatGUI { this.controls.enableRotate = true; }); } + + unload() { + this.gui.destroy(); + this.gui = new dat.GUI(); + } } diff --git a/src/js/app/model/model.js b/src/js/app/model/model.js index 24ed02c..016c1a2 100644 --- a/src/js/app/model/model.js +++ b/src/js/app/model/model.js @@ -1,8 +1,9 @@ import * as THREE from 'three'; -import Material from '../helpers/material'; -import MeshHelper from '../helpers/meshHelper'; +import Material from '../components/material'; import Helpers from '../../utils/helpers'; +import { BufferGeometryUtils } from '../../utils/bufferGeometryUtils'; +import { GLTFLoader } from '../loaders/GLTFLoader'; import Config from '../../data/config'; // Loads in a single object from the config file @@ -10,45 +11,91 @@ export default class Model { constructor(scene, manager, textures) { this.scene = scene; this.textures = textures; + this.manager = manager; - // Manager is passed in to loader to determine when loading done in main - this.loader = new THREE.ObjectLoader(manager); this.obj = null; + this.ref = null; } - load() { - // Load model with ObjectLoader - this.loader.load( - Config.model.path, - obj => { - obj.traverse(child => { - if(child instanceof THREE.Mesh) { - // Create material for mesh and set its map to texture by name from preloaded textures - const material = new Material(0xffffff).standard; - material.map = this.textures.UV; - child.material = material; + load(type) { + // Manager is passed in to loader to determine when loading done in main - // Set to cast and receive shadow if enabled - if(Config.shadow.enabled) { - child.receiveShadow = true; - child.castShadow = true; + switch (type) { + case 'gltf': + // Load model with selected loader + new GLTFLoader(this.manager).load( + Config.models[Config.model.selected].path, + (gltf) => { + const scene = gltf.scene; + let mesh; + + if (Config.shadow.enabled) { + scene.traverse(function(node) { + if (node.isMesh || node.isLight) node.castShadow = true; + if (node.isMesh) { + node.material.wireframe = Config.mesh.wireframe; + mesh = node; + } + }); } - } - }); - // Add mesh helper if Dev - if(Config.isDev && Config.mesh.enableHelper) { - new MeshHelper(this.scene, obj); - } + this.obj = mesh; - // Set prop to obj so it can be accessed from outside the class - this.obj = obj; + BufferGeometryUtils.computeTangents(mesh.geometry); - obj.scale.multiplyScalar(Config.model.scale); - this.scene.add(obj); - }, - Helpers.logProgress(), - Helpers.logError() - ); + var group = new THREE.Group(); + group.scale.multiplyScalar(0.25); + this.scene.add( group ); + + this.ref = group; + + // To make sure that the matrixWorld is up to date for the boxhelpers + group.updateMatrixWorld(true); + group.add(mesh); + + // Add to scene + this.scene.add(scene); + }, + Helpers.logProgress(), + Helpers.logError() + ); + break; + + case 'object': + // Load model with ObjectLoader + new THREE.ObjectLoader(this.manager).load( + Config.models[Config.model.selected].path, + obj => { + obj.traverse(child => { + if(child instanceof THREE.Mesh) { + // Create material for mesh and set its map to texture by name from preloaded textures + const material = new Material(0xffffff).standard; + material.map = this.textures.UV; + child.material = material; + + // Set to cast and receive shadow if enabled + if(Config.shadow.enabled) { + child.receiveShadow = true; + child.castShadow = true; + } + } + }); + + // Set prop to obj so it can be accessed from outside the class + this.obj = obj; + this.ref = obj; + + obj.scale.multiplyScalar(Config.models[Config.model.selected].scale); + this.scene.add(obj); + }, + Helpers.logProgress(), + Helpers.logError() + ); + break; + } + } + + unload() { + this.scene.remove(this.ref); } } diff --git a/src/js/data/config.js b/src/js/data/config.js index 4df6ee8..c71edb2 100644 --- a/src/js/data/config.js +++ b/src/js/data/config.js @@ -1,4 +1,4 @@ -import TWEEN from 'tween.js'; +import TWEEN from '@tweenjs/tween.js'; // This object contains the state of the app export default { @@ -14,17 +14,30 @@ export default { easing: TWEEN.Easing.Quadratic.InOut, duration: 500, model: { - path: './assets/models/Teapot.json', - scale: 20 + selected: 0, + initialTypes: ['gltf', 'object'], + type: 'gltf' }, + models: [ + { + path: './assets/models/duck.gltf', + scale: 20, + type: 'gltf' + }, + { + path: './assets/models/Teapot.json', + scale: 20, + type: 'object' + } + ], texture: { path: './assets/textures/', imageFiles: [ - {name: 'UV', image: 'UV_Grid_Sm.jpg'} + { name: 'UV', image: 'UV_Grid_Sm.jpg' } ] }, mesh: { - enableHelper: false, + enableHelper: true, wireframe: false, translucent: false, material: {