From 21f87d0c31ef348b9520ba9c1302938101025d71 Mon Sep 17 00:00:00 2001 From: Greg Fodor <gfodor@gmail.com> Date: Sat, 10 Nov 2018 01:28:59 +0000 Subject: [PATCH] Add camera mirroring --- src/components/camera-tool.js | 49 +++--------- src/components/mirror-camera-button.js | 19 +++++ src/hub.html | 10 ++- src/hub.js | 2 + src/systems/camera-mirror.js | 79 +++++++++++++++++++ .../userinput/bindings/keyboard-mouse-user.js | 5 ++ src/systems/userinput/paths.js | 2 + 7 files changed, 122 insertions(+), 44 deletions(-) create mode 100644 src/components/mirror-camera-button.js create mode 100644 src/systems/camera-mirror.js diff --git a/src/components/camera-tool.js b/src/components/camera-tool.js index 1849b3ab6..76289192e 100644 --- a/src/components/camera-tool.js +++ b/src/components/camera-tool.js @@ -101,11 +101,7 @@ AFRAME.registerComponent("camera-tool", { }, remove() { - if (this.mirrorCamera) { - document.body.classList.remove("mirrored-camera"); - } - - this.el.sceneEl.renderer.render = this.directRenderFunc; + this.el.sceneEl.systems["camera-mirror"].unmirrorCameraAtEl(this.el); }, stateAdded(evt) { @@ -114,39 +110,8 @@ AFRAME.registerComponent("camera-tool", { } }, - enableCameraMirror() { - if (this.mirrorCamera) return; - if (!this.el.sceneEl.renderer.vr.enabled) return; - - this.mirrorCamera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 30000); - this.el.setObject3D("mirror-camera", this.mirrorCamera); - this.mirrorCamera.rotation.set(0, Math.PI, 0); - - this.renderer = this.el.sceneEl.renderer; - - // This overrides the render routine to use the mirrored camera - this.directRenderFunc = this.el.sceneEl.renderer.render; - const tempScale = new THREE.Vector3(); - document.body.classList.add("mirrored-camera"); - - this.el.sceneEl.renderer.render = (scene, camera, renderTarget) => { - const sceneEl = this.el.sceneEl; - - this.directRenderFunc.call(sceneEl.renderer, scene, camera, renderTarget); - if (this.playerHead) { - tempScale.copy(this.playerHead.scale); - this.playerHead.scale.set(1, 1, 1); - } - sceneEl.renderer.vr.enabled = false; - const tmpOnAfterRender = sceneEl.object3D.onAfterRender; - delete sceneEl.object3D.onAfterRender; - this.directRenderFunc.call(sceneEl.renderer, scene, this.mirrorCamera); - sceneEl.object3D.onAfterRender = tmpOnAfterRender; - sceneEl.renderer.vr.enabled = true; - if (this.playerHead) { - this.playerHead.scale.copy(tempScale); - } - }; + mirror() { + this.el.sceneEl.systems["camera-mirror"].mirrorCameraAtEl(this.el); }, tick() { @@ -161,8 +126,10 @@ AFRAME.registerComponent("camera-tool", { tock: (function() { const tempScale = new THREE.Vector3(); + return function tock() { const sceneEl = this.el.sceneEl; + const cameraMirrorSystem = this.cameraMirrorSystem || sceneEl.systems["camera-mirror"]; const renderer = this.renderer || sceneEl.renderer; const now = performance.now(); @@ -182,8 +149,10 @@ AFRAME.registerComponent("camera-tool", { renderer.vr.enabled = false; // Use the direct, non mirrored render function if available - if (this.directRenderFunc) { - this.directRenderFunc.call(renderer, sceneEl.object3D, this.camera, this.renderTarget, true); + if (cameraMirrorSystem) { + cameraMirrorSystem + .getDirectRenderFunction() + .call(renderer, sceneEl.object3D, this.camera, this.renderTarget, true); } else { renderer.render(sceneEl.object3D, this.camera, this.renderTarget, true); } diff --git a/src/components/mirror-camera-button.js b/src/components/mirror-camera-button.js new file mode 100644 index 000000000..fc6f867d1 --- /dev/null +++ b/src/components/mirror-camera-button.js @@ -0,0 +1,19 @@ +AFRAME.registerComponent("mirror-camera-button", { + init() { + this.onClick = () => { + this.targetEl.components["camera-tool"].mirror(); + }; + + NAF.utils.getNetworkedEntity(this.el).then(networkedEl => { + this.targetEl = networkedEl; + }); + }, + + play() { + this.el.addEventListener("grab-start", this.onClick); + }, + + pause() { + this.el.removeEventListener("grab-start", this.onClick); + } +}); diff --git a/src/hub.html b/src/hub.html index 47dc4f31e..5260d6da0 100644 --- a/src/hub.html +++ b/src/hub.html @@ -203,13 +203,15 @@ shape="shape: box; halfExtents: 0.22 0.145 0.1; offset: 0 0.02 0" sticky-object="autoLockOnRelease: true; autoLockOnLoad: true; autoLockSpeedLimit: 0;" super-networked-interactable="counter: #camera-counter;" - position-at-box-shape-border="target:.delete-button" + position-at-box-shape-border="target:.camera-menu" set-yxz-order auto-scale-cannon-physics-body > - <a-entity class="delete-button" visible-while-frozen="withinDistance: 3;"> - <a-entity mixin="rounded-text-button" remove-networked-object-button position="0 0 0"> </a-entity> - <a-entity text=" value:remove; width:2.5; align:center;" text-raycast-hack position="0 0 0.01"></a-entity> + <a-entity class="camera-menu" visible-while-frozen="withinDistance: 3;"> + <a-entity mixin="rounded-text-action-button" mirror-camera-button position="0 0.125 0.01"> </a-entity> + <a-entity text=" value:mirror; width:2.5; align:center;" text-raycast-hack position="0 0.125 0.02"></a-entity> + <a-entity mixin="rounded-text-button" remove-networked-object-button position="0 -0.125 0.01"> </a-entity> + <a-entity text=" value:remove; width:2.5; align:center;" text-raycast-hack position="0 -0.125 0.02"></a-entity> </a-entity> </a-entity> </template> diff --git a/src/hub.js b/src/hub.js index bffa1d586..23362b8bb 100644 --- a/src/hub.js +++ b/src/hub.js @@ -59,6 +59,7 @@ import "./components/position-at-box-shape-border"; import "./components/pinnable"; import "./components/pin-networked-object-button"; import "./components/remove-networked-object-button"; +import "./components/mirror-camera-button"; import "./components/destroy-at-extreme-distances"; import "./components/gamma-factor"; import "./components/visible-to-owner"; @@ -82,6 +83,7 @@ import "./systems/personal-space-bubble"; import "./systems/app-mode"; import "./systems/exit-on-blur"; import "./systems/userinput/userinput"; +import "./systems/camera-mirror"; import "./gltf-component-mappings"; diff --git a/src/systems/camera-mirror.js b/src/systems/camera-mirror.js new file mode 100644 index 000000000..780495746 --- /dev/null +++ b/src/systems/camera-mirror.js @@ -0,0 +1,79 @@ +import { paths } from "./userinput/paths"; + +AFRAME.registerSystem("camera-mirror", { + tick() { + const userinput = this.el.systems.userinput; + + if (userinput.get(paths.actions.camera.exitMirror) && this.mirrorEl) { + this.unmirrorCameraAtEl(this.mirrorEl); + } + }, + + // Adds a camera under el, and starts mirroring + mirrorCameraAtEl(el) { + // TODO probably should explicitly check for immersive mode here. + if (AFRAME.utils.device.isMobile()) return; + if (this.mirrorEl && this.mirrorEl !== el) this.unmirrorCameraAtEl(this.mirrorEl); + + this.mirrorEl = el; + this.mirrorCamera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 30000); + this.mirrorCamera.rotation.set(0, Math.PI, 0); + el.setObject3D("mirror-camera", this.mirrorCamera); + + const tempScale = new THREE.Vector3(); + + const renderer = this.el.renderer; + + if (!this.directRenderFunc) { + this.directRenderFunc = renderer.render; + } + + const headEl = document.getElementById("player-head"); + const playerHead = headEl && headEl.object3D; + document.body.classList.add("mirrored-camera"); + + this.el.sceneEl.renderer.render = (scene, camera, renderTarget) => { + const wasVREnabled = this.el.renderer.vr.enabled; + + if (wasVREnabled) { + this.directRenderFunc.call(this.el.renderer, scene, camera, renderTarget); + } + + if (playerHead) { + tempScale.copy(playerHead.scale); + playerHead.scale.set(1, 1, 1); + } + this.el.renderer.vr.enabled = false; + const tmpOnAfterRender = this.el.object3D.onAfterRender; + delete this.el.object3D.onAfterRender; + this.directRenderFunc.call(this.el.renderer, scene, this.mirrorCamera); + this.el.object3D.onAfterRender = tmpOnAfterRender; + this.el.renderer.vr.enabled = wasVREnabled; + if (playerHead) { + playerHead.scale.copy(tempScale); + } + }; + }, + + unmirrorCameraAtEl(el) { + if (this.mirrorEl !== el) return; + + if (this.directRenderFunc) { + this.el.renderer.render = this.directRenderFunc; + } + + el.removeObject3D("mirror-camera"); + document.body.classList.remove("mirrored-camera"); + + this.mirrorEl = null; + this.mirrorCamera = null; + }, + + getDirectRenderFunction() { + if (this.directRenderFunc) { + return this.directRenderFunc; + } + + return this.el.renderer.render; + } +}); diff --git a/src/systems/userinput/bindings/keyboard-mouse-user.js b/src/systems/userinput/bindings/keyboard-mouse-user.js index 46e5edaf7..a151a21fb 100644 --- a/src/systems/userinput/bindings/keyboard-mouse-user.js +++ b/src/systems/userinput/bindings/keyboard-mouse-user.js @@ -77,6 +77,11 @@ export const keyboardMouseUserBindings = { dest: { value: paths.actions.boost }, xform: xforms.copy }, + { + src: { value: paths.device.keyboard.key("Escape") }, + dest: { value: paths.actions.camera.exitMirror }, + xform: xforms.falling + }, { src: { value: paths.device.keyboard.key("q") }, dest: { value: paths.actions.snapRotateLeft }, diff --git a/src/systems/userinput/paths.js b/src/systems/userinput/paths.js index 7f38c58cb..451a85ecf 100644 --- a/src/systems/userinput/paths.js +++ b/src/systems/userinput/paths.js @@ -60,6 +60,8 @@ paths.actions.leftHand.takeSnapshot = "/actions/leftHandTakeSnapshot"; paths.actions.leftHand.thumb = "/actions/leftHand/thumbDown"; paths.actions.leftHand.index = "/actions/leftHand/indexDown"; paths.actions.leftHand.middleRingPinky = "/actions/leftHand/middleRingPinkyDown"; +paths.actions.camera = {}; +paths.actions.camera.exitMirror = "/actions/cameraExitMirror"; paths.device = {}; paths.device.mouse = {}; -- GitLab