aframe/threejs camera manual rotation - three.js

I am trying to manually tween camera rotation to 0,0:
camera.object3D.matrixAutoUpdate=false;
var orgrot = { x : camera.object3D.rotation.x, y: camera.object3D.rotation.y };
var target = { x : 0, y: 0 };
var tween = new TWEEN.Tween(orgrot).to(target, 500);
tween.onUpdate(function(){
camera.object3D.rotation.x= this.x;
camera.object3D.rotation.y= this.y;
camera.object3D.updateMatrix();
});
The tween works as expected, but I am loosing mouse control over camera.
To get it back I am setting matrixAutoUpdate to true
tween.onComplete(function(){
document.querySelector('#camera').object3D.matrixAutoUpdate=true
});
But after that, the camera rotation changes back to original position (before tween ) and I would like to keep 0,0. What I am missing ? thanks
UPDATE Below is a version using aframe only without going into threejs objects
I think the problem is camera look-control component
When enabled - I can not animate camera rotation or even setAttribute.
I have to disable it first - than fire animation and than enable it again.
But the problem is, when I enable it again:
camera.setAttribute ('look-controls-enabled',"true")
camera goes back to original rotation ( state before reset animation ).
Similar problem when using matrixAutoUpdate=false/true
Here is my pen http://codepen.io/anon/pen/dMjrWd
If you rotate left 30deg, it will fire resetCamera animation - it works as intended.
But only when look component is disabled. If I enable it again in "animationend" event - the rotation will go back to original state and trigger resetCamera again and again

You really should not have to mess with matrixAutoUpdate.
But given that you are, try the following to force the position, quaternion, and scale to match the matrix:
object.matrix.decompose( object.position, object.quaternion, object.scale );
three.js r.76

I see several problems. If you are using aframe you should not access the object3D directly. You should do
cameraEl.setAttribute('position', {x: 0, y: 0; z;0 })
You can apply a tween to any entity using the declarative API
If you want to modify the camera independently of the running tween you can wrap your camera in another entity
<a-entity rotation="0 360 0"><a-entity id="camera" camera><a-animation ...></a-animation></a-entity></a-entity>

try this codeblock, it works for me on aframe 0.8.2
static faceCameraToCoords(camera, coords){
camera.setAttribute("look-controls",{enabled:false})
camera.setAttribute("rotation", coords);
var newX = camera.object3D.rotation.x
var newY = camera.object3D.rotation.y
camera.components['look-controls'].pitchObject.rotation.x = newX
camera.components['look-controls'].yawObject.rotation.y = newY
camera.setAttribute("look-controls",{enabled:true})
}

You can no longer set a-camera rotation after version 0.8.0.
Updated solution for Aframe 0.9.2:
Given the following camera setup:
<a-entity
id="rig"
position="0 1.6 0">
<a-camera position="0 0 0"></a-camera>
</a-entity>
You can directly alter the camera rotation thus:
const cameraEl = document.querySelector('a-camera');
cameraEl.components['look-controls'].pitchObject.rotation.x = newRotation.x;
cameraEl.components['look-controls'].yawObject.rotation.y = newRotation.y;
Make sure the newRotation values are in radians. For example, use THREE.Math.degToRad(newRotation.x).

Related

How to make a cube to always appear in front of the XR(phone) camera?

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 };

Making an entity rotate with the camera - Aframe

I'm attempting to make a rolodex menu in Aframe like this.
Here is the glitch so far https://glitch.com/edit/#!/fourth-kitten
I'm trying to get the entity to rotate into view with the camera
AFRAME.registerComponent('rotate-with-camera', {
tick: function (){
console.log(this)
if(this.el.sceneEl.camera){
const {rotation} = this.el.sceneEl.camera.parent
const containerRotation = this.el.getAttribute('rotation')
this.el.setAttribute('rotation', {...containerRotation, z: containerRotation.y -= rotation._y * 360})
}
}
})
However I can't get a nice smooth roll like this example and I'm confused as to the right maths to get it staying in front of the camera on roll up or roll down to make the next row animate into view.
Any ideas?
If you want to position it in front of the camera, then just use the parent - child DOM hierarchy:
<a-camera>
<a-entity position="0 0 -3></a-entity>
</a-camera>
This way your menu will be in front of the camera, and will be rotating with the camera.
To access outer elements, you can move the container a bit when the camera is looking right - left
Glitch here.

How can i achieve exact functionality like pointerlock example in threejs but move around programmatically instead of mouse

How can i achieve THREE.js pointerlock controls example functionality but move around programmatically (values from accelerometer device) instead of mouse movement?
THREE.PointerLockControls (next: Module) works this way:
Module makes a construction yawObject -> pitchObject -> camera (pitchObject is a child of yawObject and camera becomes a child of pitchObject).
You add yawObject (which you could get from Module with yourControls.getObject() function) to your scene (to keep transforms updated).
Module adds 'mousemove' event listener and updates yawObject.rotation.y and pitchObject.rotation.x when you move mouse if yourControls.enabled !== false.
Next if you are interested in actually locking cursor you could do it in your client code as in example.
And to update your camera position you could manipulate yawObject's position (yourControls.getObject().position).
So to manipulate controls without mouse you could setup Module this way:
camera.position.set(0, 0, 0);
camera.rotation.set(0, 0, 0); // THREE.PointerLockControls does this too
var myControls = new THREE.PointerLockControls(camera);
var controlsObject = myControls.getObject();
controlsObject.position.set(myEntryX, myEntryY, myEntryZ); // set starting point
controlsObject.rotation.y = myEntryYaw; // rotate yaw obj
controlsObject.children[0].rotation.x = myEntryPitch; // rotate pitch obj
scene.add(controlsObject);
and then keeping myControls.enabled = false manipulate controlsObject.position, controlsObject.rotation.y, controlsObject.children[0].rotation.x.

Get mouse clicked point's 3D coordinate in three.js

I'm new in THREE.js.
I'm trying to get 3D coordinates of point on mouse click on the object (not simple objects: Box, Sphere,..) in Canvas.
In detail, I'm working with 3D objects viewer - I have camera (THREE.PerspectiveCamera), mouse controls (rotate, zoom, move), add/remove objects (my own object, loaded using loaders for THREE.js) in scene,.. And I want to add a function, which gets 3D coordinates for clicked point in 3D.
Exactly, I want coordinates of the end point of a ray - begining from mouse click on the camera_near_window and ending to the object's point, I've clicked on..
I tried a lot of ways to do it:
Getting coordinates of point on z=0 plane -- It works fine, but it is on z=0 plane and it is not that I need, cause I have OrbitControls..
THREE.js example - clickable objects -- It uses CanvasRenderer (not WebGLRenderer) and works for a little objects (but works for my project): browser crashes when I load many objects (CanvasRenderer needs 5x more memory then WebGLRenderer).
"How to get object in WebGL 3d space from a mouse click coordinate" - I tried this one too, but raycaster.intersectObjects found nothing, intersects was an empty array (maybe it works for only simple objects like box, sphere,..).
Can anyone show me the demo code which gets 3D point coords for clicked point of clicking object in 3D, please..?
So, as I think this question is useful for someone, I'll answer it myself (I'll write my resolve):
var renderer, canvas, canvasPosition, camera, scene, rayCaster, mousePosition;
function init() {
renderer = new THREE.WebGLRenderer({ antialias: false });
canvas = renderer.domElement;
canvasPosition = $(canvas).position();
camera = new THREE.PerspectiveCamera(20, $(canvas).width() / $(canvas).height(), 0.01, 1e10);
scene = new THREE.Scene();
rayCaster = new THREE.Raycaster();
mousePosition = new THREE.Vector2();
scene.add(camera);
var myObjects = new THREE.Object3D();
// myObjects.add( your object );
// myObjects.add( your object );
// myObjects.add( your object );
myObjects.name = 'MyObj_s';
scene.add(myObjects);
};
function getClicked3DPoint(evt) {
evt.preventDefault();
mousePosition.x = ((evt.clientX - canvasPosition.left) / canvas.width) * 2 - 1;
mousePosition.y = -((evt.clientY - canvasPosition.top) / canvas.height) * 2 + 1;
rayCaster.setFromCamera(mousePosition, camera);
var intersects = rayCaster.intersectObjects(scene.getObjectByName('MyObj_s').children, true);
if (intersects.length > 0)
return intersects[0].point;
};

How to calculate local rotation to keep text upright?

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

Resources