VR headset object management

This commit is contained in:
2025-06-30 23:06:22 +03:00
parent 392a94698b
commit 4ca83b7d87
11 changed files with 71 additions and 53 deletions
@@ -75,7 +75,7 @@ export default{
this.animations = gltf.animations.map(a => ({ this.animations = gltf.animations.map(a => ({
name: a.name, id: a.uuid name: a.name, id: a.uuid
})); }));
//gameEngine.autoScale(gltf.scene); gameEngine.autoScale(gltf.scene);
let bb = new gameEngine.$.Box3().setFromObject(gltf.scene); let bb = new gameEngine.$.Box3().setFromObject(gltf.scene);
gltf.scene.traverse(function (o) { gltf.scene.traverse(function (o) {
o.frustumCulled = false; o.frustumCulled = false;
@@ -20,7 +20,7 @@ export default {
data(){ data(){
return { return {
query: { query: {
type: { $in: this.$p.objectTypes.filter(t=>t.type == this.type || !this.type).map(t=>t.value) } type: { $in: this.$p.objectTypes.filter(t=>!this.type || this.type.includes(t.type)).map(t=>t.value) }
}, },
activatorProps:{}, activatorProps:{},
dialog: false dialog: false
+4 -1
View File
@@ -163,7 +163,7 @@ export default {
} }
for (let i of this.scene.data.items || []) { for (let i of this.scene.data.items || []) {
let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`); let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`);
this.setObjectAttributes(l, i.data, gltf, 10); this.setObjectAttributes(l, i.data, gltf, 1);
gameEngine.activeObjects.add(gltf.scene); gameEngine.activeObjects.add(gltf.scene);
//console.log(JSON.stringify(l)); //console.log(JSON.stringify(l));
//window.gameEngine = gameEngine; //window.gameEngine = gameEngine;
@@ -175,6 +175,9 @@ export default {
// gameEngine.activeObjects.add(camera); // gameEngine.activeObjects.add(camera);
// this.setObjectAttributes(l, { id: 'camera', 'title': 'Main camera' }, { scene: camera }) // this.setObjectAttributes(l, { id: 'camera', 'title': 'Main camera' }, { scene: camera })
// cameraHelper.update(); // cameraHelper.update();
//this is needed cause when mounted canvas has different size
this.resize();
}, },
async expandScenarioData(scene){ async expandScenarioData(scene){
scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data
+3 -3
View File
@@ -22,7 +22,7 @@
<div class="container my-3 position-relative game-designer-canvas"> <div class="container my-3 position-relative game-designer-canvas">
<div ref="target" @click="targetClick" @pointerdown="targetPointerDown"></div> <div ref="target" @click="targetClick" @pointerdown="targetPointerDown"></div>
</div> </div>
<v-toolbar density="compact"> <!-- <v-toolbar density="compact">
<v-slide-group show-arrows> <v-slide-group show-arrows>
<v-slide-group-item v-for="(a, i) in objectAnimations" :key="i" v-slot="{ isSelected }"> <v-slide-group-item v-for="(a, i) in objectAnimations" :key="i" v-slot="{ isSelected }">
<v-btn :color="isSelected ? 'primary' : undefined" class="ma-2" <v-btn :color="isSelected ? 'primary' : undefined" class="ma-2"
@@ -31,7 +31,7 @@
</v-btn> </v-btn>
</v-slide-group-item> </v-slide-group-item>
</v-slide-group> </v-slide-group>
</v-toolbar> </v-toolbar> -->
<v-navigation-drawer location="right"> <v-navigation-drawer location="right">
<v-list v-model:selected="scenesList" selectable color="primary"> <v-list v-model:selected="scenesList" selectable color="primary">
<v-list-item v-for="(s, i) in scenes" :key="i" :title="s.data.title" :value="s"></v-list-item> <v-list-item v-for="(s, i) in scenes" :key="i" :title="s.data.title" :value="s"></v-list-item>
@@ -166,7 +166,7 @@ export default {
} }
for (let i of this.scene.data.items || []) { for (let i of this.scene.data.items || []) {
let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`); let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`);
this.setObjectAttributes(l, i.data, gltf, 10); this.setObjectAttributes(l, i.data, gltf, 1);
gameEngine.activeObjects.add(gltf.scene); gameEngine.activeObjects.add(gltf.scene);
if (i.data.$go.type == 'player3d'){ if (i.data.$go.type == 'player3d'){
let hero = new Hero(gltf, i.data.$go); let hero = new Hero(gltf, i.data.$go);
+1 -1
View File
@@ -11,7 +11,7 @@
</g> </g>
</teleport> </teleport>
<v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text"> <v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text">
<asset-selector @select="assignGameObject" type="GameObject"> <asset-selector @select="assignGameObject" :type="['GameObject', 'Player']">
<template v-slot:activator="props"> <template v-slot:activator="props">
<v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose game object</v-btn> <v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose game object</v-btn>
</template> </template>
+1 -1
View File
@@ -9,7 +9,7 @@
</g> </g>
</teleport> </teleport>
<v-card :title="modelValue.title" v-if="selected" class="mx-2" variant="text"> <v-card :title="modelValue.title" v-if="selected" class="mx-2" variant="text">
<asset-selector @select="assignEnvironment" type="Scene"> <asset-selector @select="assignEnvironment" :type="['Scene']">
<template v-slot:activator="props"> <template v-slot:activator="props">
<v-btn v-bind="props" prepend-icon="mdi-panorama-outline" block color="success" class="py-4">Choose environment</v-btn> <v-btn v-bind="props" prepend-icon="mdi-panorama-outline" block color="success" class="py-4">Choose environment</v-btn>
</template> </template>
@@ -105,7 +105,7 @@ export default {
target: null, target: null,
assetSelector: { assetSelector: {
active: false, active: false,
type: 'Scene' type: ['Scene']
}, },
dialog: false, dialog: false,
expandDrawer: false, expandDrawer: false,
+1 -1
View File
@@ -11,7 +11,7 @@
</g> </g>
</teleport> </teleport>
<v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text"> <v-card v-if="selected" :title="modelValue.title" class="mx-2" variant="text">
<asset-selector @select="assignTaskIntro" type="Descriptive"> <asset-selector @select="assignTaskIntro" :type="['Descriptive']">
<template v-slot:activator="props"> <template v-slot:activator="props">
<v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose task description</v-btn> <v-btn v-bind="props" prepend-icon="mdi-panorama-outline" color="success" block>Choose task description</v-btn>
</template> </template>
+2 -1
View File
@@ -20,7 +20,7 @@ class Hero{
this.actionIdle = this.mixer.clipAction( this.object.animations.find(a=>a.name=='idle') ); this.actionIdle = this.mixer.clipAction( this.object.animations.find(a=>a.name=='idle') );
this.actionIdle.play(); this.actionIdle.play();
this.activeAction = this.actionIdle; this.activeAction = this.actionIdle;
this.pointerControls = new PointerControls(gameEngine.cameraPivot, this.model, gameEngine.renderer.domElement); this.pointerControls = new PointerControls(gameEngine.camera, this.model, gameEngine.renderer.domElement);
gameEngine.hero = this; gameEngine.hero = this;
// Character Collider // Character Collider
@@ -96,6 +96,7 @@ class Hero{
} }
update(){ update(){
return;
let { inputVelocity, velocity, euler, quat, v, targetQuaternion, clock } = this; let { inputVelocity, velocity, euler, quat, v, targetQuaternion, clock } = this;
let pc = this.pointerControls; let pc = this.pointerControls;
pc.update(); pc.update();
+55 -42
View File
@@ -92,7 +92,7 @@ class GameEngine {
this.activeObjects = new THREE.Group(); this.activeObjects = new THREE.Group();
scene.add(this.activeObjects); scene.add(this.activeObjects);
const controls = new OrbitControls(this.camera, renderer.domElement, this.activeObjects); const controls = new OrbitControls(this.camera, renderer.domElement);
if (opts.gizmo) { if (opts.gizmo) {
const gizmo = new ViewportGizmo(this.camera, renderer, { const gizmo = new ViewportGizmo(this.camera, renderer, {
container: '.renderer-gizmo', container: '.renderer-gizmo',
@@ -181,8 +181,8 @@ class GameEngine {
c1.userData.active = false; c1.userData.active = false;
c1.addEventListener('connected', e => { c1.addEventListener('connected', e => {
c1.gamepad = e.data.gamepad; c1.gamepad = e.data.gamepad;
this.session = this.renderer.xr.getSession(); // this.session = this.renderer.xr.getSession();
this.session.addEventListener('selectstart', this.onControllerEvent.bind(this)); // this.session.addEventListener('selectstart', this.onControllerEvent.bind(this));
}) })
this.scene.add(c1); this.scene.add(c1);
@@ -213,13 +213,15 @@ class GameEngine {
line.name = 'line'; line.name = 'line';
line.scale.z = 5; line.scale.z = 5;
this.controllerLine = line;
this.xrController1 = c1 this.xrController1 = c1
this.xrController2 = c2 this.xrController2 = c2
} }
initCameraPivot() { initCameraPivot() {
const pivot = new THREE.Object3D() const pivot = new THREE.Object3D()
pivot.position.set(0, 1, 10) pivot.position.set(0, 0, 0)
const yaw = new THREE.Object3D() const yaw = new THREE.Object3D()
const pitch = new THREE.Object3D() const pitch = new THREE.Object3D()
@@ -264,10 +266,10 @@ class GameEngine {
if (gameEngine.xrController1?.gamepad) { if (gameEngine.xrController1?.gamepad) {
let gp = gameEngine.xrController1.gamepad; let gp = gameEngine.xrController1.gamepad;
if (gp.axes[3] != 0) { if (gp.axes[3] != 0) {
gameEngine.scene.position.z += gp.axes[3] * delta; gameEngine.activeObjects.position.z += gp.axes[3] * delta;
} }
if (gp.axes[2] != 0) { if (gp.axes[2] != 0) {
gameEngine.scene.position.x += gp.axes[2] * delta; gameEngine.activeObjects.position.x += gp.axes[2] * delta;
} }
} }
if (gameEngine.xrController2?.gamepad) { if (gameEngine.xrController2?.gamepad) {
@@ -279,12 +281,12 @@ class GameEngine {
// } // }
if (gp.axes[2] != 0) { if (gp.axes[2] != 0) {
if (gp1.buttons[4]?.pressed) { if (gp1.buttons[4]?.pressed) {
gameEngine.scene.position.y += gp.axes[2] * delta; gameEngine.activeObjects.position.y += gp.axes[2] * delta;
} else if (gp1.buttons[5]?.pressed) { } else if (gp1.buttons[5]?.pressed) {
let sc = gameEngine.scene.scale.x * (gp.axes[2] * delta * 0.5 + 1); let sc = gameEngine.activeObjects.scale.x * (gp.axes[2] * delta * 0.5 + 1);
gameEngine.scene.scale.set(sc, sc, sc); gameEngine.activeObjects.scale.set(sc, sc, sc);
} else { } else {
gameEngine.scene.rotation.y += gp.axes[2] * delta * 0.5; gameEngine.activeObjects.rotation.y += gp.axes[2] * delta * 0.5;
} }
} }
if (gp.buttons[4]?.pressed) { if (gp.buttons[4]?.pressed) {
@@ -306,45 +308,55 @@ class GameEngine {
onControllerEvent(event) { onControllerEvent(event) {
//this.handleXrAction(event, this); //this.handleXrAction(event, this);
event.type !== 'move' && console.log(event) //event.type !== 'move' && console.log(event)
// const controller = event.target; const controller = event.target;
// if (controller.userData.active === false) return; //console.log(event)
// this.raycaster.setFromXRController(controller); if (!controller.userData) return
// switch (event.type) { if (controller.userData.active === false) return;
// case 'selectstart': this.transformControls.getRaycaster().setFromXRController(controller);
// this.transformControls.pointerDown(null); switch (event.type) {
// break; case 'selectstart':
// case 'selectend': this.transformControls.pointerDown(null);
// this.transformControls.pointerUp(null); break;
// break; case 'selectend':
// case 'move': this.transformControls.pointerUp(null);
// this.transformControls.pointerHover(null); break;
// this.transformControls.pointerMove(null); case 'move':
// break; this.transformControls.pointerHover(null);
// } this.transformControls.pointerMove(null);
break;
}
} }
onSelect(event) { onSelect(event) {
// const controller = event.target; const controller = event.target;
// this.xrController1.userData.active = false; this.xrController1.userData.active = false;
// this.xrController2.userData.active = false; this.xrController2.userData.active = false;
// if (controller === this.xrController1) { if (controller === this.xrController1) {
// this.xrController1.userData.active = true; this.xrController1.userData.active = true;
// this.xrController1.add(line); this.xrController1.add(this.controllerLine);
// } }
// if (controller === this.xrController2) { if (controller === this.xrController2) {
// this.xrController2.userData.active = true; this.xrController2.userData.active = true;
// this.xrController2.add(line); this.xrController2.add(this.controllerLine);
// } }
// this.raycaster.setFromXRController(controller); this.raycaster.setFromXRController(controller);
// const intersects = this.raycaster.intersectObjects(this.activeObjects.children); const intersects = this.raycaster.intersectObjects(this.activeObjects.children, true);
// if (intersects.length > 0) { intersects.forEach(o => {
// this.transformControls.attach(intersects[0].object); while (o.object && !this.activeObjects.children.includes(o.object)) {
// } o.object = o.object.parent;
}
})
if (intersects.length > 0) {
setTimeout(() => {
this.transformControls.attach(intersects[0].object);
}, 100);
}
} }
$ = THREE; $ = THREE;
@@ -430,6 +442,7 @@ class GameEngine {
} }
}) })
} }
//console.log('intersects', intersects);
return intersects; return intersects;
} }
+1
View File
@@ -27,6 +27,7 @@ export default {
}, { }, {
value: 'player3d', value: 'player3d',
icon: 'human-greeting', icon: 'human-greeting',
type: 'Player',
render: true, render: true,
color: 'yellow-accent-4' color: 'yellow-accent-4'
}, { }, {