1

In my animate() function I have the following code:

  if (this.controls.forward) {

    // move in direction we look at
    var cameraDirectionVector = new THREE.Vector3(0, 0, -1);
    cameraDirectionVector.applyQuaternion(this.camera.quaternion);

    var angle = cameraDirectionVector.angleTo(this.characterMesh.position);
    this.characterMesh.translateOnAxis(cameraDirectionVector.cross(this.characterMesh.position), moveDistance);

    this.characterMesh.translateZ(-moveDistance);
  }
  if (this.controls.backward) {
    this.characterMesh.translateZ(moveDistance);
  }

The camera is a child of the characterMesh. Moving foreward and backward works perfectly. But I want to move (on a plane) where I am actually looking (just yaw). I found a code example for Unity3D and try to adapt it for three.js which did not work.

Any help or hints would be very much appreciated!

Chris C
  • 35
  • 1
  • 6

1 Answers1

3

Hmm, I'm not sure where you were going with that calculation, but I think your intention is better implemented with a dot product instead of a cross product. I adapted this Unity3D code and came up with the following solution. See that link for another potentially more efficient method.

var YAXIS = new THREE.Vector3(0, 1, 0);
var ZAXIS = new THREE.Vector3(0, 0, 1);
var direction = ZAXIS.clone();
direction.applyQuaternion(camera.quaternion);
direction.sub(YAXIS.clone().multiplyScalar(direction.dot(YAXIS)));
direction.normalize();
character.quaternion.setFromUnitVectors(ZAXIS, direction);
character.translateZ(-moveDistance);

Full Code:

var renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var vrEffect = new THREE.VREffect(renderer, function () {});

var camera = new THREE.PerspectiveCamera(
  75, window.innerWidth / window.innerHeight, 0.1, 1000);
var vrControls = new THREE.VRControls(camera);

var scene = new THREE.Scene();

scene.add(new THREE.PointLight());

var makeCube = function (color) {
  return new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.MeshLambertMaterial({
      color: color
    })
  );
};

var spacing = 1.5;
for (var i = 0; i < 10; i++) {
  for (var j = 0; j < 10; j++) {
    var color = (
      (i % 2 === 0 || j %2 === 0) ? 'green' : 'red');
    var cube = makeCube(color);
    cube.position.z = -i * spacing;
    cube.position.x = j * spacing;
    cube.position.y = -2;
    scene.add(cube);
  }
}

var character = new THREE.Object3D();
var characterBody = makeCube('blue');
characterBody.position.y = -1.5;
character.add(characterBody);
scene.add(character);

var moving = false;

window.addEventListener('keydown', function () {
  moving = true;
});

window.addEventListener('keyup', function () {
  moving = false;
});

var moveDistance = 0.1;
var YAXIS = new THREE.Vector3(0, 1, 0);
var ZAXIS = new THREE.Vector3(0, 0, 1);

var render = function() {
  requestAnimationFrame(render);
  
  vrControls.update();
  camera.position.copy(character.position);
  
  if (moving) {
    // move in direction we look at
    var direction = ZAXIS.clone();
    direction.applyQuaternion(camera.quaternion);
    direction.sub(YAXIS.clone().multiplyScalar(direction.dot(YAXIS)));
    direction.normalize();
    character.quaternion.setFromUnitVectors(ZAXIS, direction);
    character.translateZ(-moveDistance);
  }
  
  vrEffect.render(scene, camera);
};

render();


window.addEventListener('resize',  function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  vrEffect.setSize( window.innerWidth, window.innerHeight );
});
<!DOCTYPE html>
<html>
<head>
  <script src="https://rawgit.com/mrdoob/three.js/dev/build/three.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/controls/VRControls.js"></script>
  <script src="https://rawgit.com/mrdoob/three.js/dev/examples/js/effects/VREffect.js"></script>
  <meta charset="utf-8">
</head>
<body>
</body>
</html>
Community
  • 1
  • 1
brianpeiris
  • 10,735
  • 1
  • 31
  • 44
  • Thank you for the code and link! It did not work for me (and maybe I am missing something), and I have to admit I am a newbie when it comes to vectors and threejs. But maybe I was not asking my question in the right way. What I tried to ask was how can I rotate my characterMesh using the rotation information (only yaw) of my camera (HMD)? If I can achieve that, then moving forward (now into the right direction) by pressing the forward key should work. Basically I want to implement the navigation concept like it is implemented in AltspaceVR which I really like... – Chris C Sep 08 '15 at 18:59
  • @ChrisC I've updated the code to match your requirements but it also depends on how you're attaching the camera to the character. Perhaps you would be better of using Three.js' FirstPersonControls in conjunction with VRControls, similar to this: http://stackoverflow.com/questions/30511524/three-js-vrcontrols-integration-how-to-move-in-the-scene – brianpeiris Sep 08 '15 at 19:42
  • I had a look at the FirstPersonControls but it is not what I am looking for. Your updated example did not work for me either. Hmm... I found similar questions and solutions in the Unity3D forum and try to implement them in threejs, until now without success. http://answers.unity3d.com/questions/498094/how-to-make-player-move-in-the-direction-of-where.html http://answers.unity3d.com/questions/1028940/move-in-direction-camera-is-facing.html – Chris C Sep 10 '15 at 03:09
  • @ChrisC I'm pretty sure my solution does what you want it to. Integrating it into your existing code might be a different problem though. I'll have to see more of your code to figure out what's going on. I've edited my answer with the full source code. You can see a working example here: http://output.jsbin.com/coboqis/1/ – brianpeiris Sep 13 '15 at 13:57
  • Thanks again! Your example works great, as you said. I will see what's wrong with my code... – Chris C Sep 13 '15 at 21:07
  • It works in my code as well! A detail in my code made the difference: I added the camera as a child to the character and this did not work. Whereas in your code you copy the position of the character to the position of the camera and don't add the camera to the character. – Chris C Sep 13 '15 at 21:24