Search code examples
aframe

How to control camera rig orientation with optically tracked pinch in A-frame?


I wanna replicate what this guy does. Basically, you go back and forth from one corner of your room to another and rotate the scene when you reach the guardian fence.

https://repl.it/@tetegithub/aframe#index.html

<!DOCTYPE html>
<html>
<head>
    <script src="https://aframe.io/releases/1.1.0/aframe.min.js">
    </script>
</head>
<body>
    <a-scene>
        <a-box id="box" position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
        <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
        <a-sky color="#ECECEC"></a-sky>

        <a-entity id="rig" rotation="0 0 0">
            
      <a-entity id="camera" camera look-controls></a-entity>
            
      <!-- *** -->
      
      <a-entity id="leftHand" 
      hand-tracking-controls="hand: left;modelColor:#E9967A;" 
      onpinchstarted="rig.object3D.rotation.x +=Math.Pi;"></a-entity>
            
      <!-- *** -->
      
      <a-entity id="rightHand" hand-tracking-controls="hand: right;modelColor:#E9967A"></a-entity>

        </a-entity>
    </a-scene>
</body>
</html>

I've added "onpinchstarted" event in the left hand's tag in the hope that when I pinch with my left hand the camera rig will rotate. And it doesn't.I think I have to somehow work with the event listeners and handlers but all the docs I read look like they are written for the robots. Any advice appreciated.


Solution

  • Well, I came up with a sort of a solution by dissecting the example project.

    rig.js

    AFRAME.registerComponent('rig', {
    
      init: function () {
    
        this.bindMethod();
        this.el.sceneEl.addEventListener('pinchstarted', this.onPinchStarted);
      },
    
    
    //I still don't get what this thing does.
      bindMethod: function () {
        this.onPinchStarted = this.onPinchStarted.bind(this);
      },
      
      onPinchStarted: function () {
        this.el.setAttribute('rotation', {y: this.el.getAttribute('rotation').y + 30});
         },
    
    });
    
    

    index.html

    <script src="rig.js"></script>
    
    <a-entity rig>
        <a-entity camera look-controls position="0 1 0"></a-entity>
        <a-entity hand-tracking-controls="hand: left; modelColor:#E9967A;"></a-entity>
        <a-entity hand-tracking-controls="hand: right; modelColor:#E9967A;"></a-entity>
    </a-entity>
    

    Now I want the rig to yaw the same amount the camera has rotated while I was holding the pinch with my left hand.

    And I made it work after a while thanks to this person.

    index.html

    <script src="rotator.js"></script>
    
     <a-entity id="rig">
            
            <a-camera></a-camera>
    
            <a-entity
              oculus-touch-controls="hand: left;"
              hand-tracking-controls="hand: left; modelColor:#E9967A;"
              rotator="rig: #rig"
            ></a-entity>
    
            <a-entity
              oculus-touch-controls="hand: right;"
              hand-tracking-controls="hand: right; modelColor:#E9967A;"
              rotator="rig: #rig"
            ></a-entity>
          
          </a-entity>
    

    As web XR hand tracking in the Oculus Browser where I test it is still experimental and unstable I added touch controllers' grip buttons.

    rotator.js

    /* global AFRAME, THREE */
    
    AFRAME.registerComponent("rotator", {
      schema: {
        rig: { type: "selector" },
      },
    
      init: function() {
        this.bindMethods();
    
        this.el.addEventListener("pinchstarted", this.onPinchStarted);
        this.el.addEventListener("pinchended", this.onPinchEnded);
        this.el.addEventListener("gripdown", this.onPinchStarted);
        this.el.addEventListener("gripup", this.onPinchEnded);
    
        this.rig = this.data.rig;
        this.box = this.data.box;
        this.box2 = this.data.box2;
        this.camera = this.el.sceneEl.camera.el;
        this.axisY = new THREE.Vector3(0, 1, 0);
      },
    
      bindMethods: function() {
        this.onPinchStarted = this.onPinchStarted.bind(this);
        this.onPinchEnded = this.onPinchEnded.bind(this);
      },
    
      onPinchStarted: function() {
        this.trigger = 1;
        this.oldCameraAngle = this.camera.getAttribute("rotation").y;
      },
    
      tick: function() {
        
        if (this.trigger == 1) {
          
          var angleDifference = THREE.Math.degToRad(
          this.oldCameraAngle - this.camera.getAttribute("rotation").y );
          
          this.oldCameraAngle = this.camera.getAttribute("rotation").y;
    
          var cameraPosition = new THREE.Vector3();
        cameraPosition.setFromMatrixPosition(this.camera.object3D.matrixWorld);
    
          this.rig.object3D.position.add( cameraPosition.negate() );
          this.rig.object3D.position.applyAxisAngle( this.axisY, angleDifference );
          this.rig.object3D.position.add( cameraPosition.negate() );
          this.rig.object3D.rotateOnAxis( this.axisY, angleDifference );
        }
      },
    
      onPinchEnded: function() {
        this.trigger = 0;
      }
      
    });
    
    

    GitHub link and the version published on my website.