From 4d8f33f9bbc70f2929bf71d30b417df83ea26f54 Mon Sep 17 00:00:00 2001 From: Kevin Lee <kevin@infinite-lee.com> Date: Thu, 19 Apr 2018 18:57:38 -0700 Subject: [PATCH] Add teleport to gaze-only cursor --- src/components/cursor-controller.js | 64 +++++++++++++++++++---------- src/hub.html | 17 ++++++-- src/input-mappings.js | 4 +- 3 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index aa54b3e95..3840aa6a6 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -8,8 +8,9 @@ AFRAME.registerComponent("cursor-controller", { schema: { cursor: { type: "selector" }, camera: { type: "selector" }, - controller: { type: "selector" }, playerRig: { type: "selector" }, + gazeTeleportControls: { type: "selector" }, + controller: { type: "string" }, otherHand: { type: "string" }, hand: { default: "right" }, trackedControls: { type: "string", default: "[tracked-controls]" }, @@ -39,6 +40,7 @@ AFRAME.registerComponent("cursor-controller", { this.point = new THREE.Vector3(); this.mousePos = new THREE.Vector2(); this.controllerQuaternion = new THREE.Quaternion(); + this.controller = null; this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered }); @@ -69,13 +71,17 @@ AFRAME.registerComponent("cursor-controller", { update: function(oldData) { if (this.data.controller !== oldData.controller) { - if (oldData.controller) { - oldData.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener); - oldData.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener); + if (this.controller) { + this.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener); + this.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener); } - this.data.controller.addEventListener(this.data.controllerEvent, this.controllerEventListener); - this.data.controller.addEventListener(this.data.controllerEndEvent, this.controllerEndEventListener); + this.controller = document.querySelector(this.data.controller); + + if (this.controller) { + this.controller.addEventListener(this.data.controllerEvent, this.controllerEventListener); + this.controller.addEventListener(this.data.controllerEndEvent, this.controllerEndEventListener); + } } if (oldData.otherHand && this.data.otherHand !== oldData.otherHand) { @@ -131,8 +137,10 @@ AFRAME.registerComponent("cursor-controller", { this.el.removeEventListener("raycaster-intersection", this.raycasterIntersectionListener); this.el.removeEventListener("raycaster-intersection-cleared", this.raycasterIntersectionClearedListener); - this.data.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener); - this.data.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener); + if (this.controller) { + this.controller.removeEventListener(this.data.controllerEvent, this.controllerEventListener); + this.controller.removeEventListener(this.data.controllerEndEvent, this.controllerEndEventListener); + } this.data.playerRig.removeEventListener("model-loaded", this.modelLoadedListener); @@ -153,21 +161,22 @@ AFRAME.registerComponent("cursor-controller", { if (this.wasOtherHandGrabbing) return; + //set raycaster origin/direction const camera = this.data.camera.components.camera.camera; if (!this.inVR && !this.isMobile) { - //mouse + //mouse cursor mode const raycaster = this.el.components.raycaster.raycaster; raycaster.setFromCamera(this.mousePos, camera); this.origin = raycaster.ray.origin; this.direction = raycaster.ray.direction; } else if ((this.inVR || this.isMobile) && !this.hasPointingDevice) { - //gaze + //gaze cursor mode camera.getWorldPosition(this.origin); camera.getWorldDirection(this.direction); } else { - //3d - this.data.controller.object3D.getWorldPosition(this.origin); - this.data.controller.object3D.getWorldQuaternion(this.controllerQuaternion); + //3d cursor mode + this.controller.object3D.getWorldPosition(this.origin); + this.controller.object3D.getWorldQuaternion(this.controllerQuaternion); this.direction .set(0, 0, -1) .applyQuaternion(this.controllerQuaternion) @@ -178,6 +187,7 @@ AFRAME.registerComponent("cursor-controller", { let intersection = null; + //update cursor position if (!this.isGrabbing) { const intersections = this.el.components.raycaster.intersections; if (intersections.length > 0 && intersections[0].distance <= this.data.maxDistance) { @@ -199,7 +209,10 @@ AFRAME.registerComponent("cursor-controller", { this.data.cursor.object3D.position.copy(this.point); } - if (intersection) { + //update currentTargetType + if (this.isGrabbing && !intersection) { + this.currentTargetType = TARGET_TYPE_INTERACTABLE; + } else if (intersection) { if (this._isInteractableAllowed() && this._isClass("interactable", intersection.object.el)) { this.currentTargetType = TARGET_TYPE_INTERACTABLE; } else if (this._isClass("ui", intersection.object.el)) { @@ -209,6 +222,7 @@ AFRAME.registerComponent("cursor-controller", { this.currentTargetType = TARGET_TYPE_NONE; } + //update cursor material const isTarget = this._isTargetOfType(TARGET_TYPE_INTERACTABLE_OR_UI); if ((this.isGrabbing || isTarget) && !this.wasIntersecting) { this.wasIntersecting = true; @@ -218,6 +232,7 @@ AFRAME.registerComponent("cursor-controller", { this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered }); } + //update line if (this.hasPointingDevice) { this.el.setAttribute("line", { start: this.origin.clone(), end: this.data.cursor.object3D.position.clone() }); } @@ -250,23 +265,29 @@ AFRAME.registerComponent("cursor-controller", { }, _startTeleport: function() { + const hideCursor = !(this.hasPointingDevice || this.inVR); if (this.hasPointingDevice) { - this.data.controller.emit(this.data.teleportEvent, {}); - this.el.setAttribute("line", { visible: false }); - this.data.cursor.setAttribute("visible", false); + this.controller.emit(this.data.teleportEvent, {}); + } else if (this.inVR) { + this.data.gazeTeleportControls.emit(this.data.teleportEvent, {}); } + this.el.setAttribute("line", { visible: hideCursor }); + this.data.cursor.setAttribute("visible", hideCursor); }, _endTeleport: function() { + const showCursor = this.hasPointingDevice || this.inVR; if (this.hasPointingDevice) { - this.data.controller.emit(this.data.teleportEndEvent, {}); - this.el.setAttribute("line", { visible: true }); - this.data.cursor.setAttribute("visible", true); + this.controller.emit(this.data.teleportEndEvent, {}); + } else if (this.inVR) { + this.data.gazeTeleportControls.emit(this.data.teleportEndEvent, {}); } + this.el.setAttribute("line", { visible: showCursor }); + this.data.cursor.setAttribute("visible", showCursor); }, _handleMouseDown: function() { - if (this._isTargetOfType(TARGET_TYPE_INTERACTABLE)) { + if (this._isTargetOfType(TARGET_TYPE_INTERACTABLE_OR_UI)) { const lookControls = this.data.camera.components["look-controls"]; if (lookControls) lookControls.pause(); this.data.cursor.emit(this.data.controllerEvent, {}); @@ -343,5 +364,6 @@ AFRAME.registerComponent("cursor-controller", { _handleCursorLoaded: function() { this.data.cursor.object3DMap.mesh.renderOrder = 1; + this.el.quer; } }); diff --git a/src/hub.html b/src/hub.html index afa09451e..4c1186977 100644 --- a/src/hub.html +++ b/src/hub.html @@ -146,14 +146,15 @@ camera: #player-camera; controller: #player-right-controller; playerRig: #player-rig; - otherHand: #right-super-hand;" + otherHand: #right-super-hand; + gazeTeleportControls: #gaze-teleport;" raycaster="objects: .collidable, .interactable, .ui; far: 3;" line="visible: false; color: white; opacity: 0.2;" ></a-entity> <a-sphere id="cursor" - material="depthTest: false;" + material="depthTest: false; opacity:0.9;" radius="0.02" static-body="shape: sphere;" collision-filter="collisionForces: false" @@ -198,7 +199,17 @@ camera position="0 1.6 0" personal-space-bubble="radius: 0.4" - ></a-entity> + > + <a-entity + id="gaze-teleport" + position = "0.15 0 0" + teleport-controls=" + cameraRig: #player-rig; + teleportOrigin: #player-camera; + button: action_teleport_; + collisionEntities: [nav-mesh]" + ></a-entity> + </a-entity> <a-entity id="player-left-controller" diff --git a/src/input-mappings.js b/src/input-mappings.js index 09160b0ec..b692e173f 100644 --- a/src/input-mappings.js +++ b/src/input-mappings.js @@ -94,7 +94,9 @@ const config = { trackpad_dpad4_pressed_center_down: ["action_primary_down"], trackpad_dpad4_pressed_north_down: ["action_primary_down"], trackpad_dpad4_pressed_south_down: ["action_primary_down"], - trackpadup: ["action_primary_up"] + trackpadup: ["action_primary_up"], + triggerdown: ["action_primary_down"], + triggerup: ["action_primary_up"] }, keyboard: { m_press: "action_mute", -- GitLab