1
votes

I have a scene with multiple navigation points. When I teleport to any location in VR using my HMD (Oculus rift) the camera remembers the direction it should look at, in the new location and that is logically correct behavior.

But what I want is for camera to point to some other direction(mainly origin).

For this I reset the camera position to (0,0,0) when I teleport to the new location. And it works on desktop but when I use an HMD (Oculus Rift), the camera does not reset to (0,0,0).

Any suggestions would be very helpful.

1

1 Answers

4
votes

Firstly, instead of resetting the camera directly, add the camera to a rig and manipulate that instead. You'll also have to do some math to account for the users's orientation and position relative to their play space.

Here's a working demo:

const camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
const scene = new THREE.Scene();

const subject = box(1, 1, 1);
subject.position.set(2, 0, 4);
scene.add(subject);

camera.position.y = 1;
const rig = new THREE.Object3D();
rig.add(camera);
scene.add(rig);

const teleportAndLook = (function () {
  const cameraDirection = new THREE.Vector3();
  const teleportToLook = new THREE.Vector3();
  const cameraOffset = new THREE.Vector3();
  return function (teleportPos, lookPos, rig, camera){
    cameraDirection.set(0, 0, -1);
    cameraDirection.applyQuaternion(camera.quaternion);
    cameraDirection.y = 0;
    cameraDirection.normalize();

    teleportToLook.subVectors(lookPos, teleportPos)
    teleportToLook.normalize();
    
    rig.quaternion.setFromUnitVectors(cameraDirection, teleportToLook);
    
    cameraOffset.copy(camera.position);
    cameraOffset.applyQuaternion(rig.quaternion);
    cameraOffset.y = 0;
    rig.position.subVectors(teleportPos, cameraOffset);
  }
})();

function randomTeleport() { 
  const teleportPos = new THREE.Vector3();
  teleportPos.x = (Math.random() - 0.5) * 2 * 5;
  teleportPos.z = (Math.random() - 0.5) * 2 * 5;
  teleportAndLook(teleportPos, subject.position, rig, camera);
}
randomTeleport();

const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.vr.enabled = true;
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
document.body.appendChild( renderer.domElement );
document.body.appendChild(WEBVR.createButton(renderer));

function box(w, h, d) {
  const box = new THREE.Mesh(
    new THREE.BoxGeometry(w, h, d),
    new THREE.MeshLambertMaterial({color: new THREE.Color().setHSL(Math.random(), 0.2, 0.2)})
  );
  box.castShadow = true;
  box.receiveShadow = true;
  return box;
}

const light = new THREE.DirectionalLight();
light.position.set(8, 10, 5)
light.castShadow = true;
light.shadow.mapSize.setScalar(2048);
scene.add(light)
scene.add(new THREE.AmbientLight('white', 0.4));

const floor = box(20, 0.01, 20)
floor.position.y = -0.01;
scene.add(floor);
scene.add(new THREE.GridHelper()); 

renderer.domElement.addEventListener("click", randomTeleport);
setInterval(randomTeleport, 3000)

function animate() {
  renderer.render( scene, camera );
};

renderer.setAnimationLoop(animate);

window.addEventListener("resize", () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
});
body { margin: 0; font-size: 0; }
<script src="https://unpkg.com/[email protected]/examples/js/vr/WebVR.js"></script>
<script src="https://unpkg.com/[email protected]/build/three.min.js"></script>