diff --git a/src/components/GameDesigner/GameDesigner.vue b/src/components/GameDesigner/GameDesigner.vue index d59240f..4f2de31 100644 --- a/src/components/GameDesigner/GameDesigner.vue +++ b/src/components/GameDesigner/GameDesigner.vue @@ -121,7 +121,7 @@ export default { async mounted(){ gameEngine = new GameEngine(); //this.gameEngine = gameEngine; - await gameEngine.init(this.$refs.target); + await gameEngine.init(this.$refs.target, {gizmo: true}); gameEngine.scene.add(gameEngine.transformControls.getHelper()); gameEngine.scene.add(new gameEngine.$.GridHelper(100,100)); this.resize(); @@ -142,6 +142,12 @@ export default { this.scenario = null; } }, + + /** + * loads all environment objects + * @param scene Scene object from the Scenario Module + * @param target Target scene definition from Game Module + */ async loadEnvironment(scene, target){ await gameEngine.loadPanorama(`/asset/default/43.webp`); await this.expandScenarioData(scene); @@ -162,6 +168,12 @@ export default { //window.gameEngine = gameEngine; //console.log(new gameEngine.$.Euler({"isEuler":true,"_x":0,"_y":0,"_z":0,"_order":"XYZ"})); } + let camera = new gameEngine.$.PerspectiveCamera(); + let cameraHelper = new gameEngine.$.CameraHelper(camera); + gameEngine.activeObjects.add(cameraHelper); + gameEngine.activeObjects.add(camera); + this.setObjectAttributes(l, { id: 'camera', 'title': 'Main camera' }, { scene: camera }) + cameraHelper.update(); }, async expandScenarioData(scene){ scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data diff --git a/src/components/GamePlaying/GamePlaying.vue b/src/components/GamePlaying/GamePlaying.vue index f782c0c..d82301e 100644 --- a/src/components/GamePlaying/GamePlaying.vue +++ b/src/components/GamePlaying/GamePlaying.vue @@ -17,7 +17,6 @@
-
@@ -121,7 +120,7 @@ export default { async mounted(){ gameEngine = new GameEngine(); //this.gameEngine = gameEngine; - await gameEngine.init(this.$refs.target); + await gameEngine.init(this.$refs.target, { xr: true }); gameEngine.scene.add(gameEngine.transformControls.getHelper()); gameEngine.scene.add(new gameEngine.$.GridHelper(100,100)); this.resize(); @@ -143,12 +142,13 @@ export default { } }, async loadEnvironment(scene, target){ - await gameEngine.loadPanorama(`/asset/default/43.webp`); + //await gameEngine.loadPanorama(`/asset/default/43.webp`); await this.expandScenarioData(scene); + gameEngine.activeObjects.scale.set(0.033, 0.033, 0.033) target.objects = target.objects || {}; let l = target.objects; if (this.scene.data.$environment.type == 'panorama2d'){ - await gameEngine.loadPanorama(`/asset/default/${this.scene.data.$environment.asset.name}`); + //await gameEngine.loadPanorama(`/asset/default/${this.scene.data.$environment.asset.name}`); }else{ let env = await gameEngine.load(`/asset/default/${this.scene.data.$environment.asset.name}`); this.setObjectAttributes(l, this.scene.data, env, 100); @@ -162,6 +162,11 @@ export default { //window.gameEngine = gameEngine; //console.log(new gameEngine.$.Euler({"isEuler":true,"_x":0,"_y":0,"_z":0,"_order":"XYZ"})); } + if (l.camera){ + // gameEngine.camera.position.copy(l.camera.position) + // gameEngine.camera.rotation.copy(l.camera.position) + // gameEngine.camera.scale.copy(l.camera.position) + } }, async expandScenarioData(scene){ scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data diff --git a/src/lib/gameEngine.js b/src/lib/gameEngine.js index 493c2fc..d98fa89 100644 --- a/src/lib/gameEngine.js +++ b/src/lib/gameEngine.js @@ -10,9 +10,11 @@ import { MapControls } from 'three/addons/controls/MapControls.js'; import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js'; import { TransformControls } from 'three/addons/controls/TransformControls.js'; import { ARButton } from 'three/addons/webxr/ARButton.js'; +import { XRButton } from 'three/addons/webxr/XRButton.js'; +import { XRControllerModelFactory } from 'three/addons/webxr/XRControllerModelFactory.js'; class GameEngine { - async init(domNode) { + async init(domNode, opts = {}) { this.w = domNode.clientWidth || 1200, this.h = domNode.clientHeight || 800; this.aspect = this.w / this.h const gameEngine = this; @@ -83,12 +85,14 @@ class GameEngine { this.stereo.setSize( this.w, this.h ); const controls = new OrbitControls( this.camera, renderer.domElement ); - const gizmo = new ViewportGizmo(this.camera, renderer, { - container:'.renderer-gizmo', - //type:'cube' - }); - gizmo.attachControls(controls); - this.gizmo = gizmo; + if (opts.gizmo){ + const gizmo = new ViewportGizmo(this.camera, renderer, { + container:'.renderer-gizmo', + //type:'cube' + }); + gizmo.attachControls(controls); + this.gizmo = gizmo; + } this.orbitControls = controls; //controls.enableZoom = true; @@ -106,7 +110,7 @@ class GameEngine { let delta = clock.getDelta(); mixer.update(delta); gameEngine.render(scene, gameEngine.camera); - gizmo.render(); + gameEngine.gizmo?.render(); } renderer.setAnimationLoop(animate); @@ -141,7 +145,96 @@ class GameEngine { controls.rotateSpeed = 1 / gameEngine.camera.zoom; gameEngine.camera.updateProjectionMatrix(); }) - document.body.appendChild( ARButton.createButton( renderer, { } ) ); + + if (opts.ar){ + renderer.xr.enabled = true; + document.body.appendChild( ARButton.createButton( renderer, { } ) ); + } + if (opts.xr){ + renderer.xr.enabled = true; + document.body.appendChild( XRButton.createButton( renderer, { + 'optionalFeatures': [ 'depth-sensing' ] + } ) ); + this.initXrControllers(); + } + } + + initXrControllers(){ + let controller1 = this.renderer.xr.getController( 0 ); + controller1.addEventListener( 'select', this.onSelect.bind(this) ); + controller1.addEventListener( 'selectstart', this.onControllerEvent.bind(this) ); + controller1.addEventListener( 'selectend', this.onControllerEvent.bind(this) ); + controller1.addEventListener( 'move', this.onControllerEvent.bind(this) ); + controller1.userData.active = false; + this.scene.add( controller1 ); + + let controller2 = this.renderer.xr.getController( 1 ); + controller2.addEventListener( 'select', this.onSelect.bind(this) ); + controller2.addEventListener( 'selectstart', this.onControllerEvent.bind(this) ); + controller2.addEventListener( 'selectend', this.onControllerEvent.bind(this) ); + controller2.addEventListener( 'move', this.onControllerEvent.bind(this) ); + controller2.userData.active = true; + this.scene.add( controller2 ); + + const controllerModelFactory = new XRControllerModelFactory(); + + let controllerGrip1 = this.renderer.xr.getControllerGrip( 0 ); + controllerGrip1.add( controllerModelFactory.createControllerModel( controllerGrip1 ) ); + this.scene.add( controllerGrip1 ); + + let controllerGrip2 = this.renderer.xr.getControllerGrip( 1 ); + controllerGrip2.add( controllerModelFactory.createControllerModel( controllerGrip2 ) ); + this.scene.add( controllerGrip2 ); + + const geometry = new THREE.BufferGeometry().setFromPoints( [ new THREE.Vector3( 0, 0, 0 ), new THREE.Vector3( 0, 0, - 1 ) ] ); + + let line = new THREE.Line( geometry ); + line.name = 'line'; + line.scale.z = 5; + + this.xrController1 = controller1 + this.xrController2 = controller2 + } + + onControllerEvent(event) { + const controller = event.target; + if (controller.userData.active === false) return; + this.raycaster.setFromXRController(controller); + switch (event.type) { + case 'selectstart': + this.transformControls.pointerDown(null); + break; + case 'selectend': + this.transformControls.pointerUp(null); + break; + case 'move': + this.transformControls.pointerHover(null); + this.transformControls.pointerMove(null); + break; + } + } + + onSelect(event) { + const controller = event.target; + this.xrController1.userData.active = false; + this.xrController2.userData.active = false; + + if (controller === this.xrController1) { + this.xrController1.userData.active = true; + this.xrController1.add(line); + } + + if (controller === this.xrController2) { + this.xrController2.userData.active = true; + this.xrController2.add(line); + } + + this.raycaster.setFromXRController(controller); + const intersects = this.raycaster.intersectObjects(this.activeObjects.children); + + if (intersects.length > 0) { + this.transformControls.attach(intersects[0].object); + } } $ = THREE; @@ -259,7 +352,9 @@ class GameEngine { this.camera = o; this.transformControls.camera = o; this.orbitControls.object = o; - this.gizmo.camera = o; + if (this.gizmo){ + this.gizmo.camera = o; + } } setCameraPerspective() { @@ -271,7 +366,9 @@ class GameEngine { this.camera = o; this.transformControls.camera = o; this.orbitControls.object = o; - this.gizmo.camera = o; + if (this.gizmo){ + this.gizmo.camera = o; + } } resize(w, h){ @@ -288,7 +385,7 @@ class GameEngine { this.renderer.setViewport( 0, 0, this.w, this.h ); this.anaglyph.setSize( w, h ); this.stereo.setSize( w, h ); - this.gizmo.update(); + this.gizmo?.update(); } render(scene, camera){ diff --git a/vite.config.mjs b/vite.config.mjs index bf3d59b..7830939 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -72,7 +72,7 @@ export default defineConfig({ }, hmr:true, strictPort: true, - //host:'0.0.0.0', + host:'192.168.31.137', proxy:{ '/api': { target: 'https://localhost:3000',