import * as THREE from 'three'; import * as MathUtils from 'three/src/math/MathUtils.js'; import { createGround } from '../objects/ground.js'; import {loadModel} from './import.js'; const textureLoader = new THREE.TextureLoader(); function alignGround(ground, MovingObject) { /*Function used to place an object on top of another object. In fact, this is used only to place correctly objects on the ground*/ const boundingBoxGround = new THREE.Box3().setFromObject(ground); const boundingBoxMovingObject = new THREE.Box3().setFromObject(MovingObject); const groundHeight = boundingBoxGround.max.z - boundingBoxGround.min.z; const objectHeight = boundingBoxMovingObject.max.z - boundingBoxMovingObject.min.z; // Calculating offset, so this function can work with every center position const verticalOffset = (boundingBoxMovingObject.max.z + boundingBoxMovingObject.min.z) / 2; MovingObject.position.z = boundingBoxGround.max.z - verticalOffset + objectHeight / 2; } export async function addAssetsOnScene(scene){ /*This function takes the scene as arg, and is used to load everything needed on the terrain. Player, trees, fences, and everything displayed on the screen is added by this function, at the right place Will return an object containing created objects*/ scene.add(new THREE.AmbientLight(0x404040, 50));//Light, required to see /* -------------------- ADDING GROUND AND FENCES -------------------- */ let fences = [];//List of created fences const fenceModel = await loadModel('src/objects/models/fence.gltf'); //Getting width of one fence fenceModel.scene.scale.set(0.05, 0.05, 0.05); fenceModel.scene.rotateOnWorldAxis(new THREE.Vector3(1, 0, 0), MathUtils.degToRad(90));//Must be standing up const fenceHitBox = new THREE.Box3().setFromObject(fenceModel.scene); const fenceWidth = fenceHitBox.max.y - fenceHitBox.min.y; //Creating the ground const ground = createGround(35*fenceWidth, 35*fenceWidth); scene.add(ground); const groundHitBox = new THREE.Box3().setFromObject(ground); // Calculating ground size const groundXSize = groundHitBox.max.x - groundHitBox.min.x; const groundySize = groundHitBox.max.y - groundHitBox.min.y; alignGround(ground, fenceModel.scene); for(let i = 0; i { const pineClone = treePineModel.scene.clone(); pineClone.position.x = newPos.x; pineClone.position.y = newPos.y; pineClone.rotation.y = Math.random() * Math.PI * 2; scene.add(pineClone); }); const sakuraLocations = [{x:6.49, y:-9.89}, {x:9.1, y:-10.47}, {x:10.42, y:-9.44}, {x:12.6, y:-10.5}, {x:14.01, y:-9.89}, {x:15.6, y:-9.71}, {x:17.3, y:-10.4}, {x:18.81, y:-9.62}, {x:11.98, y:-9.59}, {x:8.06, y:-9.82}, {x:18.72, y:-11.94}, {x:11.1, y:-10.6}, {x:19.23, y:-13.66}, {x:18.55, y:-15.21}, {x:19.05, y:-16.95}, {x:17.64, y:-17.34}, {x:13.75, y:-16.77}, {x:12.1, y:-17.02}, {x:10.4, y:-16.98}, {x:9.34, y:-16.84}, {x:7.41, y:-17.16}, {x:5.56, y:-16.83}, {x:4.35, y:-16.56}, {x:5.56, y:-16.83}, {x:5.26, y:-15.27}, {x:4.11, y:-14.59}, {x:5.34, y:-13.32}, {x:4.17, y:-12.31}, {x:4.96, y:-11.61}, {x:12.07, y:-13.26}] sakuraLocations.forEach(newPos => { const sakuraClone = treeSakuraModel.scene.clone(); sakuraClone.position.x = newPos.x; sakuraClone.position.y = newPos.y; sakuraClone.rotation.y = Math.random() * Math.PI * 2; scene.add(sakuraClone); }); /* -------------------- ADDING GARDEN's STATUES -------------------- */ const worldStatue = await loadModel('src/objects/models/statueWorld.gltf'); worldStatue.scene.scale.set(0.09,0.09,0.09); worldStatue.scene.position.x = 9.8; worldStatue.scene.position.y = -13.6; worldStatue.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90));//Must be standing up worldStatue.scene.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad(-90)); alignGround(ground, worldStatue.scene); scene.add( worldStatue.scene ); const printerStatue = await loadModel('src/objects/models/statue3DPrinter.gltf'); printerStatue.scene.scale.set(0.09,0.09,0.09); printerStatue.scene.position.x = 14.3; printerStatue.scene.position.y = -13.6; printerStatue.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90));//Must be standing up printerStatue.scene.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad(-90)); alignGround(ground, printerStatue.scene); scene.add( printerStatue.scene ); /* -------------------- ADDING GARDEN's TABLE AND PROPS ON IT -------------------- */ const table = await loadModel('src/objects/models/table.gltf'); table.scene.scale.set(0.09,0.09,0.09); table.scene.position.x = 16; table.scene.position.y = -17.35; table.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90));//Must be standing up alignGround(ground, table.scene); scene.add( table.scene ); const gameboy = await loadModel('src/objects/models/gameboy.gltf'); gameboy.scene.scale.set(0.01,0.01,0.01); gameboy.scene.position.x = 16.62; gameboy.scene.position.y = -17.2; gameboy.scene.rotateOnWorldAxis(new THREE.Vector3(0,1,0), MathUtils.degToRad(-90)); gameboy.scene.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad(-35)); alignGround(table.scene, gameboy.scene); scene.add( gameboy.scene ); const computer = await loadModel('src/objects/models/computer.gltf'); computer.scene.scale.set(0.02,0.02,0.02); computer.scene.position.x = 16.2; computer.scene.position.y = -17.1; computer.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90)); computer.scene.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad(-90)); alignGround(table.scene, computer.scene); scene.add( computer.scene ); const gamepad = await loadModel('src/objects/models/gamepad.gltf'); gamepad.scene.scale.set(0.01,0.01,0.01); gamepad.scene.position.x = 15.7; gamepad.scene.position.y = -17.1; gamepad.scene.rotateOnWorldAxis(new THREE.Vector3(0,1,0), MathUtils.degToRad(-90)); gamepad.scene.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad(20)); alignGround(table.scene, gamepad.scene); scene.add( gamepad.scene ); /* -------------------- ADDING NAME & JOB -------------------- */ let nameplateModel; if(true){//Will be used later for localization nameplateModel = await loadModel('src/objects/models/name/NameFR.gltf'); }else if(false){ nameplateModel = await loadModel('src/objects/models/name/NameJP.gltf'); }else{ nameplateModel = await loadModel('src/objects/models/name/NameEN.gltf'); } nameplateModel.scene.scale.set(0.6,0.6,0.6); nameplateModel.scene.rotateOnWorldAxis(new THREE.Vector3(1, 0, 0), MathUtils.degToRad(60)); nameplateModel.scene.position.x = 2; nameplateModel.scene.position.y = 2; alignGround(ground, nameplateModel.scene); nameplateModel.scene.position.z += 0.2; scene.add(nameplateModel.scene); /* -------------------- ADDING SIGNS -------------------- */ const sign = await loadModel('src/objects/models/sign.gltf');//Sign model prepared sign.scene.scale.set(0.08,0.08,0.08); sign.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90)); sign.scene.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad(-90)); alignGround(ground, sign.scene); const SignPlanegeometry = new THREE.PlaneGeometry(2.95, 1.55); /* SCHOOLS */ let signPictures = ['src/objects/textures/epid.png', 'src/objects/textures/iutCalais.png'] for(let i=0; i<2; i++){ const signCopy = sign.scene.clone(); signCopy.position.x = 10 + i*5; signCopy.position.y = 1.36; scene.add( signCopy ); const signPlaneMaterial = new THREE.MeshBasicMaterial({ map:textureLoader.load(signPictures[i]) }); const signPlane = new THREE.Mesh(SignPlanegeometry, signPlaneMaterial); signPlane.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90)); signPlane.position.set( signCopy.position.x + 0.06, 1.347, 1.65);//Determined by hand scene.add(signPlane); } /* PROFESSIONAL EXPERIENCES */ signPictures = ['src/objects/textures/hachinohe.png']; for(let i=0; i<1; i++){ const signCopy = sign.scene.clone(); signCopy.position.x = -4 - i*5; signCopy.position.y = 1.36; scene.add( signCopy ); const signPlaneMaterial = new THREE.MeshBasicMaterial({ map:textureLoader.load(signPictures[i]) }); const signPlane = new THREE.Mesh(SignPlanegeometry, signPlaneMaterial); signPlane.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90)); signPlane.position.set( signCopy.position.x + 0.06, 1.347, 1.65);//Determined by hand scene.add(signPlane); } /* -------------------- ADDING LINK PLATES -------------------- */ const linkPlate = await loadModel('src/objects/models/linkPlate.gltf'); linkPlate.scene.scale.set(0.4,0.05,0.4); linkPlate.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90));//Must be standing up alignGround(ground, linkPlate.scene); linkPlate.scene.position.y = 2; scene.add( linkPlate.scene ); /* -------------------- ADDING GRASS -------------------- */ const grass1 = await loadModel('src/objects/models/grass/grass1.gltf'); const grass2 = await loadModel('src/objects/models/grass/grass2.gltf'); const grass3 = await loadModel('src/objects/models/grass/grass3.gltf'); const grass4 = await loadModel('src/objects/models/grass/grass4.gltf'); const grass5 = await loadModel('src/objects/models/grass/grass5.gltf'); const grassModels = [grass1,grass2,grass3,grass4,grass5];// Planned for later : https://threejs.org/docs/#api/en/objects/InstancedMesh grassModels.forEach(item => { //Prepare models before placing them item.scene.scale.set(0.1, 0.1, 0.1); item.scene.rotateOnWorldAxis(new THREE.Vector3(1,0,0), MathUtils.degToRad(90)); alignGround(ground, item.scene); }); function getRndInteger(min, max) { return Math.floor(Math.random() * (max - min) ) + min; } for (let i = 0; i < 140; i++) { let choosenGrassModel; let collision; choosenGrassModel = grassModels[getRndInteger(0, grassModels.length)].scene.clone(); choosenGrassModel.rotateOnWorldAxis(new THREE.Vector3(0,0,1), MathUtils.degToRad( getRndInteger(0,4) * 90));//Random rotation on Z axis do { // Random position choosenGrassModel.position.x = getRndInteger(groundHitBox.min.x, groundHitBox.max.x); choosenGrassModel.position.y = getRndInteger(groundHitBox.min.y, groundHitBox.max.y); // Checking collisions collision = false; for(let j=0; j