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!

1 Answer 1

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>

Sign up to request clarification or add additional context in comments.

6 Comments

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...
@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: stackoverflow.com/questions/30511524/…
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. answers.unity3d.com/questions/498094/… answers.unity3d.com/questions/1028940/…
@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: output.jsbin.com/coboqis/1
Thanks again! Your example works great, as you said. I will see what's wrong with my code...
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.