I'm using the PointerLockControls to control my camera but how would I be able to load the rotation of the current view to another camera that is not attached to anything but the scene?
I can get the yawObject position but the yawObject rotation does not show the exact view I had with the PointerLockControl camera. For example, if I output the following:
yawObject position: 183.91,10.00,-204.16
yawObject rotation: 0.00,73.89,0.00
pitchObject position: 0.00,20.00,0.00
pitchObject rotation: -0.10,0.00,0.00
If I try to set the 2nd camera that does not have any controls with the following:
camera2.position.set(183.91,10.00,-204.16);
camera2.rotation.set(0.00,73.89,0.00);
The resulting camera2 view is not the same.
If you want to create a second camera that has the same view direction as the camera controled by PointerLockControls, the key is to look at the method PointerLockControls.getDirection(), which returns a direction vector.
If you want to be able to set the 2nd camera's rotation directly, you do this:
camera2.rotation.order = 'YXZ'; // important!
. . .
camera2.rotation.set( pitchObject.rotation.x, yawObject.rotation.y, 0 );
where
yawObject = controls.getObject();
pitchObject = yawObject.children[ 0 ];
three.js r.67
Related
I am trying to orbit a camera on an inclined orbit around a scene while the camera always points to the scene's origin. (Think of the camera rig installation for filming the bullet dodging scene in the first Matrix movie.)
The idea is to let the x-component of the mouse position on screen determine the position of the camera on the orbit. Hence, I created a dummy object whose position is changed in the mousemove-listener. The camera is attached to the dummy object, and the dummy object is attached to a pivot which creates the orbit inclination.
var pivot = new THREE.Object3D();
var cameraPos = new THREE.Object3D();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
cameraPos.add(camera);
pivot.rotation.y = Math.PI/4;
pivot.add(cameraPos)
I've put a minimal example together here: codepen.
The result is this erratic camera movement. Any idea WHY that happens?
I cannot figure out what I am doing wrong.
A solution
I will add that I know already how to fix it.
Step 1: Detach the camera from the dummy object cameraPos
Step 2: Set the camera position manually to the position cameraPos.
var target = new THREE.Vector3();
cameraPos.getWorldPosition(target)
camera.position.copy(target);
Outro
I really like the idea of attaching the camera to an object which follows then a prescribed path. But does attaching the camera to an object create unwanted interaction? What is the explanation for this behavior?
I'm trying to make a cube mesh to be always positioned in front of the XR camera.
No matter how I move my phone camera, the cube should appear right in front of the camera showing only one side of the cube.
Firstly, I added a cube mesh to the scene in the beginning:
material = new THREE.MeshLambertMaterial({ color: 0x9797CE });
box = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), material);
box.position.set(0, 0, -3);
scene.add(box);
And then tried to draw the box in front of the XR camera:
function animate() {
let xrCamera = renderer.xr.getCamera(camera);
box.position.set(xrCamera.position.x, xrCamera.position.y, xrCamera.position.z - 3);
box.rotation.set(xrCamera.rotation.x, xrCamera.rotation.y, xrCamera.rotation.z);
renderer.render(scene, camera);
}
When I run the code, the cube appears in front of my phone camera.
But when I rotate my phone, the cube rotates itself in the same position not following the camera.
I also tried xrCamera.add(box) but it doesn't seem to work.
How can I correctly make the cube always appear still in front of the XR camera?
It's important to know that currently (r115) the transformation properties position, rotation and scale as well as the local matrix of the XR camera are not updated.
So instead of adding the box to xrCamera, add it to camera. Besides, keep in mind that WebXRManager.getCamera() is intended for internal use only and no part of the public API.
I have been solving a similar problem. I needed to get a point in front of camera using aframe API. But the challege was when the experience were on VR mode(fullscreen) and playing on movile or headset. In this context the management of the current camera is absolutely controlled by WebXR. With WebXR THREE applies headset pose to the object3D internally.
You only can use the matrixWorld of the three camera to access the camera world reference data, other properties or methods are not correct. In the case of aframe you must access to the object3D of the aframe camera entity and manage its matrixWorld. It is the only method to get correct information of the position/rotation/scale of the camera that it is move by the sensors of a movile or of a AR/VR goggles when the play is on VR/AR mode.
I use to get the in front of Camera Position With WebXR Headset Pose:
const distanceFromCamera = 250; // the depth in the screen, what ever you need
const inFrontOfCameraPosition = new AFRAME.THREE.Vector3( 0, 0, -distanceFromCamera );
const threeSceneCamera = <THREE.PerspectiveCamera>AFRAME.scenes[0].camera;
inFrontOfCameraPosition.applyMatrix4( threeSceneCamera.matrixWorld );
return { x: inFrontOfCameraPosition.x, y: inFrontOfCameraPosition.y, z: inFrontOfCameraPosition.z };
If I do not set initial position to the camera, the WEB borwser and Oculus Go browser behave differently (see images below).
const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 );
// camera position is Vector3(0, 0, 0)
scene.add( camera );
Pic. 1 - Initial camera position in web browser (e.g. Google Chrome)
Pic. 2 - Initial camera position in VR browser (e.g. default browser of Oculus Go)
It looks like Three.js's scene knows in which environment it runs and automatically adjust the camera position. How can I change the initial position of the camera?
Currently, I am doing somethink like this:
const cameraHolder = new Group();
cameraHolder.add(camera);
cameraHolder.position.set(0, 1, 0);
scene.add(cameraHolder);
but again, it doesn't resolve the issue with different positions in different environments.
I believe this is the behaviour of the reference space. If you use reference space type of *-floor the device knows about how tall you are. The camera y is then set to your device y position, which makes sense. As I couldn't find where to grab the device height from I just set the reference space type to local.
this.renderer.xr.setReferenceSpaceType( 'local' );
For me the scene.add(cameraHolder) was necessary, otherwise the camera wouldn't receive the position/rotation. Old HMDs had the cameras attached to a "head" model, then you would turn the head instead of the camera.
You can use
renderer.xr.addEventListener()
Example
camera = new THREE.PerspectiveCamera(35, width / height, 1, 15);
camera.position.set(0, 0.6, 3); // Set the initial Camera Position.
const cameraGroup = new THREE.Group();
cameraGroup.position.set(0, -1, 1.5); // Set the initial VR Headset Position.
//When user turn on the VR mode.
renderer.xr.addEventListener('sessionstart', function () {
scene.add(cameraGroup);
cameraGroup.add(camera);
});
//When user turn off the VR mode.
renderer.xr.addEventListener('sessionend', function () {
scene.remove(cameraGroup);
cameraGroup.remove(camera);
});
Within my THREE scene i have an Object that rotates. The child object is positioned at (92,92,92) within the rotating Object, so it orbits the centre position (0,0,0) is a spherical path with my mouse movement. How can i find the global position of the child object in respect to the scene as it rotates. I'm fairly new to THREE.js and thankful for any support in advance.
My code:
ObjectParent = new THREE.Object3D();
scene.add( ObjectParent );
ObjectChild = new THREE.Object3D();
ObjectParent.add( ObjectChild );
ObjectChild.position.set(92,92,92);
Render:
ObjectParent.rotation.y -= (target.y + ObjectParent.rotation.y) * 0.08;
ObjectParent.rotation.x += (target.x - ObjectParent.rotation.x) * 0.07;
ObjectParent.updateMatrixWorld();
scene.updateMatrixWorld();
First of all, you usually do not need to call
ObjectParent.updateMatrixWorld();
scene.updateMatrixWorld();
inside your render loop. The renderer will do that for you.
To find the world position of a child object, you can use this pattern:
var vector = new THREE.Vector3();
...
vector.setFromMatrixPosition( child.matrixWorld );
The renderer should have previously updated the scene matrices for you. If you have changed a parent's position since the last rendering, you will have to first call
parent.updateMatrixWorld();
to update the relevant matrices.
It is a good idea to look at the three.js source code so you understand what these functions do.
three.js r.67
I have text on the screen that always faces the user and remains upright with the following code (this is working):
object.lookAt(camera.position);
object.rotation.x = camera.rotation.x;
object.rotation.y = camera.rotation.y;
object.rotation.z = camera.rotation.z;
Now, after a button has rotated the scene by 90 degrees about the y-axis,
target = new THREE.Vector3(camera.position.z, camera.position.y, -camera.position.x);
object.lookAt(target);
So the text is facing the user as desired, but I can't figure out how to calculate the object rotation to keep the text vertical as I rotate the scene around with trackball controls:
object.rotation.x = ??
object.rotation.y = ??
object.rotation.z = ??
Suggestions? Thanks!
The easiest solution is to use THREE.OrbitControls instead.
Then, in your render loop:
object.quaternion.copy( camera.quaternion );
three.js r.69