From d2282ca8325138b0d7c62294ec2d86acef1c9d8f Mon Sep 17 00:00:00 2001 From: Greg Fagan Date: Wed, 6 May 2020 19:01:30 -0500 Subject: [PATCH] Fix look-at component for vec3 targets and cameras fix supermedium/superframe#229 Vec3 targets were not working. As weddingdj observed, in the update method the `data` property was the default empty string, and not the component attribute. Not sure the underlying cause, but probably in A-Frame's component `buildData` method. This results in the component immediately removing itself. Resolved here by changing the default to a vec3 rather than empty string. Might also resolve supermedium/superframe#217 Also fixed the -z flip with cameras. The line of code that performs the flip was commented out, and it is unclear why. I restored that line and moved the logic to a `lookAt` method on the component, so it could be used in the `update` path as well, which never properly accounted for the camera. In addition, hooked up events to watch for the camera being attached or detached from the component, which at the very least makes this component's camera behavior independent of the attribute order. Finally, I edited the demo scene to add uses of the component that execute these code paths, to verify it works. --- components/look-at/examples/basic/index.html | 29 ++++++++++- components/look-at/index.js | 51 +++++++++++++------- 2 files changed, 62 insertions(+), 18 deletions(-) diff --git a/components/look-at/examples/basic/index.html b/components/look-at/examples/basic/index.html index c0f433d1..18c57d39 100644 --- a/components/look-at/examples/basic/index.html +++ b/components/look-at/examples/basic/index.html @@ -6,6 +6,28 @@ + @@ -29,13 +51,18 @@ + position="0 0 1" toggleable-camera> + + + + + diff --git a/components/look-at/index.js b/components/look-at/index.js index eecb2fef..c493b75f 100644 --- a/components/look-at/index.js +++ b/components/look-at/index.js @@ -17,7 +17,7 @@ delete AFRAME.components['look-at']; */ AFRAME.registerComponent('look-at', { schema: { - default: '', + default: '0 0 0', parse: function (value) { // A static position to look at. @@ -39,6 +39,9 @@ AFRAME.registerComponent('look-at', { init: function () { this.target3D = null; this.vector = new THREE.Vector3(); + this.cameraListener = AFRAME.utils.bind(this.cameraListener, this); + this.el.addEventListener('componentinitialized', this.cameraListener); + this.el.addEventListener('componentremoved', this.cameraListener); }, /** @@ -48,7 +51,6 @@ AFRAME.registerComponent('look-at', { update: function () { var self = this; var target = self.data; - var object3D = self.el.object3D; var targetEl; // No longer looking at anything (i.e., look-at=""). @@ -58,7 +60,7 @@ AFRAME.registerComponent('look-at', { // Look at a position. if (typeof target === 'object') { - return object3D.lookAt(new THREE.Vector3(target.x, target.y, target.z)); + return this.lookAt(new THREE.Vector3(target.x, target.y, target.z)); } // Assume target is a string. @@ -83,27 +85,42 @@ AFRAME.registerComponent('look-at', { return function (t) { // Track target object position. Depends on parent object keeping global transforms up // to state with updateMatrixWorld(). In practice, this is handled by the renderer. - var target; var target3D = this.target3D; - var object3D = this.el.object3D; - var vector = this.vector; - if (target3D) { target3D.getWorldPosition(vec3); - if (this.el.getObject3D('camera')) { - // Flip the vector to -z, looking away from target for camera entities. When using - // lookat from THREE camera objects, this is applied for you, but since the camera is - // nested into a Object3D, we need to apply this manually. - // vector.subVectors(object3D.position, vec3).add(object3D.position); - } else { - vector = vec3; - } - object3D.lookAt(vector); + this.lookAt(vec3); } - }; + } })(), + remove: function () { + this.el.removeEventListener('componentinitialized', this.cameraListener); + this.el.removeEventListener('componentremoved', this.cameraListener); + }, + beginTracking: function (targetEl) { this.target3D = targetEl.object3D; + }, + + cameraListener: function (e) { + if (e.detail && e.detail.name === 'camera') { + this.update(); + } + }, + + lookAt: function (position) { + var vector = this.vector; + var object3D = this.el.object3D; + + if (this.el.getObject3D('camera')) { + // Flip the vector to -z, looking away from target for camera entities. When using + // lookat from THREE camera objects, this is applied for you, but since the camera is + // nested into a Object3D, we need to apply this manually. + vector.subVectors(object3D.position, position).add(object3D.position); + } else { + vector.copy(position); + } + + object3D.lookAt(vector); } });