Fix connecter and controller bug.

This commit is contained in:
Michael Mainguy 2024-05-31 14:14:28 -05:00
parent fa8865d013
commit d8d91dd688
9 changed files with 96 additions and 135 deletions

View File

@ -61,7 +61,6 @@ export class Base {
this._meshUnderPointer = null; this._meshUnderPointer = null;
} }
} }
}); });
this.diagramManager = diagramManager; this.diagramManager = diagramManager;
@ -116,6 +115,7 @@ export class Base {
this.grabbedMesh = clone.mesh; this.grabbedMesh = clone.mesh;
this.grabbedMeshType = getMeshType(clone.mesh, this.diagramManager); this.grabbedMeshType = getMeshType(clone.mesh, this.diagramManager);
this._meshUnderPointer = clone.mesh; this._meshUnderPointer = clone.mesh;
clone.grabbed = true;
} }
}, 300, this); }, 300, this);
} }
@ -149,6 +149,7 @@ export class Base {
const diagramObject = this.diagramManager.getDiagramObject(mesh.id); const diagramObject = this.diagramManager.getDiagramObject(mesh.id);
if (diagramObject.isGrabbable) { if (diagramObject.isGrabbable) {
diagramObject.baseTransform.setParent(this.xrInputSource.motionController.rootMesh); diagramObject.baseTransform.setParent(this.xrInputSource.motionController.rootMesh);
diagramObject.grabbed = true;
this.grabbedObject = diagramObject; this.grabbedObject = diagramObject;
} }
break; break;
@ -159,6 +160,7 @@ export class Base {
const clone = grabAndClone(this.diagramManager, mesh, this.xrInputSource.motionController.rootMesh); const clone = grabAndClone(this.diagramManager, mesh, this.xrInputSource.motionController.rootMesh);
this.grabbedObject = clone; this.grabbedObject = clone;
this.grabbedMesh = clone.mesh; this.grabbedMesh = clone.mesh;
clone.grabbed = true;
} }
} }
@ -182,6 +184,7 @@ export class Base {
} }
this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL); this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
diagramObject.mesh.computeWorldMatrix(false); diagramObject.mesh.computeWorldMatrix(false);
diagramObject.grabbed = false;
} }
this.grabbedObject = null; this.grabbedObject = null;
@ -199,6 +202,7 @@ export class Base {
} }
this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL); this.diagramManager.onDiagramEventObservable.notifyObservers(event, DiagramEventObserverMask.ALL);
diagramObject.mesh.computeWorldMatrix(false); diagramObject.mesh.computeWorldMatrix(false);
this.grabbedObject.grabbed = false;
this.grabbedObject = null; this.grabbedObject = null;
this.grabbedMesh = null; this.grabbedMesh = null;
this.grabbedMeshType = null; this.grabbedMeshType = null;

View File

@ -27,7 +27,7 @@ export class InputTextView {
this.controllers = controllers; this.controllers = controllers;
this.scene = DefaultScene.Scene; this.scene = DefaultScene.Scene;
this.inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene); this.inputMesh = MeshBuilder.CreatePlane("input", {width: 1, height: .5}, this.scene);
this.handle = new Handle(this.inputMesh); this.handle = new Handle(this.inputMesh, 'Input');
this.inputMesh.position.y = .06; this.inputMesh.position.y = .06;
this.inputMesh.position.z = .02; this.inputMesh.position.z = .02;
this.createKeyboard(); this.createKeyboard();

View File

@ -1,4 +1,4 @@
import {Scene, TransformNode, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {Scene, WebXRDefaultExperience} from "@babylonjs/core";
import {Controllers} from "../controllers/controllers"; import {Controllers} from "../controllers/controllers";
import {Handle} from "../objects/handle"; import {Handle} from "../objects/handle";
import {DefaultScene} from "../defaultScene"; import {DefaultScene} from "../defaultScene";
@ -15,9 +15,6 @@ export abstract class AbstractMenu {
this.controllers = controllers; this.controllers = controllers;
} }
protected createHandle(mesh: TransformNode, offset: Vector3, rotation: Vector3) {
this.handle = new Handle(mesh, offset, rotation);
}
public toggle() { public toggle() {
throw new Error("AbstractMenu.toggle() not implemented"); throw new Error("AbstractMenu.toggle() not implemented");
} }

View File

@ -30,7 +30,7 @@ export class ConfigMenu {
this._scene = DefaultScene.Scene; this._scene = DefaultScene.Scene;
this.baseTransform = new TransformNode("configMenuBase", this._scene); this.baseTransform = new TransformNode("configMenuBase", this._scene);
this._handle = new Handle(this.baseTransform); this._handle = new Handle(this.baseTransform, 'Configuration');
this.config = config; this.config = config;
this.buildMenu(); this.buildMenu();
} }

View File

@ -30,9 +30,10 @@ export class DiagramObject {
private _observingStart: number; private _observingStart: number;
private _sceneObserver: Observer<Scene>; private _sceneObserver: Observer<Scene>;
private _eventObservable: Observable<DiagramEvent>; private _eventObservable: Observable<DiagramEvent>;
private _mesh: AbstractMesh; private _mesh: AbstractMesh;
private _label: AbstractMesh; private _label: AbstractMesh;
public grabbed: boolean = false;
public get mesh(): AbstractMesh { public get mesh(): AbstractMesh {
return this._mesh; return this._mesh;
} }

View File

@ -1,105 +1,59 @@
import {AbstractMesh, InstancedMesh, Mesh, Scene, TransformNode, Vector3} from "@babylonjs/core"; import {AbstractMesh, Scene, TransformNode, Vector3} from "@babylonjs/core";
import {HtmlMeshBuilder} from "babylon-html"; import {HtmlMeshBuilder} from "babylon-html";
import log, {Logger} from "loglevel";
export class Handle { export class Handle {
public mesh: AbstractMesh; public mesh: AbstractMesh;
private readonly menuItem: TransformNode; private readonly _menuItem: TransformNode;
private _isStored: boolean = false; private _isStored: boolean = false;
private offset: Vector3; private _offset: Vector3;
private rotation: Vector3; private _rotation: Vector3;
private readonly _label: string;
private readonly _logger: Logger = log.getLogger('Handle');
constructor(mesh: TransformNode, offset: Vector3 = Vector3.Zero(), rotation: Vector3 = Vector3.Zero()) { constructor(mesh: TransformNode, label: string = 'Handle', offset: Vector3 = Vector3.Zero(), rotation: Vector3 = Vector3.Zero()) {
this.menuItem = mesh; this._menuItem = mesh;
this.offset = offset; this._offset = offset;
this.rotation = rotation; this._rotation = rotation;
this._label = label;
this._logger.debug('Handle created with label ' + label);
this.buildHandle(); this.buildHandle();
} }
public get idStored() { public get idStored() {
return this._isStored; return this._isStored;
} }
private buildHandle() { private buildHandle() {
const scene: Scene = this.menuItem.getScene(); const scene: Scene = this._menuItem.getScene();
const handle = getHandleMesh("handle-" + this.menuItem.id + "-mesh", scene); const handle = HtmlMeshBuilder.CreatePlaneSync('handle-' + this._menuItem.id, {
if (this.menuItem) { html:
this.menuItem.setParent(handle); `<div style="width: 100%; height: 100%; border-radius: 32px; background-color: #111122; color: #eeeeee"><center>${this._label}</center></div>
`, width: .5, height: .1, image: {width: 256, height: 51}
}, scene);
handle.id = 'handle-' + this._menuItem.id;
if (this._menuItem) {
this._menuItem.setParent(handle);
} }
const stored = localStorage.getItem(handle.id); const stored = localStorage.getItem(handle.id);
if (stored) { if (stored) {
this._logger.debug('Stored location found for ' + handle.id);
try { try {
const locationdata = JSON.parse(stored); const locationdata = JSON.parse(stored);
this._logger.debug('Stored location data found ', locationdata);
handle.position = new Vector3(locationdata.position.x, locationdata.position.y, locationdata.position.z); handle.position = new Vector3(locationdata.position.x, locationdata.position.y, locationdata.position.z);
handle.rotation = new Vector3(locationdata.rotation.x, locationdata.rotation.y, locationdata.rotation.z); handle.rotation = new Vector3(locationdata._rotation.x, locationdata._rotation.y, locationdata._rotation.z);
this._isStored = true; this._isStored = true;
} catch (e) { } catch (e) {
console.error(e); this._logger.error(e);
handle.position = Vector3.Zero(); handle.position = Vector3.Zero();
} }
} else { } else {
handle.position = this.offset; handle.position = this._offset;
handle.rotation = this.rotation; handle.rotation = this._rotation;
``
} }
handle.metadata = {handle: true}; handle.metadata = {handle: true};
this.mesh = handle; this.mesh = handle;
} }
private setPlatformParent() {
const platform = this.menuItem.getScene().getNodeById("platform");
if (platform) {
this.mesh.parent = platform;
/*if (handle.mesh.position.x != 0 && handle.mesh.position.y != 0 && handle.mesh.position.z != 0) {
offset = handle.mesh.position;
}
if (handle.mesh.rotation.x != 0 && handle.mesh.rotation.y != 0 && handle.mesh.rotation.z != 0) {
rotation = handle.mesh.rotation;
}*/
//handle.mesh.parent = platform;
if (!this._isStored) {
this.mesh.position = this.offset;
this.mesh.rotation = this.rotation;
}
} else {
this.menuItem.getScene().onNewMeshAddedObservable.add((mesh: AbstractMesh) => {
if (mesh && mesh.id == "platform") {
//const handle = this.handle;
this.menuItem.parent = mesh;
if (!this._isStored) {
this.mesh.position = this.offset;
this.mesh.rotation = this.rotation;
}
}
}, -1, false, this, false);
}
}
}
function getHandleMesh(name: string, scene: Scene): InstancedMesh {
const existingBase = scene.getMeshById("base-handle-mesh");
if (existingBase) {
const instance = new InstancedMesh(name, (existingBase as Mesh));
instance.setParent(scene.getMeshByName("platform"));
return instance;
}
/*const handle = MeshBuilder.CreateCapsule("base-handle-mesh", {
radius: .04,
orientation: Vector3.Right(),
height: .3
}, scene);*/
const handle = HtmlMeshBuilder.CreatePlaneSync("base-handle-mesh", {
html:
`<div style="width: 100%; height: 100%; border-radius: 32px; background-color: #111122; color: #eeeeee"><center>Handle</center></div>
`, width: .5, height: .1, image: {width: 256, height: 51}
}, scene);
//handle.material = buildStandardMaterial('base-handle-material', scene, "#CCCCDD");
handle.id = "base-handle-mesh";
const instance = new InstancedMesh(name, (handle as Mesh));
instance.setParent(scene.getMeshById("platform"));
return instance;
} }

View File

@ -1,4 +1,4 @@
import {Color3, MeshBuilder, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {Color3, MeshBuilder, Vector3, WebXRDefaultExperience} from "@babylonjs/core";
import {AbstractMenu} from "../menus/abstractMenu"; import {AbstractMenu} from "../menus/abstractMenu";
import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers"; import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers";
import {Control3D, GUI3DManager, PlanePanel, Slider3D} from "@babylonjs/gui"; import {Control3D, GUI3DManager, PlanePanel, Slider3D} from "@babylonjs/gui";
@ -19,12 +19,12 @@ export class SoccerMenu extends AbstractMenu {
private manager: GUI3DManager; private manager: GUI3DManager;
private state: SoccerMenuState = SoccerMenuState.NONE; private state: SoccerMenuState = SoccerMenuState.NONE;
private readonly field: Field; private readonly field: Field;
private logger: Logger = log.getLogger('SoccerMenu') private readonly logger: Logger = log.getLogger('SoccerMenu')
private startTime: number; private startTime: number;
private startPosition: Vector3; private startPosition: Vector3;
constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers) { constructor(xr: WebXRDefaultExperience, controllers: Controllers) {
super(scene, xr, controllers); super(xr, controllers);
this.field = new Field(this.scene); this.field = new Field(this.scene);
this.manager = new GUI3DManager(this.scene); this.manager = new GUI3DManager(this.scene);
@ -180,7 +180,7 @@ export class SoccerMenu extends AbstractMenu {
this.manager.controlScaling = .2; this.manager.controlScaling = .2;
//panel.updateLayout(); //panel.updateLayout();
//slider.position.x = 1; //slider.position.x = 1;
this.createHandle(this.manager.rootContainer.children[0].node); //this.createHandle(this.manager.rootContainer.children[0].node);
//this.handle.mesh.position = getFrontPosition(3, this.scene).add(new Vector3(0, .5, 0)); //this.handle.mesh.position = getFrontPosition(3, this.scene).add(new Vector3(0, .5, 0));
} }

View File

@ -13,55 +13,75 @@ const colors: string[] = [
export class Toolbox { export class Toolbox {
private readonly tools: Map<string, InstancedMesh> = new Map<string, InstancedMesh>(); public readonly _toolboxBaseNode: TransformNode;
private readonly _tools: Map<string, InstancedMesh> = new Map<string, InstancedMesh>();
private readonly _logger = log.getLogger('Toolbox');
private readonly _handle: Handle;
private readonly _scene: Scene;
constructor() { constructor() {
this.scene = DefaultScene.Scene; this._scene = DefaultScene.Scene;
this.toolboxBaseNode = new TransformNode("toolbox", this.scene); this._toolboxBaseNode = new TransformNode("toolbox", this._scene);
this.handle = new Handle(this.toolboxBaseNode); this._handle = new Handle(this._toolboxBaseNode, 'Toolbox');
this.toolboxBaseNode.position.y = .2; this._toolboxBaseNode.position.y = .2;
this.toolboxBaseNode.scaling = new Vector3(0.6, 0.6, 0.6); this._toolboxBaseNode.scaling = new Vector3(0.6, 0.6, 0.6);
this.buildToolbox(); this.buildToolbox();
Toolbox._instance = this; Toolbox._instance = this;
} }
private readonly logger = log.getLogger('Toolbox');
private index = 0; private index = 0;
public readonly toolboxBaseNode: TransformNode;
private readonly scene: Scene;
private colorPicker: TransformNode; private colorPicker: TransformNode;
private changing = false; private changing = false;
private readonly handle: Handle;
public static _instance; public static _instance: Toolbox;
public static get instance() { public static get instance() {
return Toolbox._instance; return Toolbox._instance;
} }
public isTool(mesh: AbstractMesh) { public get handleMesh(): AbstractMesh {
return this.tools.has(mesh.id); return this._handle.mesh;
}
public isTool(mesh: AbstractMesh) {
return this._tools.has(mesh.id);
}
private buildToolbox() {
this.setupPointerObservable();
this.buildColorPicker();
if (this._toolboxBaseNode.parent) {
const platform = this._scene.getMeshById("platform");
if (platform) {
this.assignHandleParentAndStore(platform);
} else {
const observer = this._scene.onNewMeshAddedObservable.add((mesh: AbstractMesh) => {
if (mesh && mesh.id == "platform") {
this.assignHandleParentAndStore(mesh);
this._scene.onNewMeshAddedObservable.remove(observer);
}
}, -1, false, this, false);
}
}
} }
private nodePredicate = (node: Node) => {
return node.getClassName() == "InstancedMesh" &&
node.isEnabled(false) == true
};
private setupPointerObservable() { private setupPointerObservable() {
this.scene.onPointerObservable.add((pointerInfo) => { this._scene.onPointerObservable.add((pointerInfo) => {
const pickedMesh = pointerInfo?.pickInfo?.pickedMesh;
if (pointerInfo.type == 1 && if (pointerInfo.type == 1 &&
pointerInfo.pickInfo.pickedMesh?.metadata?.tool == 'color') { pickedMesh?.metadata?.tool == 'color') {
if (this.changing) { if (this.changing) {
this._logger.debug('changing');
this.colorPicker.setEnabled(true); this.colorPicker.setEnabled(true);
return; return;
} else { } else {
const active = pointerInfo.pickInfo.pickedMesh?.parent.getChildren(this.nodePredicate, true); const active = pickedMesh?.parent.getChildren(this.nodePredicate, true);
for (const node of active) { for (const node of active) {
node.setEnabled(false); node.setEnabled(false);
} }
const nodes = pointerInfo.pickInfo.pickedMesh?.metadata?.tools; const nodes = pickedMesh?.metadata?.tools;
if (nodes) { if (nodes) {
for (const node of nodes) { for (const node of nodes) {
this.scene.getNodeById(node)?.setEnabled(true); this._scene.getNodeById(node)?.setEnabled(true);
} }
} }
} }
@ -69,14 +89,19 @@ export class Toolbox {
}); });
} }
private nodePredicate = (node: Node) => {
return node.getClassName() == "InstancedMesh" &&
node.isEnabled(false) == true
};
private buildColorPicker() { private buildColorPicker() {
let initial = true; let initial = true;
for (const c of colors) { for (const c of colors) {
const cnode = buildColor(Color3.FromHexString(c), this.scene, this.toolboxBaseNode, this.index++, this.tools); const cnode = buildColor(Color3.FromHexString(c), this._scene, this._toolboxBaseNode, this.index++, this._tools);
if (initial) { if (initial) {
initial = false; initial = false;
for (const id of cnode.metadata.tools) { for (const id of cnode.metadata.tools) {
this.scene.getNodeById(id)?.setEnabled(true); this._scene.getNodeById(id)?.setEnabled(true);
} }
} }
@ -88,7 +113,7 @@ export class Toolbox {
const offset = new Vector3(-.50, 1.6, .38); const offset = new Vector3(-.50, 1.6, .38);
const rotation = new Vector3(.5, -.6, .18); const rotation = new Vector3(.5, -.6, .18);
const handle = this.handle; const handle = this._handle;
handle.mesh.parent = mesh; handle.mesh.parent = mesh;
if (!handle.idStored) { if (!handle.idStored) {
handle.mesh.position = offset; handle.mesh.position = offset;
@ -96,26 +121,5 @@ export class Toolbox {
} }
} }
private buildToolbox() {
this.setupPointerObservable();
this.buildColorPicker();
if (this.toolboxBaseNode.parent) {
const platform = this.scene.getMeshById("platform");
if (platform) {
this.assignHandleParentAndStore(platform);
} else {
const observer = this.scene.onNewMeshAddedObservable.add((mesh: AbstractMesh) => {
if (mesh && mesh.id == "platform") {
this.assignHandleParentAndStore(mesh);
this.scene.onNewMeshAddedObservable.remove(observer);
}
}, -1, false, this, false);
}
}
}
public get handleMesh(): AbstractMesh {
return this.handle.mesh;
}
} }

View File

@ -15,7 +15,8 @@ import {Introduction} from "./tutorial/introduction";
const webGpu = false; const webGpu = false;
log.setLevel('debug', false); log.setLevel('error', false);
log.getLogger('Handle').setLevel('debug');
const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement); const canvas = (document.querySelector('#gameCanvas') as HTMLCanvasElement);
export class VrApp { export class VrApp {