javascriptthree.jsaframewebvr

How can i get a Third person perspective for a model using Aframe?


I want my A-frame camera to be behind the model and work as a TPP. I want a model to sync with the camera and rotate and move where ever the camera is moving but it should not move if the camera is pointing up and down it should not look like the model is stuck on the camera.

<html>

<head>
  <script src="https://aframe.io/releases/0.7.1/aframe.min.js"></script>
  <script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v3.13.1/dist/aframe-extras.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/aframe-physics-components@1.1.0/dist/aframe-physics-components.min.js"></script>
  <script src="https://unpkg.com/aframe-event-set-component@^4.0.0/dist/aframe-event-set-component.min.js"></script>
  <script src="https://unpkg.com/super-hands@^3.0.1/dist/super-hands.min.js"></script>
</head>

<body>
  <a-scene physics="gravity: -9.8; restitution: 0.7;" antialias="true">
    <a-assets>
      <img id="ground-grass" src="grass.jpg" />
    </a-assets>
    <a-entity universal-controls="" camera kinematic-body=""
      position="-2.9021956210846644 1.5405810531492952 -3.927244596410301"></a-entity>
    <a-plane src="#ground-grass" scale="50 50 1" repeat=" 5 5 1" rotation="-90 0 0" static-body></a-plane>
    <a-box color="#AA0000" scale="2 2 2" position="-2.5 0.5 -7.5" static-body></a-box>
  </a-scene>
</body>

</html>

If I move the camera the box should also move. Output image


Solution

  • The easiest way would be simple reparenting:

     <!-- The default aframe camera entity -->
     <a-camera>
       <!-- The object with the same transform as the camera + some offset -->
       <a-box position="0 0 -0.5"></a-box>
     </a-camera>
    

    <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
    
      <!-- "Player" -->
      <a-camera>
        <a-box position="0 -0.5 -0.65" scale="0.25 0.25 0.25" color="red"></a-box>
      </a-camera>
    
    </a-scene>


    A more complex, but flexible solution, would be creating a controller with javascript. Lets say we want to:

    we could do it with a component like this:

    <script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
    <script src="https://unpkg.com/aframe-orbit-controls@1.2.0/dist/aframe-orbit-controls.min.js"></script>
    
    <script>
      AFRAME.registerComponent("follow-box", {
        schema: {
          target: {type: "selector"}
        },
        tick: (function() {
          // create once
          const tmpv = new THREE.Vector3();
    
          return function(t, dt) {
            if (!this.data.target) return; // ignore when there is no target
            const target = this.data.target.getObject3D("mesh"); // get the mesh
            // track the position
            const position = target.getWorldPosition(tmpv); // get the world position
            this.el.object3D.position.lerp(tmpv, 0.5) // linear interpolation towards the world position
          }
        })()
      })
      AFRAME.registerComponent("rotate-with-camera", {
        tick: (function() {
          // create once
          const tmpq = new THREE.Quaternion();
          const tmpe = new THREE.Euler();
          
          return function(t, dt) {
            if (!this.el.sceneEl.camera) return; // ignore when there is no camera
            const cam = this.el.sceneEl.camera.el; // get the camera entity
            cam.object3D.getWorldQuaternion(tmpq); // get the world rotation
              tmpe.setFromQuaternion(tmpq, 'YXZ')
              // set attribute is necesarry for wasd-controls
            this.el.setAttribute("rotation", {x: 0, y: tmpe.y * 180 / Math.PI, z: 0 })
          }
        })()
      })
    </script>
    <a-scene>
      <a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9"></a-box>
      <a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E"></a-sphere>
      <a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
      <a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
    
      <!-- camera "rig" -->
      <a-entity follow-box="target: #player" look-controls>
        <a-entity camera position="0 1.6 2"></a-entity>
      </a-entity>
    
      <!-- the "player" -->
      <a-box id="player" color="red" wasd-controls="speed: 35" rotate-with-camera></a-box>
      
      <a-sky color="#ECECEC"></a-sky>
    </a-scene>

    Here's a glitch of it working in aframe networked


    The best way would be to re-use the orbit-controls, but afaik they won't work with wasd controls without some customization