Added Initial Config Menu.

This commit is contained in:
Michael Mainguy 2023-07-27 15:43:34 -05:00
parent 06b2989f3a
commit 9d5cb0ab95
13 changed files with 169 additions and 59 deletions

View File

@ -23,7 +23,7 @@ import HavokPhysics from "@babylonjs/havok";
import {Rigplatform} from "./controllers/rigplatform"; import {Rigplatform} from "./controllers/rigplatform";
import {DiagramManager} from "./diagram/diagramManager"; import {DiagramManager} from "./diagram/diagramManager";
import {Toolbox} from "./toolbox/toolbox"; import {Toolbox} from "./toolbox/toolbox";
import {DualshockEventMapper} from "./util/DualshockEventMapper"; import {DualshockEventMapper} from "./util/dualshockEventMapper";
import log from "loglevel"; import log from "loglevel";

View File

@ -24,6 +24,7 @@ export class Base {
protected previousRotation: Vector3 = null; protected previousRotation: Vector3 = null;
protected previousScaling: Vector3 = null; protected previousScaling: Vector3 = null;
protected previousPosition: Vector3 = null; protected previousPosition: Vector3 = null;
protected readonly xr: WebXRDefaultExperience; protected readonly xr: WebXRDefaultExperience;
constructor(controller: WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience) { constructor(controller: WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience) {
@ -42,18 +43,30 @@ export class Base {
this.initGrip(init.components['xr-standard-squeeze']); this.initGrip(init.components['xr-standard-squeeze']);
}); });
} }
public disable() {
this.controller.motionController.rootMesh.setEnabled(false);
this.controller.pointer.setEnabled(false);
}
public enable() {
this.controller.motionController.rootMesh.setEnabled(true);
this.controller.pointer.setEnabled(true);
}
private createCopy(mesh: AbstractMesh) { private createCopy(mesh: AbstractMesh) {
if (!mesh.isAnInstance) { if (!mesh.isAnInstance) {
return new InstancedMesh("new", (mesh as Mesh)); return new InstancedMesh("new", (mesh as Mesh));
} else { } else {
return new InstancedMesh("new", (mesh as InstancedMesh).sourceMesh); return new InstancedMesh("new", (mesh as InstancedMesh).sourceMesh);
} }
} }
private initGrip(grip: WebXRControllerComponent) { private initGrip(grip: WebXRControllerComponent) {
grip.onButtonStateChangedObservable.add(() => { grip.onButtonStateChangedObservable.add(() => {
if (grip.changes.pressed) { if (grip.changes.pressed) {
if (grip.pressed){ if (grip.pressed) {
let mesh = this.scene.meshUnderPointer; let mesh = this.scene.meshUnderPointer;
if (this.xr.pointerSelection.getMeshUnderPointer) { if (this.xr.pointerSelection.getMeshUnderPointer) {
mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId); mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);

View File

@ -1,7 +1,9 @@
import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core"; import {AbstractMesh, Observable, TransformNode} from "@babylonjs/core";
export type ControllerEventType = {
type: string
}
export class Controllers { export class Controllers {
public static movable: TransformNode | AbstractMesh; public static movable: TransformNode | AbstractMesh;
public static controllerObserver = new Observable(); public static controllerObserver: Observable<ControllerEventType> = new Observable();
} }

View File

@ -1,17 +1,18 @@
import {Scene, Vector3, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core"; import {Scene, Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
import {Base} from "./base"; import {Base} from "./base";
import {Controllers} from "./controllers"; import {Controllers} from "./controllers";
import log from "loglevel"; import log from "loglevel";
import {ConfigMenu} from "../menus/configMenu";
export class Left extends Base { export class Left extends Base {
public static instance: Left; public static instance: Left;
public configMenu: ConfigMenu;
constructor(controller: constructor(controller:
WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience) { WebXRInputSource, scene: Scene, xr: WebXRDefaultExperience) {
super(controller, scene, xr); super(controller, scene, xr);
this.configMenu = new ConfigMenu(this.scene, xr.baseExperience);
Left.instance = this; Left.instance = this;
this.controller.onMotionControllerInitObservable.add((init) => { this.controller.onMotionControllerInitObservable.add((init) => {
if (init.components['xr-standard-thumbstick']) { if (init.components['xr-standard-thumbstick']) {
@ -24,6 +25,8 @@ export class Left extends Base {
this.moveMovable(value); this.moveMovable(value);
} }
}); });
this.initXButton(init.components['x-button']);
this.initYButton(init.components['y-button']);
init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => { init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => {
if (value.pressed) { if (value.pressed) {
log.trace('Left', 'thumbstick changed'); log.trace('Left', 'thumbstick changed');
@ -35,6 +38,26 @@ export class Left extends Base {
} }
private initXButton(xbutton: WebXRControllerComponent) {
if (xbutton) {
xbutton.onButtonStateChangedObservable.add((button) => {
if (button.pressed) {
Controllers.controllerObserver.notifyObservers({type: 'x-button', value: button.value});
}
});
}
}
private initYButton(ybutton: WebXRControllerComponent) {
if (ybutton) {
ybutton.onButtonStateChangedObservable.add((button) => {
if (button.pressed) {
Controllers.controllerObserver.notifyObservers({type: 'y-button', value: button.value});
}
});
}
}
private moveMovable(value: { x: number, y: number }) { private moveMovable(value: { x: number, y: number }) {
if (Math.abs(value.x) > .1) { if (Math.abs(value.x) > .1) {
Controllers.movable.position.x += .005 * Math.sign(value.x); Controllers.movable.position.x += .005 * Math.sign(value.x);

View File

@ -1,11 +1,5 @@
import {Base} from "./base"; import {Base} from "./base";
import { import {Scene, Vector3, WebXRControllerComponent, WebXRDefaultExperience, WebXRInputSource} from "@babylonjs/core";
Scene,
Vector3,
WebXRControllerComponent,
WebXRDefaultExperience,
WebXRInputSource
} from "@babylonjs/core";
import {Controllers} from "./controllers"; import {Controllers} from "./controllers";
import log from "loglevel"; import log from "loglevel";
@ -22,8 +16,6 @@ export class Right extends Base {
this.initAButton(init.components['a-button']); this.initAButton(init.components['a-button']);
this.initThumbstick(init.components['xr-standard-thumbstick']); this.initThumbstick(init.components['xr-standard-thumbstick']);
}); });
} }
private initBButton(bbutton: WebXRControllerComponent) { private initBButton(bbutton: WebXRControllerComponent) {

View File

@ -16,16 +16,15 @@ import {
} from "@babylonjs/core"; } from "@babylonjs/core";
import {Right} from "./right"; import {Right} from "./right";
import {Left} from "./left"; import {Left} from "./left";
import {Bmenu} from "../menus/bmenu"; import {EditMenu} from "../menus/editMenu";
import {Controllers} from "./controllers"; import {Controllers} from "./controllers";
import log from "loglevel"; import log from "loglevel";
export class Rigplatform { export class Rigplatform {
private velocityIndex = 2; private velocityIndex = 2;
private readonly velocityArray = [0.01, 0.1, 1, 2, 5]; private readonly velocityArray = [0.01, 0.1, 1, 2, 5];
public bMenu: Bmenu; public bMenu: EditMenu;
private readonly scene: Scene; private readonly scene: Scene;
public static instance: Rigplatform; public static instance: Rigplatform;
private static xr: WebXRDefaultExperience; private static xr: WebXRDefaultExperience;
@ -41,8 +40,9 @@ export class Rigplatform {
this.scene = scene; this.scene = scene;
Rigplatform.xr = xr; Rigplatform.xr = xr;
Rigplatform.instance = this; Rigplatform.instance = this;
this.bMenu = new Bmenu(scene, xr.baseExperience); this.bMenu = new EditMenu(scene, xr.baseExperience);
this.camera = scene.activeCamera; this.camera = scene.activeCamera;
this.rigMesh = MeshBuilder.CreateBox("platform", {width: 2, height: .02, depth: 2}, scene); this.rigMesh = MeshBuilder.CreateBox("platform", {width: 2, height: .02, depth: 2}, scene);
for (const cam of scene.cameras) { for (const cam of scene.cameras) {
cam.parent = this.rigMesh; cam.parent = this.rigMesh;

View File

@ -1,11 +0,0 @@
export class Amenu {
private visible = false;
constructor() {
}
public toggle() {
this.visible = !this.visible;
}
}

68
src/menus/configMenu.ts Normal file
View File

@ -0,0 +1,68 @@
import {AdvancedDynamicTexture, RadioGroup, SelectionPanel} from "@babylonjs/gui";
import {AbstractMesh, Angle, MeshBuilder, Scene, WebXRExperienceHelper} from "@babylonjs/core";
import {CameraHelper} from "../util/cameraHelper";
import log from "loglevel";
import {AppConfig} from "../util/appConfig";
import {Controllers} from "../controllers/controllers";
export class ConfigMenu {
private readonly scene: Scene;
private readonly xr: WebXRExperienceHelper;
private configPlane: AbstractMesh = null;
constructor(scene: Scene, xr: WebXRExperienceHelper) {
this.scene = scene;
this.xr = xr;
Controllers.controllerObserver.add((event) => {
if (event.type == 'x-button') {
this.toggle();
}
});
}
public toggle() {
if (this.configPlane) {
this.configPlane.dispose();
this.configPlane = null;
return;
}
this.configPlane = MeshBuilder
.CreatePlane("gridSizePlane",
{
width: .25,
height: .5
}, this.scene);
const configTexture = AdvancedDynamicTexture.CreateForMesh(this.configPlane, 256, 512);
configTexture.background = "white";
const selectionPanel = new SelectionPanel("selectionPanel");
selectionPanel.fontSize = "24px";
selectionPanel.height = "100%";
configTexture.addControl(selectionPanel)
const radio1 = new RadioGroup("Rotation Snap");
radio1.addRadio("Off", this.rotateVal);
radio1.addRadio("22.5 degrees", this.rotateVal);
radio1.addRadio("45 degrees", this.rotateVal);
radio1.addRadio("90 degrees", this.rotateVal);
selectionPanel.addGroup(radio1);
const radio2 = new RadioGroup("Grid Snap");
radio2.addRadio("Off", this.gridVal);
radio2.addRadio("1 cm", this.gridVal);
radio2.addRadio("10 cm", this.gridVal);
radio2.addRadio("25 cm", this.gridVal);
selectionPanel.addGroup(radio1);
selectionPanel.addGroup(radio2);
this.configPlane.position = CameraHelper.getFrontPosition(2, this.scene);
this.configPlane.rotation.y = Angle.FromDegrees(180).radians();
}
private rotateVal(value) {
AppConfig.config.rotateSnap = AppConfig.config.rotateSnapArray[value];
log.debug("configMenu", "rotate Snap", value);
}
private gridVal(value) {
AppConfig.config.gridSnap = AppConfig.config.gridSnapArray[value];
log.debug("configMenu", "grid Snap", value);
}
}

View File

@ -14,8 +14,10 @@ import {DiagramEvent, DiagramEventType} from "../diagram/diagramEntity";
import {MeshConverter} from "../diagram/meshConverter"; import {MeshConverter} from "../diagram/meshConverter";
import log from "loglevel"; import log from "loglevel";
import {InputTextView} from "../information/inputTextView"; import {InputTextView} from "../information/inputTextView";
import {Right} from "../controllers/right";
import {Left} from "../controllers/left";
export class Bmenu { export class EditMenu {
private state: BmenuState = BmenuState.NONE; private state: BmenuState = BmenuState.NONE;
private manager: GUI3DManager; private manager: GUI3DManager;
private readonly scene: Scene; private readonly scene: Scene;
@ -102,6 +104,10 @@ export class Bmenu {
} else { } else {
textInput.value = ""; textInput.value = "";
} }
if (this.xr.sessionManager.inXRSession) {
Right.instance.disable();
Left.instance.disable();
}
textInput.focus(); textInput.focus();
if (navigator.userAgent.indexOf('Macintosh') > -1) { if (navigator.userAgent.indexOf('Macintosh') > -1) {
@ -128,6 +134,8 @@ export class Bmenu {
MeshConverter.updateTextNode(mesh, textInput.value); MeshConverter.updateTextNode(mesh, textInput.value);
this.persist(mesh, textInput.value); this.persist(mesh, textInput.value);
this.cleanup(); this.cleanup();
Right.instance.enable();
Left.instance.enable();
}); });
} }
this.textInput = textInput; this.textInput = textInput;

View File

@ -1,9 +1,13 @@
import { import {
AbstractMesh, Angle, AbstractMesh,
Color3, InstancedMesh, Mesh, Angle,
Color3,
InstancedMesh,
Mesh,
MeshBuilder, MeshBuilder,
Scene, Scene,
StandardMaterial, TransformNode, StandardMaterial,
TransformNode,
Vector3, Vector3,
WebXRExperienceHelper WebXRExperienceHelper
} from "@babylonjs/core"; } from "@babylonjs/core";
@ -80,8 +84,6 @@ export class Toolbox {
this.addPanel.position = new Vector3(0, 0, .5); this.addPanel.position = new Vector3(0, 0, .5);
addButton.onPointerClickObservable.add(() => { addButton.onPointerClickObservable.add(() => {
this.buildColor(Color3.Random()); this.buildColor(Color3.Random());
}); });
} }
@ -106,14 +108,16 @@ export class Toolbox {
newItem.position = new Vector3(this.calculatePosition(++i), .1, 0); newItem.position = new Vector3(this.calculatePosition(++i), .1, 0);
} }
} }
const myPlane = MeshBuilder const colorPickerPlane = MeshBuilder
.CreatePlane("myPlane", .CreatePlane("myPlane",
{width: Toolbox.WIDGET_SIZE, {
height: Toolbox.WIDGET_SIZE}, this.scene); width: Toolbox.WIDGET_SIZE,
myPlane.parent=mesh; height: Toolbox.WIDGET_SIZE
myPlane.position= new Vector3(this.calculatePosition(++i), .1, 0); }, this.scene);
colorPickerPlane.parent = mesh;
colorPickerPlane.position = new Vector3(this.calculatePosition(++i), .1, 0);
const advancedTexture2 = AdvancedDynamicTexture.CreateForMesh(myPlane, 1024, 1024); const colorPickerTexture = AdvancedDynamicTexture.CreateForMesh(colorPickerPlane, 1024, 1024);
const colorPicker = new ColorPicker("color-picker"); const colorPicker = new ColorPicker("color-picker");
colorPicker.scaleY = 5; colorPicker.scaleY = 5;
colorPicker.scaleX = 5; colorPicker.scaleX = 5;
@ -134,7 +138,7 @@ export class Toolbox {
); );
}); });
advancedTexture2.addControl(colorPicker); colorPickerTexture.addControl(colorPicker);
this.addPanel.position.z += .25; this.addPanel.position.z += .25;
this.node.position.z -= .125; this.node.position.z -= .125;
} }

19
src/util/appConfig.ts Normal file
View File

@ -0,0 +1,19 @@
export class AppConfig {
public gridSnap = 0;
public rotateSnap = 0;
public gridSnapArray =
[0, 0.1, 0.5, 1];
public rotateSnapArray =
[0, 22.5, 45, 90]
private static _config: AppConfig;
public static get config() {
if (!AppConfig._config) {
AppConfig._config = new AppConfig();
}
return AppConfig._config;
}
}

View File

@ -1,5 +1,6 @@
import {DualShockButton} from "@babylonjs/core"; import {DualShockButton} from "@babylonjs/core";
import log from "loglevel"; import log from "loglevel";
type ButtonEvent = { type ButtonEvent = {
objectName?: string, objectName?: string,
pressed: boolean, pressed: boolean,
@ -57,17 +58,18 @@ export class DualshockEventMapper {
log.debug('DualshockEventMapper','D-Pad Up'); log.debug('DualshockEventMapper','D-Pad Up');
break; break;
case 13: case 13:
log.debug('DualshockEventMapper','D-Pad Down'); log.debug('DualshockEventMapper', 'D-Pad Down');
buttonEvent.objectName = "left-controller"; buttonEvent.objectName = "left-controller";
buttonEvent.buttonIndex = 3; buttonEvent.buttonIndex = 3;
break; break;
case 14: case 14:
log.debug('DualshockEventMapper','D-Pad Left'); log.debug('DualshockEventMapper', 'D-Pad Left');
log.debug('DualshockEventMapper', 'D-Pad Left');
buttonEvent.objectName = "left-controller"; buttonEvent.objectName = "left-controller";
buttonEvent.buttonIndex = 4; buttonEvent.buttonIndex = 4;
break; break;
case 15: case 15:
log.debug('DualshockEventMapper','D-Pad Right'); log.debug('DualshockEventMapper', 'D-Pad Right');
break; break;
case 10: case 10:
log.debug('DualshockEventMapper','L3'); log.debug('DualshockEventMapper','L3');

View File

@ -1,10 +0,0 @@
import {PlanePanel} from "@babylonjs/gui";
export class MyMenu extends PlanePanel {
public arrangeChildren: boolean = true;
protected _arrangeChildren() {
if (this.arrangeChildren) {
super._arrangeChildren();
}
}
}