Simplified interactions, changed menu interactions for changing entities.

This commit is contained in:
Michael Mainguy 2024-04-10 16:36:36 -05:00
parent 2d3855621e
commit 727977d5c6
14 changed files with 303 additions and 138 deletions

98
package-lock.json generated
View File

@ -8,14 +8,14 @@
"name": "immersive",
"version": "0.0.1",
"dependencies": {
"@babylonjs/core": "^6.45.1",
"@babylonjs/gui": "^6.45.1",
"@babylonjs/core": "^7.1.0",
"@babylonjs/gui": "^7.1.0",
"@babylonjs/havok": "1.3.1",
"@babylonjs/inspector": "^6.45.1",
"@babylonjs/loaders": "^6.45.1",
"@babylonjs/materials": "^6.45.1",
"@babylonjs/procedural-textures": "^6.45.1",
"@babylonjs/serializers": "^6.45.1",
"@babylonjs/inspector": "^7.1.0",
"@babylonjs/loaders": "^7.1.0",
"@babylonjs/materials": "^7.1.0",
"@babylonjs/procedural-textures": "^7.1.0",
"@babylonjs/serializers": "^7.1.0",
"@picovoice/cobra-web": "^2.0.3",
"@picovoice/eagle-web": "^1.0.0",
"@picovoice/web-voice-processor": "^4.0.9",
@ -51,26 +51,26 @@
}
},
"node_modules/@babylonjs/core": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.45.1.tgz",
"integrity": "sha512-wkORoAqpnZb10bUhrI0vinE9IiW7+gSgH4U4Zp41wO4kSeV0mtJY+Q5Ez6/n9ad9sLykD2FD7650B+Qi5tTMSw=="
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-7.1.0.tgz",
"integrity": "sha512-nz1CmflajMPnjdnwYrj72s4D/Q8IkOW4DBbwMfUNLFSCondfFXS3sZBgHeCAHpimR5n4e27YwvJ66MkQJsSraQ=="
},
"node_modules/@babylonjs/gui": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.45.1.tgz",
"integrity": "sha512-lev/3nprv4t8lu3kW1zdlH7VzlWh9dmyZ2PkzybmBI6nB48bswPm7cX2ppaFTkpY8Z904js9TOsrYQotMzsUiw==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-7.1.0.tgz",
"integrity": "sha512-tY6MGtigjZwv+9rqtGTsyBZL9sHSPjgVq+JEWHUsACH0ffNkKsQxtKSDc5bryzNQpo1rzTMHqEeU+DnqNSVe1Q==",
"peerDependencies": {
"@babylonjs/core": "^6.0.0"
"@babylonjs/core": "^7.0.0"
}
},
"node_modules/@babylonjs/gui-editor": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/@babylonjs/gui-editor/-/gui-editor-6.8.0.tgz",
"integrity": "sha512-XSTYEfCdf04Th1xrTuIO/lHBSmfiG4s4fIDzpi0+OERO19bKQffzhFGh95NVzdL0XhvnQT88Fb6bkvsuAxFI/Q==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/gui-editor/-/gui-editor-7.1.0.tgz",
"integrity": "sha512-YHPR/2HxTT1ILSdGMAKOZ+askVCRV/hnI5CQqLVmAYkoW5FlY7TdRJtHn0JGEiOuK6Z5T3lJ3ru89wM+lGLqeg==",
"peer": true,
"peerDependencies": {
"@babylonjs/core": "^6.0.0",
"@babylonjs/gui": "^6.0.0",
"@babylonjs/core": "^7.0.0",
"@babylonjs/gui": "^7.0.0",
"@types/react": ">=16.7.3",
"@types/react-dom": ">=16.0.9"
}
@ -84,57 +84,57 @@
}
},
"node_modules/@babylonjs/inspector": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.45.1.tgz",
"integrity": "sha512-4YhJLD2FrVXUFIU+ttBanhevVaCBVLaBxhPuwrxXxKWkuBulFOQz7GkvRT/CJwA3Ad9/66qwS5+vfRT99GLM/w==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-7.1.0.tgz",
"integrity": "sha512-Hs9pk1LstJMnD4xXpHFlQVqXPtH/hhUcNSPaZlz8iesFrHJEXF4Mlao+ozwbl2WzDbMzmmex5nc1lw2HEBdhww==",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.0.0",
"@fortawesome/free-solid-svg-icons": "^6.0.0"
},
"peerDependencies": {
"@babylonjs/core": "^6.0.0",
"@babylonjs/gui": "^6.0.0",
"@babylonjs/gui-editor": "^6.0.0",
"@babylonjs/loaders": "^6.0.0",
"@babylonjs/materials": "^6.0.0",
"@babylonjs/serializers": "^6.0.0",
"@babylonjs/core": "^7.0.0",
"@babylonjs/gui": "^7.0.0",
"@babylonjs/gui-editor": "^7.0.0",
"@babylonjs/loaders": "^7.0.0",
"@babylonjs/materials": "^7.0.0",
"@babylonjs/serializers": "^7.0.0",
"@types/react": ">=16.7.3",
"@types/react-dom": ">=16.0.9"
}
},
"node_modules/@babylonjs/loaders": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-6.45.1.tgz",
"integrity": "sha512-a75JvRVxT3DROCrl5iigLEpI5/eR7Rh4wdsDzZNn7bv3sXB40Kbw8EL60W3jDBXPdGUqNVzqtrxJF/ec2udg/Q==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-7.1.0.tgz",
"integrity": "sha512-6gLbFiUsiqsQDRWLl4TL5pMKiemSAB/E61SHpp8xkBalxZUiKroSbZt3Irxc7CHIq8SE5CYfPUPYjs6BmpTgqw==",
"peerDependencies": {
"@babylonjs/core": "^6.0.0",
"babylonjs-gltf2interface": "^6.0.0"
"@babylonjs/core": "^7.0.0",
"babylonjs-gltf2interface": "^7.0.0"
}
},
"node_modules/@babylonjs/materials": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-6.45.1.tgz",
"integrity": "sha512-v1jqgG0bfX+8Qezq4eDT2sSjpQYW+ocNU70dbJF0AYrhuhhgf0SpM28C7DAKi9GUOKjMvZrIBEbFmJ6AijLjcQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-7.1.0.tgz",
"integrity": "sha512-tHzpV6xUqpAgF9rPudDXetk1tIPbhggrybfIpvoWwbKlffIPQw4URsA+IBG04U5owWsicdhvTLQWP1WEwfbMQg==",
"peerDependencies": {
"@babylonjs/core": "^6.0.0"
"@babylonjs/core": "^7.0.0"
}
},
"node_modules/@babylonjs/procedural-textures": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-6.45.1.tgz",
"integrity": "sha512-QpLuPknYIvylfUscSqorkuXO4QSI49atQnScWN43ZpRzr+ecXWnxEaOyAmt7bbf93htshtIkUQdJhwx8w4fqrg==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/procedural-textures/-/procedural-textures-7.1.0.tgz",
"integrity": "sha512-ajjaXEQJpWNQQzWZdUJJzN4NBtI96lxbrhmBUpPdfQwAhX2LRG0tbKWKXd66QHh82f/FG+daIA2BCL7M4f2MMw==",
"peerDependencies": {
"@babylonjs/core": "^6.0.0"
"@babylonjs/core": "^7.0.0"
}
},
"node_modules/@babylonjs/serializers": {
"version": "6.45.1",
"resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-6.45.1.tgz",
"integrity": "sha512-iSPUdjZhQIbSyi21IFiFC/wm6Bj4zcH9NhsN9i+xqLTbO/Uho49cHU0ew39n0Xn+LRsGRMTJWQLTsp+TPvAvrw==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babylonjs/serializers/-/serializers-7.1.0.tgz",
"integrity": "sha512-ToYutpqvqFVic+mhFkza6rLeE31sXXpixhdpu2bE+MRP13FoxNKfPD4np/DGBP7zUWmXIi2yRm6sZ7cGs8jp1g==",
"peerDependencies": {
"@babylonjs/core": "^6.0.0",
"babylonjs-gltf2interface": "^6.0.0"
"@babylonjs/core": "^7.0.0",
"babylonjs-gltf2interface": "^7.0.0"
}
},
"node_modules/@esbuild/aix-ppc64": {
@ -1083,9 +1083,9 @@
}
},
"node_modules/babylonjs-gltf2interface": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-6.8.0.tgz",
"integrity": "sha512-uCehLc8CnMUvWYttqQmJCHnhUjoftb4gK6Q+GXclgNr3CWiNDXHnbiBZQynA8SBfgkgE3bRk1+u+J5PQwkOepQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-7.1.0.tgz",
"integrity": "sha512-44UnRGFj/kp6/MxB6SU5ThxYBjm9W0aYGkDbtSoPW2ZuWd4uTCjCKe8oS3fhsqXcZ5+K+rQVsHb785hxC4zRcw==",
"peer": true
},
"node_modules/base64-js": {

View File

@ -17,14 +17,14 @@
},
"dependencies": {
"axios": "^1.6.8",
"@babylonjs/core": "^6.45.1",
"@babylonjs/gui": "^6.45.1",
"@babylonjs/core": "^7.1.0",
"@babylonjs/gui": "^7.1.0",
"@babylonjs/havok": "1.3.1",
"@babylonjs/inspector": "^6.45.1",
"@babylonjs/loaders": "^6.45.1",
"@babylonjs/materials": "^6.45.1",
"@babylonjs/procedural-textures": "^6.45.1",
"@babylonjs/serializers": "^6.45.1",
"@babylonjs/inspector": "^7.1.0",
"@babylonjs/loaders": "^7.1.0",
"@babylonjs/materials": "^7.1.0",
"@babylonjs/procedural-textures": "^7.1.0",
"@babylonjs/serializers": "^7.1.0",
"events": "^3.3.0",
"@typed-mxgraph/typed-mxgraph": "^1.0.8",
"@types/node": "^18.14.0",

View File

@ -20,7 +20,9 @@ import {snapGridVal} from "../util/functions/snapGridVal";
import {snapRotateVal} from "../util/functions/snapRotateVal";
import {grabAndClone} from "./functions/grab";
import {isDiagramEntity} from "../diagram/functions/isDiagramEntity";
import {ClickMenu} from "../menus/clickMenu";
const CLICK_TIME = 300;
export class Base {
static stickVector = Vector3.Zero();
protected controller: WebXRInputSource;
@ -32,7 +34,7 @@ export class Base {
protected previousRotation: Vector3 = null;
protected previousScaling: Vector3 = null;
protected previousPosition: Vector3 = null;
private clickStart: number = 0;
protected readonly xr: WebXRDefaultExperience;
protected readonly diagramManager: DiagramManager;
private logger: log.Logger;
@ -45,6 +47,7 @@ export class Base {
controllers: Controllers,
diagramManager: DiagramManager) {
this.logger = log.getLogger('Base');
this.logger.setLevel(this.logger.levels.DEBUG);
this.controller = controller;
this.controllers = controllers;
this.scene = scene;
@ -71,9 +74,14 @@ export class Base {
this.diagramManager = diagramManager;
this.controller.onMotionControllerInitObservable.add((init) => {
this.logger.debug(init.components);
if (init.components['xr-standard-squeeze']) {
this.initGrip(init.components['xr-standard-squeeze'])
}
if (init.components['xr-standard-trigger']) {
this.initClicker(init.components['xr-standard-trigger']);
}
}, -1, false, this);
this.controllers.controllerObserver.add((event) => {
this.logger.debug(event);
@ -108,7 +116,33 @@ export class Base {
this.controller.pointer.setEnabled(true)
}
private grab() {
protected initClicker(trigger: WebXRControllerComponent) {
this.logger.debug("initTrigger");
trigger.onButtonStateChangedObservable.add(() => {
if (trigger.changes.pressed) {
if (trigger.pressed) {
if (this.clickStart == 0) {
this.clickStart = Date.now();
window.setTimeout(() => {
if (this.clickStart > 0) {
this.logger.debug("grabbing and cloning");
this.grab(true);
}
}, 300, this);
}
} else {
const clickEnd = Date.now();
if (this.clickStart > 0 && (clickEnd - this.clickStart) < CLICK_TIME) {
this.click();
}
this.drop();
this.clickStart = 0;
}
}
}, -1, false, this);
}
private grab(cloneEntity: boolean = false) {
let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
if (!mesh) {
return;
@ -116,7 +150,7 @@ export class Base {
let player = false;
if (!isDiagramEntity(mesh)) {
if (mesh?.metadata?.handle == true) {
if (this.handleWasGrabbed(mesh)) {
mesh && mesh.setParent(this.controller.motionController.rootMesh);
this.grabbedMesh = mesh;
} else {
@ -132,7 +166,6 @@ export class Base {
}
} else {
if (mesh?.metadata?.template == '#connection-template') {
return;
}
@ -143,7 +176,7 @@ export class Base {
this.previousScaling = mesh?.scaling.clone();
this.previousPosition = mesh?.position.clone();
if (!mesh.metadata?.grabClone || player) {
if ((!mesh.metadata?.grabClone || player) && !cloneEntity) {
if (mesh.physicsBody) {
const transformNode = setupTransformNode(mesh, this.controller.motionController.rootMesh);
mesh.physicsBody.setMotionType(PhysicsMotionType.ANIMATED);
@ -151,9 +184,9 @@ export class Base {
} else {
mesh.setParent(this.controller.motionController.rootMesh);
}
this.grabbedMesh = mesh;
} else {
this.logger.debug("cloning " + mesh?.id);
const clone = grabAndClone(this.diagramManager, mesh, this.controller.motionController.rootMesh);
clone.newMesh.metadata.grabClone = false;
clone.newMesh.metadata.tool = false;
@ -168,29 +201,25 @@ export class Base {
}
}
private toolboxHandleWasGrabbed(mesh: AbstractMesh): boolean {
private handleWasGrabbed(mesh: AbstractMesh): boolean {
if (isDiagramEntity(mesh)) {
this.grabbedMesh = null;
this.previousParentId = null;
mesh.setParent(null);
return false;
} else {
return (mesh?.metadata?.handle == true);
}
}
private drop() {
const mesh = this.grabbedMesh;
if (!mesh) {
return;
}
if (this.toolboxHandleWasGrabbed(mesh)) {
if (this.handleWasGrabbed(mesh)) {
mesh.setParent(this.scene.getMeshByName("platform"))
return;
}
reparent(mesh, this.previousParentId, this.grabbedMeshParentId);
this.grabbedMeshParentId = null;
if (!mesh.physicsBody) {
mesh.position = snapGridVal(mesh.position, this.diagramManager._config.current.gridSnap);
mesh.rotation = snapRotateVal(mesh.rotation, this.diagramManager._config.current.rotateSnap);
@ -224,15 +253,32 @@ export class Base {
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
}
private click() {
let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
if (pointable(mesh)) {
this.logger.debug("click on " + mesh.id);
const menu = new ClickMenu(mesh, this.diagramManager);
} else {
this.logger.debug("click on nothing");
}
}
private initGrip(grip: WebXRControllerComponent) {
grip.onButtonStateChangedObservable.add(() => {
if (grip.changes.pressed) {
if (grip.pressed) {
this.grab();
} else {
this.drop();
}
}
});
}
}
function pointable(mesh: AbstractMesh): boolean {
return (mesh && mesh.metadata?.template && !mesh.metadata?.tool && !mesh.metadata?.handle && !mesh.metadata?.grabbable && !mesh.metadata?.grabClone);
}

1
src/env.d.ts vendored
View File

@ -3,6 +3,7 @@
interface ImportMetaEnv {
readonly VITE_SYNCDB_ENDPOINT: string,
readonly VITE_SYNCDB_USER: string
readonly VITE_CREATE_ENDPOINT: string
// more env variables...
}

View File

@ -37,8 +37,6 @@ export class InputTextView {
}
public showVirtualKeyboard() {
const inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
const handle = new Handle(inputMesh);
setMenuPosition(handle.mesh, this.scene, new Vector3(0, .4, 0));

View File

@ -1,20 +0,0 @@
import log from "loglevel";
const logger = log.getLogger('syncDoc');
export function syncDoc(info) {
logger.debug(info);
if (info.direction == 'pull') {
const docs = info.change.docs;
for (const doc of docs) {
logger.debug(doc);
if (doc._deleted) {
logger.debug('Delete', doc);
this.removeObserver.notifyObservers({id: doc._id, template: doc.template}, 1);
} else {
this.updateObserver.notifyObservers(doc, 1);
}
}
}
}

View File

@ -6,7 +6,6 @@ import {v4 as uuidv4} from 'uuid';
import axios from "axios";
import {DiagramManager} from "../diagram/diagramManager";
import log, {Logger} from "loglevel";
import {syncDoc} from "./functions/syncDoc";
const logger: Logger = log.getLogger('PouchdbPersistenceManager');
export class PouchdbPersistenceManager {
@ -166,7 +165,7 @@ export class PouchdbPersistenceManager {
createSnap: 0,
turnSnap: 0,
flyMode: true,
currentDiagramId: uuidv4()
currentDiagramId: 'public'
}
try {
await this.setConfig(defaultConfig, true);
@ -217,22 +216,53 @@ export class PouchdbPersistenceManager {
}
private async beginSync(remoteDbName: string) {
private syncDoc(info) {
logger.debug(info);
if (info.direction == 'pull') {
const docs = info.change.docs;
for (const doc of docs) {
logger.debug(doc);
if (doc._deleted) {
logger.debug('Delete', doc);
this.removeObserver.notifyObservers({id: doc._id, template: doc.template}, 1);
} else {
this.updateObserver.notifyObservers(doc, 1);
}
}
}
}
private async beginSync(localName: string) {
try {
//const remoteDbName = "db1";
const userHex = remoteDbName.split('-');
if (userHex.length < 2) {
return;
}
const username = hex_to_ascii(userHex[1]);
const remoteUserName = username;
const password = "password";
const userHex = ascii_to_hex(localName);
const remoteDbName = 'userdb-' + userHex;
const remoteUserName = localName;
const password = localName;
const dbs = await axios.get(import.meta.env.VITE_SYNCDB_ENDPOINT + 'list');
logger.debug(dbs.data);
if (dbs.data.indexOf(remoteDbName) == -1) {
logger.warn('sync target missing');
logger.warn('sync target missing attempting to create');
const newdb = await axios.post(import.meta.env.VITE_CREATE_ENDPOINT,
{
"_id": "org.couchdb.user:" + localName,
"name": localName,
"password": localName,
"roles": ["readers"],
"type": "user"
}
);
if (newdb.status == 200) {
logger.info('sync target created');
} else {
return;
}
}
const userEndpoint: string = import.meta.env.VITE_USER_ENDPOINT
logger.debug(userEndpoint);
logger.debug(remoteDbName);
@ -262,9 +292,11 @@ export class PouchdbPersistenceManager {
{auth: {username: remoteUserName, password: password}, skip_setup: true});
const dbInfo = await this.remote.info();
logger.debug(dbInfo);
syncDoc.bind(this);
this.db.sync(this.remote, {live: true, retry: true})
.on('change', syncDoc)
.on('change', (info) => {
this.syncDoc(info)
})
.on('active', function (info) {
logger.debug('sync active', info)
})
@ -272,7 +304,7 @@ export class PouchdbPersistenceManager {
logger.debug('sync paused', info)
})
.on('error', function (err) {
logger.debug('sync error', err)
logger.error('sync error', err)
});
} catch (err) {
logger.error(err);
@ -283,8 +315,17 @@ export class PouchdbPersistenceManager {
function hex_to_ascii(input) {
var hex = input.toString();
let output = '';
for (var n = 0; n < hex.length; n += 2) {
for (let n = 0; n < hex.length; n += 2) {
output += String.fromCharCode(parseInt(hex.substr(n, 2), 16));
}
return output;
}
function ascii_to_hex(str) {
const arr1 = [];
for (let n = 0, l = str.length; n < l; n++) {
var hex = Number(str.charCodeAt(n)).toString(16);
arr1.push(hex);
}
return arr1.join('');
}

78
src/menus/clickMenu.ts Normal file
View File

@ -0,0 +1,78 @@
import {Button3D, GUI3DManager, PlanePanel, TextBlock} from "@babylonjs/gui";
import {AbstractMesh, TransformNode} from "@babylonjs/core";
import {DiagramEvent, DiagramEventType} from "../diagram/types/diagramEntity";
import {toDiagramEntity} from "../diagram/functions/toDiagramEntity";
import {DiagramManager} from "../diagram/diagramManager";
export class ClickMenu {
private static readonly sounds;
private readonly entity: AbstractMesh;
private readonly manager: GUI3DManager;
private readonly transform: TransformNode;
private readonly diagramManager: DiagramManager;
constructor(entity: AbstractMesh, diagramManager: DiagramManager) {
this.entity = entity;
this.diagramManager = diagramManager;
const scene = entity.getScene();
const manager = new GUI3DManager(scene);
const transform = new TransformNode("transform", scene);
transform.position = entity.absolutePosition.clone();
transform.position.y += entity.scaling.y;
const panel = new PlanePanel();
panel.orientation = PlanePanel.FACEFORWARDREVERSED_ORIENTATION;
panel.columns = 4;
manager.controlScaling = .1;
manager.addControl(panel);
panel.addControl(this.makeButton("Remove", "remove"));
panel.addControl(this.makeButton("Label", "label"));
panel.addControl(this.makeButton("Connect", "connect"));
panel.addControl(this.makeButton("Close", "close"));
panel.linkToTransformNode(transform);
this.transform = transform;
this.manager = manager;
}
private makeButton(name: string, id: string) {
const button = new Button3D(name);
//button.scaling = new Vector3(.1, .1, .1);
button.name = id;
const text = new TextBlock(name, name);
text.fontSize = "48px";
text.color = "#ffffff";
text.alpha = 1;
button.content = text;
button.onPointerClickObservable.add(() => {
switch (id) {
case "close":
this.dispose();
break;
case "remove":
const event: DiagramEvent = {
type: DiagramEventType.REMOVE,
entity:
toDiagramEntity(this.entity)
}
this.diagramManager.onDiagramEventObservable.notifyObservers(event, -1);
this.dispose();
break;
case "label":
}
}, -1, false, this, true);
return button;
}
private dispose() {
this.manager.dispose();
this.transform.dispose();
}
}

View File

@ -13,6 +13,7 @@ export class Handle {
private buildHandle() {
const scene: Scene = this.transformNode.getScene();
const handle = getHandleMesh("handle-" + this.transformNode.id + "-mesh", scene);
handle.position = Vector3.Zero();
handle.metadata = {handle: true};
if (this.transformNode) {

View File

@ -0,0 +1,6 @@
export type ObjectMetaType = {
id: string;
parent: string;
position: { x: number, y: number, z: number };
rotation: { x: number, y: number, z: number };
}

View File

@ -1,6 +1,5 @@
import {AxesViewer, Color3, Mesh, Node, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {AbstractMesh, AxesViewer, Color3, Node, Observable, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {GUI3DManager, StackPanel3D,} from "@babylonjs/gui";
import {setMenuPosition} from "../util/functions/setMenuPosition";
import {buildColor} from "./functions/buildColor";
import log from "loglevel";
import {Handle} from "../objects/handle";
@ -34,20 +33,14 @@ export class Toolbox {
new Handle(this.toolboxBaseNode);
this.toolboxBaseNode.position.y = .2;
//this.toolboxBaseNode.position.z = .05;
/**this.axes = new AxesViewer(this.scene);
/*this.axes = new AxesViewer(this.scene);
this.axes.xAxis.parent = this.toolboxBaseNode;
this.axes.yAxis.parent = this.toolboxBaseNode;
this.axes.zAxis.parent = this.toolboxBaseNode;*/
this.axes.zAxis.parent = this.toolboxBaseNode; */
this.toolboxBaseNode.scaling = new Vector3(0.6, 0.6, 0.6);
this.buildToolbox();
}
public toggle() {
this.toolboxBaseNode.parent.setEnabled(!this.toolboxBaseNode.parent.isEnabled(false));
setMenuPosition(this.toolboxBaseNode.parent as Mesh, this.scene,
Vector3.Zero());
}
public updateToolbox(color: string) {
if (color) {
if (this.scene.getMeshById("toolbox-color-" + color)) {
@ -98,9 +91,27 @@ export class Toolbox {
}
}
//this.toolboxBaseNode.parent.setEnabled(false);
setMenuPosition(this.toolboxBaseNode.parent as Mesh, this.scene,
Vector3.Zero());
const offset = new Vector3(0, 1, 1);
if (this.toolboxBaseNode.parent) {
const platform = this.scene.getNodeById("platform");
if (platform) {
const handle = (this.toolboxBaseNode.parent as TransformNode);
handle.parent = platform;
handle.position = offset;
} else {
this.scene.onNewMeshAddedObservable.add((mesh: AbstractMesh) => {
if (mesh.id == "platform") {
const handle = (this.toolboxBaseNode.parent as TransformNode);
handle.parent = mesh;
handle.position = offset;
}
});
}
}
/*setMenuPosition(this.toolboxBaseNode.parent as Mesh, this.scene,
Vector3.Zero());*/
}
}

View File

@ -1,10 +1,11 @@
import {MeshBuilder, Scene, Vector3} from "@babylonjs/core";
const debug = false;
const debug = true;
export function getFrontPosition(distance: number, scene: Scene): Vector3 {
const offset = new Vector3(0, 0, distance);
offset.applyRotationQuaternionInPlace(scene.activeCamera.absoluteRotation);
const newPos = scene.activeCamera.globalPosition.add(offset);
//offset.applyRotationQuaternionInPlace(scene.activeCamera.absoluteRotation);
const camPos = scene.activeCamera.globalPosition.clone();
const newPos = camPos.add(offset);
if (debug) {
const mesh = MeshBuilder.CreateIcoSphere("front", {radius: .1}, scene);
mesh.position = newPos;

View File

@ -1,5 +1,4 @@
import {Scene, TransformNode, Vector3} from "@babylonjs/core";
import {getFrontPosition} from "./getFrontPosition";
import {Scene, TransformNode, Vector3, WebXRCamera} from "@babylonjs/core";
import log from "loglevel";
const logger = log.getLogger('setMenuPosition');
@ -39,34 +38,33 @@ export function setMenuPosition(node: TransformNode, scene: Scene, offset: Vecto
*/
if (scene.activeCamera) {
setPosition(node, scene, offset);
//setPosition(node, scene, offset);
} else {
scene.onActiveCameraChanged.add((scene: Scene) => {
setPosition(node, scene, offset);
//setPosition(node, scene, offset);
});
logger.error("No active camera");
}
}
const debug = true;
const debug = false;
function setPosition(node: TransformNode, scene: Scene, offset: Vector3 = Vector3.Zero()) {
const platform = scene.getNodeById("platform");
switch (scene.activeCamera.getClassName()) {
case "WebXRCamera":
//const oldParent = node.parent;
window.setTimeout(() => {
node.setParent(null);
const front = getFrontPosition(1, scene).clone();
const camPos = scene.activeCamera.globalPosition.clone();
const newPos = new Vector3(front.x + offset.x, 1.2 + offset.y, front.z + offset.z);
const camera = scene.activeCamera as WebXRCamera;
const front = camera.getFrontPosition(.7);
const camPos = camera.globalPosition.clone();
const newPos = new Vector3(front.x + offset.x, front.y + offset.y - .3, front.z + offset.z);
node.position = newPos;
node.lookAt(camPos);
// const target = MeshBuilder.CreateIcoSphere("target", {radius: .1}, scene);
// target.position = newPos;
// target.setParent(platform);
node.setParent(platform);
}, 1000);
break;
case "FreeCamera":
case "DeviceOrientationCamera":

View File

@ -18,6 +18,10 @@ export default defineConfig({
'^/sync/.*': {
target: 'https://www.deepdiagram.com/',
changeOrigin: true,
},
'^/create-db': {
target: 'https://www.deepdiagram.com/',
changeOrigin: true,
}
}
},