diff --git a/src/components/GamePlaying/GamePlaying.vue b/src/components/GamePlaying/GamePlaying.vue index f6942cb..2618bf1 100644 --- a/src/components/GamePlaying/GamePlaying.vue +++ b/src/components/GamePlaying/GamePlaying.vue @@ -205,23 +205,23 @@ export default { // gameEngine.camera.scale.copy(l.camera.position) } - let testGame1 = new Game1(gameEngine, '/static/textures/game1-test.jpg', 2, 3); - gameEngine.activeObjects.add(testGame1.object); - testGame1.object.position.set(0, 1, -15); + // let testGame1 = new Game1(gameEngine, '/static/textures/game1-test.jpg', 2, 3); + // gameEngine.activeObjects.add(testGame1.object); + // testGame1.object.position.set(0, 1, -15); - let testGame2 = new Game2(gameEngine, '/static/textures/game2-test.jpg', 3, 3); - gameEngine.activeObjects.add(testGame2.object); - testGame2.object.position.set(0, 1, 15); - testGame2.object.rotation.y += Math.PI; + // let testGame2 = new Game2(gameEngine, '/static/textures/game2-test.jpg', 3, 3); + // gameEngine.activeObjects.add(testGame2.object); + // testGame2.object.position.set(0, 1, 15); + // testGame2.object.rotation.y += Math.PI; - let testGame4 = new Game4(gameEngine, '/static/feathers-game.glb', 3, 4); - gameEngine.activeObjects.add(testGame4.object); - testGame4.object.position.set(15, 1, 5); + // let testGame4 = new Game4(gameEngine, '/static/feathers-game.glb', 3, 4); + // gameEngine.activeObjects.add(testGame4.object); + // testGame4.object.position.set(15, 1, 5); - let vp = new VideoPlayer(gameEngine, this.$refs.videoPlayer, 16, 9); - gameEngine.activeObjects.add(vp.object); - vp.object.position.set(37, 5.5, 15); - vp.object.rotation.y += -Math.PI/2; + // let vp = new VideoPlayer(gameEngine, this.$refs.videoPlayer, 16, 9); + // gameEngine.activeObjects.add(vp.object); + // vp.object.position.set(37, 5.5, 15); + // vp.object.rotation.y += -Math.PI/2; let maze = new MazeQuizGame(gameEngine, {}, [ {s: 'Кое е най-голямото езеро в България', h: 'Wrong answer', a: true}, diff --git a/src/components/InteractiveObjects/ImageObject.js b/src/components/InteractiveObjects/ImageObject.js new file mode 100644 index 0000000..2b78760 --- /dev/null +++ b/src/components/InteractiveObjects/ImageObject.js @@ -0,0 +1,34 @@ +import { TextureLoader, MeshStandardMaterial, MeshBasicMaterial, PlaneGeometry, Mesh } from "three"; +import { assignParams } from "@/lib/MeshUtils"; + +class ImageObject { + constructor(obj, context) { + var t = new TextureLoader().setPath(context.path).load(obj.value); + //t.encoding = sRGBEncoding; + var mp = { + map: t, + alphaTest: 0.5 + }; + if (obj.nm) { + mp.normalMap = new TextureLoader().setPath(context.path).load(obj.nm); + } + if (obj.em) { + mp.emissiveMap = new TextureLoader().setPath(context.path).load(obj.em); + } + if (obj.am) { + mp.alphaMap = new TextureLoader().setPath(context.path).load(obj.am); + } + obj.material && Object.assign(mp, obj.material); + let geo = new PlaneGeometry(context.wallSize * (obj.w || 1), context.wallSize * (obj.h || 1)); + if (obj.uv) { + var uvAttribute = geo.attributes.uv; + for (var i = 0; i < uvAttribute.count; i++) { + uvAttribute.setXY(i, obj.uv[2 * i], obj.uv[2 * i + 1]); + } + } + this.object = new Mesh(geo, mp.metalness ? new MeshStandardMaterial(mp) : new MeshBasicMaterial(mp)); + assignParams(this.object, obj); + } +} + +export {ImageObject} \ No newline at end of file diff --git a/src/components/InteractiveObjects/InteractiveObject.js b/src/components/InteractiveObjects/InteractiveObject.js index c0a7cfe..18b0734 100644 --- a/src/components/InteractiveObjects/InteractiveObject.js +++ b/src/components/InteractiveObjects/InteractiveObject.js @@ -1,8 +1,7 @@ -import { ImageObject } from "./ImageObject"; -import { Hint } from "./Hint"; +//import { Hint } from "./Hint"; import { Group, AnimationMixer, LoopPingPong, Vector3 } from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; -import { Utils } from "./Utils"; +import { assignMaterial, assignParams } from "@/lib/MeshUtils"; import { Game1 } from "./PuzzleGame1"; import { Game2 } from "./PuzzleGame2"; // import { Game3 } from "./games/Game3"; @@ -10,6 +9,7 @@ import { Game4 } from "./PuzzleGame4"; // import { Game5 } from "./games/Game5"; // import { Game6 } from "./games/Game6"; import { TextObject } from "./TextObject"; +import { ImageObject } from "./ImageObject"; const games = {Game1, Game2, Game4}; @@ -31,7 +31,7 @@ class InteractiveObject { break; case 'text': let text = new TextObject(obj, context); - resolve(text.mesh); + resolve(text.object); break; case 'mesh': mesh = obj.value; @@ -39,12 +39,12 @@ class InteractiveObject { break; case 'image': let imo = new ImageObject(obj, context); - mesh = imo.mesh; + mesh = imo.object; resolve(mesh); break; case 'hint': let hint = new Hint(obj, context); - mesh = hint.mesh; + mesh = hint.object; resolve(mesh); break; case 'gltf': @@ -58,7 +58,7 @@ class InteractiveObject { // object.castShadow = true; // object.receiveShadow = true; }); - Utils.assignMaterial(gltfObj, obj, context); + assignMaterial(gltfObj, obj, context); if (gltf.animations && gltf.animations.length) { let mixer = new AnimationMixer(gltfObj); context.mixers.push(mixer); @@ -71,7 +71,7 @@ class InteractiveObject { break; case 'asset': mesh = context.assets[obj.value].clone(); - Utils.assignMaterial(mesh, obj, context); + assignMaterial(mesh, obj, context); resolve(mesh); break; case 'Game1': @@ -81,7 +81,7 @@ class InteractiveObject { case 'Game5': case 'Game6': var game = new games[obj.type](context, obj.args[0], obj.args[1], obj.args[2]); - mesh = game.game; + mesh = game.object; mesh.game = game; resolve(mesh); break; @@ -89,14 +89,14 @@ class InteractiveObject { }); this.ready.then((mesh) => { mesh.go = {}; - let restriction; - if (!context.disableRestrictions && obj.restriction) { - restriction = { - type: 'deny', - a: [obj.room.localToWorld(new Vector3().fromArray(obj.restriction[0])), obj.room.localToWorld(new Vector3().fromArray(obj.restriction[1]))] - }; - context.areas.push(restriction); - } + // let restriction; + // if (!context.disableRestrictions && obj.restriction) { + // restriction = { + // type: 'deny', + // a: [obj.room.localToWorld(new Vector3().fromArray(obj.restriction[0])), obj.room.localToWorld(new Vector3().fromArray(obj.restriction[1]))] + // }; + // context.areas.push(restriction); + // } mesh.go.finish = () => { if (obj.finish) { var f; @@ -115,15 +115,15 @@ class InteractiveObject { } if (restriction) context.areas.splice(context.areas.indexOf(restriction), 1); }; - if (mesh.game) mesh.game.onfinish = mesh.go.finish; - Utils.assignParams(mesh, obj); + if (mesh.object) mesh.object.onfinish = mesh.go.finish; + assignParams(mesh, obj); obj.animation && context.motionEngine.add({ o: mesh, a: obj.animation.motion, r: obj.animation.repeat, t: obj.animation.duration || 1 }); - this.mesh = mesh; + this.object = mesh; }); } } diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js index 0ee0086..7755359 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js @@ -1,6 +1,5 @@ import { Group, Vector3, Matrix4, Mesh, Quaternion, BoxGeometry } from 'three'; -import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; -import { TextObject } from '../TextObject'; +import { InteractiveObject } from '../InteractiveObject'; class MazeObject { constructor(engine, def, params = {}){ @@ -14,7 +13,8 @@ class MazeObject { context.wallSize = params.wallSize || 1.2*scale; //half context.tubeSize = params.tubeSize || 1.2*scale; context.wallDepth = params.wallDepth || 0*scale; - context.fontPath = params.fontPath || '/static/fonts/Jura-SemiBold.ttf'; + context.fontPath = params.fontPath || '/static/fonts/Montserrat-Regular.ttf'; + context.scale = scale; this.context = context; let _tf = { @@ -29,7 +29,6 @@ class MazeObject { }; let o = {}; - let areas = [], mazeMeshes = []; function addPhysics(matrix, position, size, placement = 'side'){ let quat = new Quaternion().setFromRotationMatrix(matrix); @@ -58,7 +57,7 @@ class MazeObject { let t = o.tunnel.clone(); t.position.set(0, 0, i * context.tubeSize); def.matrix && t.applyMatrix4(def.matrix); - mazeMeshes.push(t); + root.add(t); } offsetZ = def.len * context.tubeSize; //if (!def.len) offsetZ = -.275; @@ -70,7 +69,6 @@ class MazeObject { // console.log(offsetZ, room.localToWorld(new Vector3(context.tubeSize / 2, 0.6, offsetZ/2))) - let ofZ = def.len * context.tubeSize addPhysics(def.matrix, [context.tubeSize / 2, 0.6, offsetZ/2], offsetZ) addPhysics(def.matrix, [-context.tubeSize / 2, 0.6, offsetZ/2], offsetZ) @@ -109,18 +107,19 @@ class MazeObject { } e.forEach(g => { - def.matrix && g.applyMatrix4(def.matrix); - mazeMeshes.push(g); + g.applyMatrix4(def.matrix); + root.add(g); }); - def.objects && def.objects.forEach(obj => { + def.objects && def.objects.forEach(async obj => { obj.room = room; // let go = new GameObject(obj, context); - let go = new TextObject(obj, context) - go.mesh.scale.multiplyScalar(scale) - go.mesh.position.multiply(new Vector3(scale, scale, context.wallSize)) - go.mesh.applyMatrix4(def.matrix); - root.add(go.mesh); + let go = new InteractiveObject(obj, context) + await go.ready; + go.object.scale.multiplyScalar(context.wallSize) + go.object.position.multiplyScalar(context.wallSize) + go.object.applyMatrix4(def.matrix); + root.add(go.object); // go.ready.then(mesh => { // room.add(mesh); // }); @@ -151,11 +150,11 @@ class MazeObject { // console.log(e, o[e].geometry.boundingBox) }); this.mazeObject(def, room); - mazeMeshes.forEach(mesh=>{ - //let mesh = new Mesh(mg, o.tunnel.material) - root.add(mesh); - //engine.phy.add(mesh, 'fixed') - }) + // mazeMeshes.forEach(mesh=>{ + // //let mesh = new Mesh(mg, o.tunnel.material) + // root.add(mesh); + // //engine.phy.add(mesh, 'fixed') + // }) console.log(o.tunnel) //scene.add(new Mesh(BufferGeometryUtils.mergeGeometries(mazeGeometries, false), o.tunnel.material)); diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js index 95ca333..d05fa42 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js @@ -23,7 +23,15 @@ class MazeQuizGame { len, objects:[ { - type: 'text', text: cq.s, position:[0,.44,len], rotation:[0,Math.PI, 0] + type: 'text', text: cq.s, position:[0,.4,len+.96], rotation:[0,Math.PI, 0] + },{ + type: 'image', value: '/static/textures/arrow.png', position:[-.5,.44,len+.96], rotation:[0,Math.PI, 0], scale: [0.03, 0.03, 0.03] + },{ + type: 'text', text: 'Вярно', position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0] + },{ + type: 'image', value: '/static/textures/arrow.png', position:[.5,.44,len+.96], rotation:[0,Math.PI, Math.PI], scale: [0.03, 0.03, 0.03] + },{ + type: 'text', text: 'Невярно', position:[.5,.3,len+.9], rotation:[0,Math.PI, 0] } ], [lrv?'r':'l']:{ @@ -32,7 +40,7 @@ class MazeQuizGame { len: lr, objects:[ { - type: 'text', text: cq.h, position:[0,.44,lr], rotation:[0,Math.PI, 0] + type: 'text', text: cq.h, position:[0,.44,lr+.96], rotation:[0,Math.PI, 0] } ] } diff --git a/src/components/InteractiveObjects/TextObject.js b/src/components/InteractiveObjects/TextObject.js index 2578829..f0b394f 100644 --- a/src/components/InteractiveObjects/TextObject.js +++ b/src/components/InteractiveObjects/TextObject.js @@ -1,13 +1,13 @@ import { MeshStandardMaterial, Color, Vector3 } from "three"; import { Text } from "troika-three-text"; -import Utils from "@/lib/utils"; +import { assignParams } from "@/lib/MeshUtils"; class TextObject { constructor(obj, params) { const txt = new Text(); // Set properties to configure: txt.text = obj.text; - txt.fontSize = 0.022; + txt.fontSize = 0.033; txt.lineHeight = 1.1; txt.maxWidth = obj.width || params.wallSize * .73; txt.textAlign = 'center'; @@ -16,18 +16,19 @@ class TextObject { txt.anchorY = 'bottom'; txt.curveRadius = 0; txt.outlineColor = 0xffffff; - txt.outlineWidth = '15%'; - txt.outlineBlur = '50%'; - Utils.assignMeshParams(txt, obj) + txt.outlineWidth = '1%'; + txt.depthOffset = 0.1; + //txt.outlineBlur = '50%'; + txt.color = new Color(0xffffff); + assignParams(txt, obj) let m = new MeshStandardMaterial({ roughness: .73, metalness: .37, }); txt.material = m; - txt.color = new Color(0x0); txt.sync(); this.txt = txt; - this.mesh = txt; + this.object = txt; // if (obj.effect == 'distance') { // let dstm = .8; // var oldBR = txt.onBeforeRender; diff --git a/src/lib/MeshUtils.js b/src/lib/MeshUtils.js new file mode 100644 index 0000000..0421d62 --- /dev/null +++ b/src/lib/MeshUtils.js @@ -0,0 +1,30 @@ +import { TextureLoader } from "three"; + +function assignParams(mesh, params){ + ['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p])); + ['visible', 'name'].forEach(p=>{ + if (params[p]!==undefined) mesh[p] = params[p]; + }); +} + +function assignMaterial(mesh, params, context){ + if (params.name && params.material){ + console.log(mesh) + //let mp = params.material.metalness ? new MeshStandardMaterial(params.material) : new MeshBasicMaterial(params.material) + Object.assign(mesh.material, params.material) + if (params.dm){ + var dm = new TextureLoader().setPath(context.path).load(params.dm); + mesh.material.map = dm; + } + if (params.nm){ + mesh.material.normalMap = new TextureLoader().setPath(context.path).load(params.nm); + } + if (params.em) { + mesh.material.emissiveMap = new TextureLoader().setPath(context.path).load(params.em); + } + //mesh.material = mp; + mesh.material.needsUpdate = true; + } +} + +export { assignParams, assignMaterial } \ No newline at end of file diff --git a/src/lib/gameEngine.js b/src/lib/gameEngine.js index 0ac10d7..3d01aff 100644 --- a/src/lib/gameEngine.js +++ b/src/lib/gameEngine.js @@ -4,6 +4,7 @@ import { DRACOLoader } from 'three/examples/jsm/Addons.js'; import { OrbitControls } from 'three/examples/jsm/Addons.js'; //import { Controller as OrbitControls } from './3rd-party/phy/3TH/Controller.js'; import { ViewportGizmo } from "three-viewport-gizmo"; +import Stats from 'three/examples/jsm/libs/stats.module'; //import { AnaglyphEffect } from './three/AnaglyphEffect'; import { AnaglyphEffect } from 'three/addons/effects/AnaglyphEffect.js'; import { StereoEffect } from 'three/addons/effects/StereoEffect.js'; @@ -23,7 +24,7 @@ class GameEngine { this.opts = opts; const gameEngine = this; - this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.aspect, 0.01, 1000); + this.perspectiveCamera = new THREE.PerspectiveCamera(45, this.aspect, 0.01, 25); this.raycaster = new THREE.Raycaster(); this.perspectiveCamera.position.set(0, 0, 10); @@ -163,6 +164,9 @@ class GameEngine { await this.initPhysics(); + this.stats = new Stats(); + document.body.appendChild(this.stats.dom); + if (opts.ar) { renderer.xr.enabled = true; document.body.appendChild(ARButton.createButton(renderer, {})); @@ -569,6 +573,7 @@ class GameEngine { } else { this.renderer.render(scene, camera); } + this.stats?.update() } } diff --git a/src/lib/utils.js b/src/lib/utils.js index 80e5fe9..c6d4f79 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -54,11 +54,4 @@ export default { rad2deg(rad){ return rad * 180 / Math.PI; }, - - assignMeshParams(mesh, params){ - ['scale', 'rotation', 'position'].forEach(p=>params[p] && mesh[p].fromArray(params[p])); - ['visible', 'name'].forEach(p=>{ - if (params[p]!==undefined) mesh[p] = params[p]; - }); - }, } \ No newline at end of file