diff --git a/index.html b/index.html
index 7957f56..9464f6e 100644
--- a/index.html
+++ b/index.html
@@ -15,7 +15,7 @@
align-content: center;
flex-direction: column;
z-index: -1;
- background: url("/loading-loading-forever.gif");
+ background: url("/spinner.gif");
background-position: center;
background-repeat: no-repeat;
text-align: center;
diff --git a/package-lock.json b/package-lock.json
index df53abc..a04d981 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,10 +10,10 @@
"hasInstallScript": true,
"dependencies": {
"@auth0/auth0-spa-js": "^2.0.8",
- "@babylonjs/core": "^6.8.0",
- "@babylonjs/gui": "^6.9.0",
- "@babylonjs/havok": "^1.0.1",
- "@babylonjs/inspector": "^6.8.0",
+ "@babylonjs/core": "^6.12.3",
+ "@babylonjs/gui": "^6.12.3",
+ "@babylonjs/havok": "^1.1.0",
+ "@babylonjs/inspector": "^6.12.3",
"@maptiler/client": "^1.5.0",
"axios": "^1.4.0",
"express": "^4.18.2",
@@ -48,14 +48,14 @@
}
},
"node_modules/@babylonjs/core": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.8.0.tgz",
- "integrity": "sha512-wTWj9TsnVGqfXt+tXKi7+SIWi4MzBMwIq+jcylRR1qzHTHFfMuKrRRLZJ5jQtpAhcDPI2TOuJ3/NOccPyawlgQ=="
+ "version": "6.12.3",
+ "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-6.12.3.tgz",
+ "integrity": "sha512-p1di605M2Pa5+YiHbydGJ3PA4nUWSlmu79agL3mcsq7s8zC5VN/HaK1uNSicYI9LhVfPF6bDsVGHqCXxEkRsFQ=="
},
"node_modules/@babylonjs/gui": {
- "version": "6.9.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.9.0.tgz",
- "integrity": "sha512-RcVorxsj6n2EbwkBJYPBqF88Rybd3OHbx55runbMSehb9rKhc6d2QIiXTi7yI2oBNyuQBsDxx+ky58Rur2UXww==",
+ "version": "6.12.3",
+ "resolved": "https://registry.npmjs.org/@babylonjs/gui/-/gui-6.12.3.tgz",
+ "integrity": "sha512-Yh9rVWwAymjy23g8dC5PMjeI2c71HWMZ6Lw2G0yjTZS9gf0st2A/OLsv/4ofK51u0fqvHZFBTfFTL5ZOFYNMow==",
"peerDependencies": {
"@babylonjs/core": "^6.0.0"
}
@@ -73,17 +73,17 @@
}
},
"node_modules/@babylonjs/havok": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.0.1.tgz",
- "integrity": "sha512-J41CIAbL9WOQkPRdMADEVKDKZsU4iOlesBg0C/LP1GPxUncGVylLPkyyGPcQPLd6ifV9cZcnkEJrkiE8xVahTw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@babylonjs/havok/-/havok-1.1.0.tgz",
+ "integrity": "sha512-BNo2d+gfkoCbbEGYOVZgdPWG6NRdo5Tjvd9rpjMs0sWV/EaKQ6kL8hnJUn+HVZx4hdyKrTkq8ThTGFt/nTediA==",
"dependencies": {
"@types/emscripten": "^1.39.6"
}
},
"node_modules/@babylonjs/inspector": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.8.0.tgz",
- "integrity": "sha512-tu3nb0l7xSYXkTaKAnP7zBL34qR9J0op+NzOn4Y1C9RcY91yH3YfLTdoo4pFA0K5NaS99W0nAIjCcrS2BPBmMQ==",
+ "version": "6.12.3",
+ "resolved": "https://registry.npmjs.org/@babylonjs/inspector/-/inspector-6.12.3.tgz",
+ "integrity": "sha512-REW+BF4LQhOK0cRRTVfSaOGnjh1LVE1lgwel7BBjjWeRcIjCVBimAprPY8rE0K+EAGMmPlxt9rDIpGoA0PUTqQ==",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-regular-svg-icons": "^6.0.0",
diff --git a/package.json b/package.json
index c3ef175..361feca 100644
--- a/package.json
+++ b/package.json
@@ -12,10 +12,10 @@
"postinstall": "cp ./node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm ./node_modules/.vite/deps"
},
"dependencies": {
- "@babylonjs/core": "^6.8.0",
- "@babylonjs/gui": "^6.9.0",
- "@babylonjs/havok": "^1.0.1",
- "@babylonjs/inspector": "^6.8.0",
+ "@babylonjs/core": "^6.12.3",
+ "@babylonjs/gui": "^6.12.3",
+ "@babylonjs/havok": "^1.1.0",
+ "@babylonjs/inspector": "^6.12.3",
"express": "^4.18.2",
"@auth0/auth0-spa-js": "^2.0.8",
"ring-client-api": "^11.8.0",
diff --git a/public/spinner.gif b/public/spinner.gif
new file mode 100644
index 0000000..116ffcb
Binary files /dev/null and b/public/spinner.gif differ
diff --git a/src/app.ts b/src/app.ts
index 98fe0be..b3c7c3d 100644
--- a/src/app.ts
+++ b/src/app.ts
@@ -19,15 +19,16 @@ import {
///import {havokModule} from "./util/havok";
import HavokPhysics from "@babylonjs/havok";
import {Rigplatform} from "./controllers/rigplatform";
-
import {DiagramManager} from "./diagram/diagramManager";
-class App {
+export class App {
//preTasks = [havokModule];
private token: string;
-
+ public static scene: Scene;
+ public static xr: WebXRDefaultExperience;
+ public static rig: Rigplatform;
constructor() {
const canvas = document.createElement("canvas");
canvas.style.width = "100%";
@@ -40,38 +41,46 @@ class App {
}
async initialize(canvas) {
-
+ if (App.xr) {
+ App.xr.dispose();
+ App.xr=null;
+ }
+ if (App.scene) {
+ App.scene.dispose();
+ App.scene = null;
+ }
+ if (DiagramManager.onDiagramEventObservable) {
+ DiagramManager.onDiagramEventObservable.clear();
+ DiagramManager.onDiagramEventObservable = null;
+ }
const engine = new Engine(canvas, true);
const scene = new Scene(engine);
- const diagramManager = new DiagramManager(scene);
+
+ App.scene = scene;
+
+
+
const havokInstance = await HavokPhysics();
+
const havokPlugin = new HavokPlugin(true, havokInstance);
scene.enablePhysics(new Vector3(0, -9.8, 0), havokPlugin);
const camera: ArcRotateCamera = new ArcRotateCamera("Camera", Math.PI / 2, Math.PI / 2, 2,
new Vector3(0, 1.6, 0), scene);
camera.attachControl(canvas, true);
new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
-
-
- //const envTexture = new CubeTexture("/assets/textures/SpecularHDR.dds", scene);
- //scene.createDefaultSkybox(envTexture, true, 1000);
-
const photoDome = new PhotoDome('sky',
'./outdoor_field.jpeg', {},
scene);
- const xr = await WebXRDefaultExperience.CreateAsync(scene, {
- floorMeshes: [this.createGround(scene)],
+ App.xr = await WebXRDefaultExperience.CreateAsync(scene, {
+ floorMeshes: [this.createGround()],
disableTeleportation: true,
optionalFeatures: true
});
- const rig = new Rigplatform(scene, xr);
- //const ring = new Cameras(scene, this.token);
- //ring.getCameras().then(() => ring.createCameras());
- //xr.teleportation.detach();
+ const diagramManager = new DiagramManager(App.scene, App.xr.baseExperience);
+ App.rig = new Rigplatform(App.scene, App.xr);
- // hide/show the Inspector
window.addEventListener("keydown", (ev) => {
// Shift+Ctrl+Alt+I
if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
@@ -89,19 +98,19 @@ class App {
});
}
- createGround(scene) {
- const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", scene);
- const gText = new Texture("./grass1.jpeg", scene);
+ createGround() {
+ const groundMaterial = new PBRMetallicRoughnessMaterial("groundMaterial", App.scene);
+ const gText = new Texture("./grass1.jpeg", App.scene);
gText.uScale = 40;
gText.vScale = 40;
groundMaterial.baseTexture = gText;
groundMaterial.metallic = 0;
groundMaterial.roughness = 1;
- const ground = MeshBuilder.CreateGround("ground", {width: 100, height: 100, subdivisions: 1}, scene);
+ const ground = MeshBuilder.CreateGround("ground", {width: 100, height: 100, subdivisions: 1}, App.scene);
ground.material = groundMaterial;
- const groundAggregate = new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, scene);
+ new PhysicsAggregate(ground, PhysicsShapeType.BOX, {mass: 0}, App.scene);
return ground;
}
}
diff --git a/src/controllers/base.ts b/src/controllers/base.ts
index 319c414..1213944 100644
--- a/src/controllers/base.ts
+++ b/src/controllers/base.ts
@@ -1,10 +1,8 @@
import {Vector3, WebXRInputSource} from "@babylonjs/core";
-import {Rigplatform} from "./rigplatform";
export class Base {
static stickVector = Vector3.Zero();
protected controller: WebXRInputSource;
- protected rig: Rigplatform;
protected speedFactor = 4;
constructor(controller:
@@ -22,8 +20,7 @@ export class Base {
}
});
}
-
- setRig(rig: Rigplatform) {
- this.rig = rig;
+ public mesh() {
+ return this.controller.grip;
}
}
\ No newline at end of file
diff --git a/src/controllers/controllers.ts b/src/controllers/controllers.ts
new file mode 100644
index 0000000..73882eb
--- /dev/null
+++ b/src/controllers/controllers.ts
@@ -0,0 +1,20 @@
+
+import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core";
+
+export enum ControllerMovementMode {
+ ROTATE,
+ TRANSLATE
+}
+export class Controllers {
+ public static movable: TransformNode | AbstractMesh;
+ public static controllerObserver = new Observable();
+ public static movementMode: ControllerMovementMode = ControllerMovementMode.ROTATE;
+ public static toggleMovementMode() {
+ if (this.movementMode == ControllerMovementMode.ROTATE) {
+ this.movementMode = ControllerMovementMode.TRANSLATE;
+ } else {
+ this.movementMode = ControllerMovementMode.ROTATE;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/controllers/left.ts b/src/controllers/left.ts
index ff7e110..8a582fb 100644
--- a/src/controllers/left.ts
+++ b/src/controllers/left.ts
@@ -1,40 +1,65 @@
import {Vector3, WebXRInputSource} from "@babylonjs/core";
import {Base} from "./base";
+import {Controllers} from "./controllers";
+
export class Left extends Base {
-
+ public static instance: Left;
constructor(controller:
WebXRInputSource) {
super(controller);
+
+ Left.instance = this;
this.controller.onMotionControllerInitObservable.add((init) => {
if (init.components['xr-standard-thumbstick']) {
init.components['xr-standard-thumbstick']
.onAxisValueChangedObservable.add((value) => {
-
- if (Math.abs(value.x) > .1) {
- this.rig.leftright(value.x * this.speedFactor);
- Base.stickVector.x = 1;
+ if (!Controllers.movable) {
+ this.moveRig(value);
} else {
- Base.stickVector.x = 0;
- }
- if (Math.abs(value.y) > .1) {
- this.rig.updown(value.y * this.speedFactor);
- Base.stickVector.y = 1;
- } else {
- Base.stickVector.y = 0;
+ this.moveMovable(value);
}
- if (Base.stickVector.equals(Vector3.Zero())) {
- this.rig.updown(0);
- this.rig.leftright(0)
- } else {
-
- }
});
}
});
}
+
+ private moveMovable(value: { x: number, y: number }) {
+ if (Math.abs(value.x) > .1) {
+ Controllers.movable.position.x += .005 * Math.sign(value.x);
+ } else {
+
+ }
+ if (Math.abs(value.y) > .1) {
+ Controllers.movable.position.y += -.005 * Math.sign(value.y);
+ } else {
+
+ }
+ }
+
+ private moveRig(value: { x: number, y: number }) {
+ if (Math.abs(value.x) > .1) {
+ Controllers.controllerObserver.notifyObservers({type: 'leftright', value: value.x * this.speedFactor});
+ Base.stickVector.x = 1;
+ } else {
+ Base.stickVector.x = 0;
+ }
+ if (Math.abs(value.y) > .1) {
+ Controllers.controllerObserver.notifyObservers({type: 'updown', value: value.y * this.speedFactor});
+ Base.stickVector.y = 1;
+ } else {
+ Base.stickVector.y = 0;
+ }
+
+ if (Base.stickVector.equals(Vector3.Zero())) {
+ Controllers.controllerObserver.notifyObservers({type: 'leftright', value: 0});
+ Controllers.controllerObserver.notifyObservers({type: 'updown', value: 0});
+ } else {
+
+ }
+ }
}
\ No newline at end of file
diff --git a/src/controllers/right.ts b/src/controllers/right.ts
index 16bf432..54bb12f 100644
--- a/src/controllers/right.ts
+++ b/src/controllers/right.ts
@@ -1,71 +1,160 @@
import {Base} from "./base";
-import {Vector3, WebXRInputSource} from "@babylonjs/core";
-import {Bmenu, BmenuState} from "../menus/bmenu";
-import {DiagramEvent, DiagramEventType, DiagramManager} from "../diagram/diagramManager";
+import {Angle, Observable, Vector3, WebXRControllerComponent, WebXRInputSource} from "@babylonjs/core";
+import {Bmenu} from "../menus/bmenu";
+import {DiagramManager} from "../diagram/diagramManager";
+import {ControllerMovementMode, Controllers} from "./controllers";
+import {BmenuState} from "../menus/MenuState";
+import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
+
+
export class Right extends Base {
private bmenu: Bmenu;
+ public static instance: Right;
+
private down: boolean = false;
+ private initBButton(bbutton: WebXRControllerComponent) {
+ if (bbutton) {
+ bbutton.onButtonStateChangedObservable.add((value) => {
+ if (value.pressed) {
+ this.bmenu.toggle(this.controller.grip);
+ }
+ });
+ }
+ }
+
+ private initTrigger(trigger: WebXRControllerComponent) {
+ if (trigger) {
+ trigger
+ .onButtonStateChangedObservable
+ .add((value) => {
+ if (value.value > .4 && !this.down) {
+ this.down = true;
+ if (this.bmenu.getState() == BmenuState.ADDING) {
+ this.bmenu.setState(BmenuState.DROPPING);
+ const event: DiagramEvent = {
+ type: DiagramEventType.DROP,
+ entity: null
+ }
+ DiagramManager.onDiagramEventObservable.notifyObservers(event);
+ }
+ }
+ if (value.value < .05) {
+ this.down = false;
+ }
+ });
+ }
+ }
+
+ private initAButton(abutton: WebXRControllerComponent) {
+ if (abutton) {
+ abutton.onButtonStateChangedObservable.add((value) => {
+ if (value.pressed) {
+ if (DiagramManager.currentMesh) {
+ if (Controllers.movable) {
+ Controllers.movable = null;
+ } else {
+ Controllers.movable = DiagramManager.currentMesh;
+ }
+
+ }
+ }
+ });
+ }
+ }
+
+ private initThumbstick(thumbstick: WebXRControllerComponent) {
+ if (thumbstick) {
+ thumbstick.onAxisValueChangedObservable.add((value) => {
+ if (!Controllers.movable) {
+ this.moveRig(value);
+ } else {
+ if (Controllers.movementMode == ControllerMovementMode.ROTATE) {
+ this.rotateMovable(value);
+ } else {
+ this.moveMovable(value);
+ }
+ }
+ });
+ thumbstick.onButtonStateChangedObservable.add((value) => {
+ if (value.pressed) {
+ Controllers.toggleMovementMode();
+ }
+ });
+ }
+ }
+
+ private moveRig(value) {
+ if (Math.abs(value.x) > .1) {
+ Controllers.controllerObserver.notifyObservers({type: 'turn', value: value.x});
+ } else {
+ Controllers.controllerObserver.notifyObservers({type: 'turn', value: 0});
+ }
+ if (Math.abs(value.y) > .1) {
+ Controllers.controllerObserver.notifyObservers({type: 'forwardback', value: value.y * this.speedFactor});
+ Base.stickVector.z = 1;
+ } else {
+ Controllers.controllerObserver.notifyObservers({type: 'forwardback', value: 0});
+ Base.stickVector.z = 0;
+ }
+ if (Base.stickVector.equals(Vector3.Zero())) {
+ Controllers.controllerObserver.notifyObservers({type: 'forwardback', value: 0});
+ }
+ }
+
constructor(controller:
WebXRInputSource) {
super(controller);
+ Right.instance = this;
this.controller.onMotionControllerInitObservable.add((init) => {
- const trigger = init.components['xr-standard-trigger'];
- if (trigger) {
- trigger
- .onButtonStateChangedObservable
- .add((value) => {
- if (value.value > .4 && !this.down) {
- this.down = true;
- if (this.bmenu.getState() == BmenuState.ADDING) {
- this.bmenu.setState(BmenuState.DROPPING);
- const event: DiagramEvent = {
- type: DiagramEventType.DROP,
- entity: null
- }
- DiagramManager.onDiagramEventObservable.notifyObservers(event);
- }
- }
- if (value.value < .05) {
- this.down = false;
- }
- });
- }
- if (init.components['b-button']) {
- init.components['b-button'].onButtonStateChangedObservable.add((value) => {
- if (value.pressed) {
- this.bmenu.toggle();
- }
- });
- }
-
- if (init.components['xr-standard-thumbstick']) {
- init.components['xr-standard-thumbstick']
- .onAxisValueChangedObservable.add((value) => {
- if (Math.abs(value.x) > .1) {
- this.rig.turn(value.x);
- } else {
- this.rig.turn(0);
- }
-
- if (Math.abs(value.y) > .1) {
- this.rig.forwardback(value.y * this.speedFactor);
- Base.stickVector.z = 1;
- } else {
- Base.stickVector.z = 0;
- }
- if (Base.stickVector.equals(Vector3.Zero())) {
- this.rig.forwardback(0);
- }
- });
- }
+ this.initTrigger(init.components['xr-standard-trigger']);
+ this.initBButton(init.components['b-button']);
+ this.initAButton(init.components['a-button']);
+ this.initThumbstick(init.components['xr-standard-thumbstick']);
+ this.initGrip(init.components['xr-standard-squeeze']);
});
}
+ private initGrip(grip: WebXRControllerComponent) {
+ grip.onButtonStateChangedObservable.add((value) => {
+ if (value.value > .5) {
+ if (this.controller.pointer.collider.collidedMesh) {
+ console.log(this.controller.pointer.collider.collidedMesh.id);
+ }
+ }
+ });
+ }
public setBMenu(menu: Bmenu) {
this.bmenu = menu;
this.bmenu.setController(this.controller);
}
+ private rotateMovable(value: { x: number; y: number }) {
+ if (Math.abs(value.y) > .1) {
+ Controllers.movable.rotation.x +=
+ Angle.FromDegrees(Math.sign(value.y) * 1).radians();
+ Controllers.movable.rotation.x = this.fixRadians(Controllers.movable.rotation.x);
+ }
+ if (Math.abs(value.x) > .1) {
+ Controllers.movable.rotation.z +=
+ Angle.FromDegrees(Math.sign(value.x) * 1).radians();
+ Controllers.movable.rotation.z = this.fixRadians(Controllers.movable.rotation.z);
+ }
+ }
+ private fixRadians(value: number) {
+ if (value > 2 * Math.PI) {
+ return value - 2 * Math.PI;
+ } else {
+ return value;
+ }
+ }
+ private moveMovable(value: { x: number; y: number }) {
+ if (Math.abs(value.y) > .1) {
+ Controllers.movable.position.z += Math.sign(value.y) * -.005;
+ }
+ if (Math.abs(value.x) > .1) {
+ Controllers.movable.position.x += Math.sign(value.x) * .005;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/controllers/rigplatform.ts b/src/controllers/rigplatform.ts
index 1f4aeec..fd85c98 100644
--- a/src/controllers/rigplatform.ts
+++ b/src/controllers/rigplatform.ts
@@ -17,33 +17,36 @@ import {
import {Right} from "./right";
import {Left} from "./left";
import {Bmenu} from "../menus/bmenu";
+import {Hud} from "../information/hud";
+import {Controllers} from "./controllers";
+
export class Rigplatform {
static LINEAR_VELOCITY = 4;
static ANGULAR_VELOCITY = 3;
static x90 = Quaternion.RotationAxis(Vector3.Up(), 1.5708);
public bMenu: Bmenu;
+ private scene: Scene;
+ public static instance: Rigplatform;
+ private static xr: WebXRDefaultExperience;
private yRotation: number = 0;
- public right: Right;
- public left: Left;
public body: PhysicsBody;
public rigMesh: Mesh;
private camera: Camera;
- private scene: Scene;
- private xr: WebXRDefaultExperience;
private turning: boolean = false;
constructor(scene: Scene, xr: WebXRDefaultExperience) {
- this.xr = xr;
- this.bMenu = new Bmenu(scene, this.xr.baseExperience);
- this.camera = scene.activeCamera;
-
this.scene = scene;
+ Rigplatform.xr = xr;
+ Rigplatform.instance = this;
- this.rigMesh = MeshBuilder.CreateCylinder("platform", {diameter: 1.5, height: .01}, scene);
-
- for (const cam of this.scene.cameras) {
+ this.bMenu = new Bmenu(scene, xr.baseExperience);
+ this.camera = scene.activeCamera;
+ this.rigMesh = MeshBuilder.CreateBox("platform", {width: 2, height: .02, depth: 2}, scene);
+ const hud = new Hud(this.rigMesh, scene);
+ for (const cam of scene.cameras) {
cam.parent = this.rigMesh;
+ cam.position = new Vector3(0, 1.6, 0);
}
const myMaterial = new StandardMaterial("myMaterial", scene);
@@ -55,31 +58,28 @@ export class Rigplatform {
new PhysicsAggregate(
this.rigMesh,
PhysicsShapeType.CYLINDER,
- {friction: 1, center: Vector3.Zero(), radius: .5, mass: .1, restitution: .1},
+ {friction: 1, center: Vector3.Zero(), radius: .5, mass: 10, restitution: .01},
scene);
- rigAggregate.body.setMotionType(PhysicsMotionType.ANIMATED);
- rigAggregate.body.setGravityFactor(0);
+ rigAggregate.body.setMotionType(PhysicsMotionType.DYNAMIC);
+ rigAggregate.body.setGravityFactor(.001);
+
this.#fixRotation();
this.body = rigAggregate.body;
this.#setupKeyboard();
this.#initializeControllers();
- this.scene.onActiveCameraChanged.add((s) => {
+ scene.onActiveCameraChanged.add((s) => {
this.camera = s.activeCamera;
this.camera.parent = this.rigMesh;
- console.log('camera changed');
});
}
public forwardback(val: number) {
const ray = this.camera.getForwardRay();
-
this.body.setLinearVelocity(ray.direction.scale(val * -1));
}
public leftright(val: number) {
-
-
const ray = this.camera.getForwardRay();
const direction = ray.direction.applyRotationQuaternion(Rigplatform.x90).scale(val);
this.body.setLinearVelocity(direction);
@@ -125,28 +125,46 @@ export class Rigplatform {
}
#initializeControllers() {
- this.xr.input.onControllerAddedObservable.add((source, state) => {
+ Rigplatform.xr.input.onControllerAddedObservable.add((source) => {
let controller;
switch (source.inputSource.handedness) {
case "right":
- controller = new Right(source);
- this.right = controller;
- controller.setBMenu(this.bMenu);
+ Right.instance = new Right(source);
+ Right.instance.setBMenu(this.bMenu);
+ Controllers.controllerObserver.add((event: { type: string, value: number }) => {
+ switch (event.type) {
+ case "turn":
+ this.turn(event.value);
+ break;
+ case "forwardback":
+ this.forwardback(event.value);
+ break;
+ case "leftright":
+ this.leftright(event.value);
+ break;
+ case "updown":
+ this.updown(event.value);
+ break;
+ case "stop":
+ this.stop();
+ break;
+
+ }
+
+ });
break;
case "left":
- controller = new Left(source);
- this.left = controller;
+ Left.instance = new Left(source);
break;
}
- this.xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
+ Rigplatform.xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
if (controller) {
controller.setRig(this);
}
-
- console.log(source);
- console.log(state);
});
+
+
}
//create a method to set the camera to the rig
@@ -181,7 +199,7 @@ export class Rigplatform {
this.updown(1 * Rigplatform.LINEAR_VELOCITY);
break;
case " ":
- this.bMenu.toggle()
+ this.bMenu.toggle(this.rigMesh)
}
});
@@ -197,6 +215,7 @@ export class Rigplatform {
#fixRotation() {
this.scene.registerBeforeRender(() => {
const q = this.rigMesh.rotationQuaternion;
+ this.body.setAngularVelocity(Vector3.Zero());
const e = q.toEulerAngles();
e.y += this.yRotation;
q.copyFrom(Quaternion.FromEulerAngles(0, e.y, 0));
diff --git a/src/diagram/diagramEntity.ts b/src/diagram/diagramEntity.ts
index 139597f..a794dcf 100644
--- a/src/diagram/diagramEntity.ts
+++ b/src/diagram/diagramEntity.ts
@@ -1,2 +1,31 @@
+import {Vector3} from "@babylonjs/core";
+import {BmenuState} from "../menus/MenuState";
+export enum DiagramEventType {
+ ADD,
+ REMOVE,
+ MODIFY,
+ DROP,
+ DROPPED,
+ CLEAR,
+
+
+}
+export type DiagramEvent = {
+ type: DiagramEventType;
+ menustate?: BmenuState;
+ entity?: DiagramEntity;
+
+}
+export type DiagramEntity = {
+ color?: string;
+ id?: string;
+ last_seen?: Date;
+ position?: Vector3;
+ rotation?: Vector3;
+ template?: string;
+ text?: string;
+ scale?: Vector3;
+ parent?: string;
+}
diff --git a/src/diagram/diagramManager.ts b/src/diagram/diagramManager.ts
index 1d6d444..ec0f633 100644
--- a/src/diagram/diagramManager.ts
+++ b/src/diagram/diagramManager.ts
@@ -1,77 +1,70 @@
-import {AbstractMesh, Color3, Mesh, MeshBuilder, Observable, Scene, StandardMaterial, Vector3} from "@babylonjs/core";
+import {
+ AbstractMesh,
+ Angle,
+ Color3,
+ Mesh,
+ MeshBuilder,
+ Observable, Scene,
+ StandardMaterial,
+ Vector3, WebXRExperienceHelper
+} from "@babylonjs/core";
import {v4 as uuidv4} from 'uuid';
-import {BmenuState} from "../menus/bmenu";
-
-
-export enum DiagramEventType {
- ADD,
- REMOVE,
- MODIFY,
- DROP,
- DROPPED,
-
-
-}
-
-export type DiagramEvent = {
- type: DiagramEventType;
- menustate?: BmenuState;
- entity?: DiagramEntity;
-
-}
-
-export type DiagramEntity = {
- color?: string;
- id?: string;
- last_seen?: Date;
- position?: Vector3;
- rotation?: Vector3;
- template?: string;
- text?: string;
- scale?: Vector3;
- parent?: string;
-}
+import {DiagramEntity, DiagramEvent, DiagramEventType} from "./diagramEntity";
+import {PersistenceManager} from "./persistenceManager";
export class DiagramManager {
+ private persistenceManager: PersistenceManager = new PersistenceManager();
static onDiagramEventObservable = new Observable();
- static leftController: Mesh;
+ private scene: Scene;
+ private xr: WebXRExperienceHelper;
static currentMesh: AbstractMesh;
- static rightController: Mesh;
- static state: BmenuState;
- private readonly scene: Scene;
- constructor(scene: Scene) {
+ constructor(scene: Scene, xr: WebXRExperienceHelper) {
this.scene = scene;
+ this.xr = xr;
+ this.persistenceManager.updateObserver.add(this.#onRemoteEvent, -1, true, this);
+ this.persistenceManager.initialize();
+ if (!DiagramManager.onDiagramEventObservable) {
+ DiagramManager.onDiagramEventObservable = new Observable();
+ }
if (DiagramManager.onDiagramEventObservable.hasObservers()) {
} else {
DiagramManager.onDiagramEventObservable.add(this.#onDiagramEvent, -1, true, this);
}
}
+ #onRemoteEvent(event: DiagramEntity) {
+ const mesh = this.#createMesh(event);
+ const material = new StandardMaterial("material-" + event.id, this.scene);
+ material.diffuseColor = Color3.FromHexString(event.color);
+ mesh.material = material;
+ }
#onDiagramEvent(event: DiagramEvent) {
- console.log(event);
const entity = event.entity;
-
let mesh;
-
let material
if (entity) {
mesh = this.scene.getMeshByName(entity.id);
- material = this.scene.getMaterialByName("material-" + entity.id);
- if (!material) {
- material = new StandardMaterial("material-" + event.entity.id, this.scene);
- material.ambientColor = Color3.FromHexString(event.entity.color.replace("#", ""));
+ if (mesh) {
+ material = mesh.material;
}
}
-
switch (event.type) {
+ case DiagramEventType.CLEAR:
+ DiagramManager.currentMesh.dispose();
+ DiagramManager.currentMesh = null;
+ break;
case DiagramEventType.DROPPED:
break;
case DiagramEventType.DROP:
if (DiagramManager.currentMesh) {
- const newMesh = DiagramManager.currentMesh.clone(DiagramManager.currentMesh.name = "id" + uuidv4(), DiagramManager.currentMesh.parent);
+ this.persistenceManager.add(DiagramManager.currentMesh);
+ const newName = uuidv4();
+ const newMesh = DiagramManager.currentMesh.clone("id"+newName, DiagramManager.currentMesh.parent);
+ const newMaterial = DiagramManager.currentMesh.material.clone("material"+newName);
+ newMesh.material=newMaterial;
DiagramManager.currentMesh.setParent(null);
DiagramManager.currentMesh = newMesh;
DiagramManager.onDiagramEventObservable.notifyObservers({
@@ -81,44 +74,51 @@ export class DiagramManager {
}
break;
case DiagramEventType.ADD:
- if (DiagramManager.currentMesh){
+ if (DiagramManager.currentMesh) {
DiagramManager.currentMesh.dispose();
}
-
if (mesh) {
return;
} else {
mesh = this.#createMesh(entity);
+ if (!material) {
+ material = new StandardMaterial("material-" + event.entity.id, this.scene);
+ material.diffuseColor = Color3.FromHexString(event.entity.color);
+ mesh.material = material;
+
+ }
if (!mesh) {
return;
}
-
}
-
+ DiagramManager.currentMesh = mesh;
+ break;
case DiagramEventType.MODIFY:
if (!mesh) {
} else {
- const rotation = entity.rotation;
- const scale = entity.scale;
- const position = entity.position;
+ if (!material) {
+ material = new StandardMaterial("material-" + event.entity.id, this.scene);
+ material.diffuseColor = Color3.FromHexString(event.entity.color);
+ if (mesh) {
+ mesh.material = material;
+ }
+ }
mesh.material = material;
- mesh.position = new Vector3(position.x, position.y, position.z);
- mesh.rotation = new Vector3(rotation.x, rotation.y, rotation.z);
-
+ mesh.position = entity.position;
+ mesh.rotation = entity.rotation;
if (entity.parent) {
mesh.parent = this.scene.getMeshByName(entity.parent);
+ } else {
+
}
}
DiagramManager.currentMesh = mesh;
break;
case DiagramEventType.REMOVE:
break;
-
-
}
-
}
#createMesh(entity: DiagramEntity) {
@@ -130,28 +130,41 @@ export class DiagramManager {
case "#box-template":
mesh = MeshBuilder.CreateBox(entity.id,
{
- width: entity.scale.x,
- height: entity.scale.y,
- depth: entity.scale.z
+ width: 1,
+ height: 1,
+ depth: 1
}, this.scene);
+
break;
-
case "#sphere-template":
-
- mesh = MeshBuilder.CreateSphere(entity.id, {diameter: entity.scale.x}, this.scene);
+ mesh = MeshBuilder.CreateSphere(entity.id, {diameter: 1}, this.scene);
break
case "#cylinder-template":
mesh = MeshBuilder.CreateCylinder(entity.id, {
- diameter: entity.scale.x,
- height: entity.scale.y
+ diameter: 1,
+ height: 1
}, this.scene);
break;
default:
mesh = null;
}
+ if (mesh) {
+ mesh.metadata = {template: entity.template};
+
+ if (entity.position) {
+ mesh.position = entity.position;
+ }
+ if (entity.rotation) {
+ mesh.rotation = entity.rotation;
+ }
+ if (entity.parent) {
+ mesh.parent = this.scene.getMeshByName(entity.parent);
+ }
+ if (entity.scale) {
+ mesh.scaling = entity.scale;
+ }
+ }
+
return mesh;
}
-
-}
-
-
+}
\ No newline at end of file
diff --git a/src/diagram/persistenceManager.ts b/src/diagram/persistenceManager.ts
new file mode 100644
index 0000000..52a3c02
--- /dev/null
+++ b/src/diagram/persistenceManager.ts
@@ -0,0 +1,48 @@
+import {AbstractMesh, Mesh, Observable, StandardMaterial, Vector3} from "@babylonjs/core";
+import {DiagramEntity} from "./diagramEntity";
+
+export class PersistenceManager {
+ public updateObserver: Observable = new Observable();
+
+ constructor() {
+
+ }
+ public add(mesh: AbstractMesh) {
+ const entity = {};
+ entity.id = mesh.id;
+ entity.position = mesh.position.toString();
+ entity.rotation = mesh.rotation.toString();
+ entity.last_seen = new Date().getDate();
+ entity.template = "default";
+ entity.text = "";
+ entity.scale = mesh.scaling.toString();
+ if (mesh.material) {
+ entity.color = (mesh.material as StandardMaterial).diffuseColor.toHexString();
+ }
+
+ console.log(entity);
+ }
+
+ public remove() {
+
+ }
+ public modify() {
+
+ }
+ public initialize() {
+ const entity: DiagramEntity = {};
+ entity.id = "test";
+ entity.position = new Vector3(0,2,-2);
+ entity.rotation = Vector3.Zero();
+ entity.last_seen = new Date();
+ entity.scale = Vector3.One();
+ entity.color = "#ff0000";
+ entity.text = "test";
+ entity.parent = null;
+ entity.template = "#box-template";
+
+ this.updateObserver.notifyObservers(entity);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/information/hud.ts b/src/information/hud.ts
new file mode 100644
index 0000000..74f4fac
--- /dev/null
+++ b/src/information/hud.ts
@@ -0,0 +1,56 @@
+import {AbstractMesh, Color3, MeshBuilder, Scene, Vector3} from "@babylonjs/core";
+import {AdvancedDynamicTexture, StackPanel, TextBlock} from "@babylonjs/gui";
+import {Controllers} from "../controllers/controllers";
+
+export class Hud {
+ private scene: Scene;
+ private parent: AbstractMesh;
+ private hudPlane: AbstractMesh;
+ constructor(parent: AbstractMesh, scene: Scene) {
+ this.scene = scene;
+ this.parent = parent;
+ this.hudPlane = MeshBuilder.CreatePlane("hudPlane", {width: 1, height: .5}, this.parent.getScene());
+ this.hudPlane.parent=this.parent.getScene().activeCamera
+ this.parent.getScene().onActiveCameraChanged.add((scene) => {
+ this.hudPlane.parent = scene.activeCamera;
+ });
+ this.hudPlane.position = new Vector3(.5, .75, 3);
+
+ this.hudPlane.outlineColor = Color3.FromHexString("#ffffff");
+
+
+ const textPosition = this.createTextBlock();
+ const textRotation = this.createTextBlock();
+
+ const hudTexture = AdvancedDynamicTexture.CreateForMesh(this.hudPlane, 1024, 512);
+
+ hudTexture.background = "black";
+ const stackPanel = new StackPanel();
+ hudTexture.addControl(stackPanel);
+
+
+ stackPanel.addControl(textPosition);
+ stackPanel.addControl(textRotation);
+
+ this.scene.onBeforeRenderObservable.add(() => {
+ if (Controllers.movable) {
+ textPosition.text = 'position: '+ this.formatVector3(Controllers.movable.position);
+ textRotation.text = 'rotation: '+ this.formatVector3(Controllers.movable.rotation);
+ }
+ });
+ }
+ createTextBlock(): TextBlock {
+ const text = new TextBlock();
+ text.isHitTestVisible = false;
+ text.text = "";
+ text.height="20%";
+ text.resizeToFit=true;
+
+ text.color="white";
+ text.fontSize = 64;
+ return text;
+ }
+ private formatVector3(v: Vector3): string {
+ return `(${v.x.toFixed(2)},${v.y.toFixed(2)},${v.z.toFixed(2)})`;
+ }
+}
diff --git a/src/menus/MenuState.ts b/src/menus/MenuState.ts
new file mode 100644
index 0000000..125c074
--- /dev/null
+++ b/src/menus/MenuState.ts
@@ -0,0 +1,6 @@
+export enum BmenuState {
+ NONE,
+ ADDING, // Adding a new entity
+ DROPPING, // Dropping an entity
+
+}
\ No newline at end of file
diff --git a/src/menus/bmenu.ts b/src/menus/bmenu.ts
index 01e83b8..e9cf293 100644
--- a/src/menus/bmenu.ts
+++ b/src/menus/bmenu.ts
@@ -1,43 +1,36 @@
import {
AbstractMesh,
- Angle,
Color3,
Scene,
StandardMaterial,
- TransformNode,
Vector3,
WebXRExperienceHelper,
WebXRInputSource
} from "@babylonjs/core";
-import {GUI3DManager, HolographicButton, PlanePanel} from "@babylonjs/gui";
-import {DiagramEntity, DiagramEvent, DiagramEventType, DiagramManager} from "../diagram/diagramManager";
+import {GUI3DManager, NearMenu, TouchHolographicButton} from "@babylonjs/gui";
+import {DiagramManager} from "../diagram/diagramManager";
+import {BmenuState} from "./MenuState";
+import {DiagramEntity, DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
-export enum BmenuState {
- NONE,
- ADDING, // Adding a new entity
- DROPPING, // Dropping an entity
-
-}
export class Bmenu {
- private readonly scene;
private state: BmenuState = BmenuState.NONE;
+ private manager: GUI3DManager;
+ private scene: Scene;
- private xr;
- private manager;
- private panel;
private rightController: AbstractMesh;
+ private xr: WebXRExperienceHelper;
constructor(scene: Scene, xr: WebXRExperienceHelper) {
this.scene = scene;
- this.manager = new GUI3DManager(scene);
-
this.xr = xr;
+
DiagramManager.onDiagramEventObservable.add((event: DiagramEvent) => {
if (event.type === DiagramEventType.DROPPED) {
this.state = BmenuState.ADDING;
}
});
+
}
setController(controller: WebXRInputSource) {
@@ -45,7 +38,7 @@ export class Bmenu {
}
makeButton(name: string, id: string) {
- const button = new HolographicButton(name);
+ const button = new TouchHolographicButton(name);
button.text = name;
button.name = id;
button.onPointerClickObservable.add(this.#clickhandler, -1, false, this);
@@ -59,76 +52,94 @@ export class Bmenu {
public setState(state: BmenuState) {
this.state = state;
}
-
- toggle() {
- if (this.panel) {
- this.panel.dispose();
- this.panel = null;
-
+ toggle(mesh: AbstractMesh) {
+ console.log(mesh.name);
+ if (this.manager) {
+ this.manager.dispose();
+ this.manager = null;
} else {
- const anchor = new TransformNode("bMenuAnchor");
- anchor.rotation.y = Angle.FromDegrees(180).radians();
- const cam = this.xr.camera.getFrontPosition(1);
- cam.y = cam.y - .5;
- anchor.position = cam;
- const panel = new PlanePanel();
- panel.margin = .06;
+ this.manager = new GUI3DManager(this.scene);
+ const panel = new NearMenu();
this.manager.addControl(panel);
- panel.linkToTransformNode(anchor);
- panel.addControl(this.makeButton("Add Box", "addBox"));
- panel.addControl(this.makeButton("Add Sphere", "addSphere"));
- panel.addControl(this.makeButton("Add Cylinder", "addCylinder"));
- panel.addControl(this.makeButton("Done Adding", "doneAdding"));
- for (const control of panel.children) {
- control.scaling = new Vector3(.1, .1, .1);
- }
- this.panel = panel;
- }
+ const follower = panel.defaultBehavior.followBehavior;
+ follower.maxViewHorizontalDegrees = 45;
+ follower.useFixedVerticalOffset = true;
+ follower.fixedVerticalOffset = 1;
+ follower.defaultDistance = 2;
+ follower.maximumDistance = 3;
+ follower.minimumDistance = 1;
+ panel.backPlateMargin = .01;
+ panel.scaling= new Vector3(.5, .5, .1);
+ panel.margin = .01;
+ //panel.scaling.x = .5;
+ //panel.scaling.y = .5;
+ //const camdir = panel.mesh.getDirection(this.xr.camera.globalPosition);
+ //panel.mesh.lookAt(this.xr.camera.globalPosition);
+ panel.addButton(this.makeButton("Add Box", "addBox"));
+ panel.addButton(this.makeButton("Add Sphere", "addSphere"));
+ panel.addButton(this.makeButton("Add Cylinder", "addCylinder"));
+ panel.addButton(this.makeButton("Done Adding", "doneAdding"));
+ this.manager.controlScaling = .5;
+
+ }
}
#clickhandler(_info, state) {
console.log(state.currentTarget.name);
+ const id = this?.rightController?.id || null;
let entity: DiagramEntity = {
template: null,
- position: new Vector3(0, -.040, .13),
- rotation: new Vector3(),
+ position: new Vector3(-.01, -.1, .14),
+ rotation: new Vector3(76.04, 0, 0),
scale: new Vector3(.1, .1, .1),
- color: "#CEE",
+ color: "#CC0000",
text: "test",
last_seen: new Date(),
- parent: this.rightController.id
-
+ parent: id
};
switch (state.currentTarget.name) {
case "addBox":
entity.template = "#box-template";
+ this.state = BmenuState.ADDING;
break;
case "addSphere":
entity.template = "#sphere-template";
+ this.state = BmenuState.ADDING;
break;
case "addCylinder":
entity.template = "#cylinder-template";
+ this.state = BmenuState.ADDING;
break;
case "doneAdding":
this.state = BmenuState.NONE;
+
break;
default:
console.log("Unknown button");
return;
}
- const event: DiagramEvent = {
- type: DiagramEventType.ADD,
- entity: entity
+ if (this.state === BmenuState.ADDING) {
+ const event: DiagramEvent = {
+ type: DiagramEventType.ADD,
+ entity: entity
+ }
+ DiagramManager.onDiagramEventObservable.notifyObservers(event);
+ } else {
+ const event: DiagramEvent = {
+ type: DiagramEventType.CLEAR
+ }
+ DiagramManager.onDiagramEventObservable.notifyObservers(event);
}
- this.state = BmenuState.ADDING;
- DiagramManager.onDiagramEventObservable.notifyObservers(event);
+
+
+
}
#createDefaultMaterial() {
- const myMaterial = new StandardMaterial("myMaterial", this.scene);
+ const myMaterial = new StandardMaterial("myMaterial", this.scene);
myMaterial.diffuseColor = Color3.FromHexString("#CEE");
return myMaterial;
}