I have an initial roll, pitch & yaw for my camera and so I update the camera rotation with the respective values and it seems correct.
When I create and update the OrbitControls() the values are lost and I don't see a way to set the initial direction in the OrbitControls() constructor or methods.
I tried creating the controls after I updated my camera and that didn't help.
Is it possible to do this?
// Molly
You can compute the initial lookAt / target into some Vector3 computed with spherical / cartesian conversion
Then set the Orbit controller's target with it and save the state. It will use this target as a reference from now on
// Your initial target
let sphericalTarget = new THREE.Spherical(1, Math.PI / 2 - pitch, yaw)
let target = new THREE.Vector3().setFromSpherical(sphericalTarget)
controls = new THREE.OrbitControls()
controls.target = target
controls.saveState()
Related
I'm rather new to threejs, so what I'm doing might not be the most efficient way.
I have an object in AR on a mobile device and I want to know if I intersect with it when touching on the screen.
I use the following code to generate the raycast, and it works initally.
const tempMatrix = new THREE.Matrix4();
tempMatrix.identity().extractRotation(this.controller.matrixWorld);
this.raycaster.ray.origin.setFromMatrixPosition(this.controller.matrixWorld);
this.raycaster.ray.direction.set(0, 0, -1).applyMatrix4(tempMatrix);
However, I have the ability to reposition the object (i.e. reset the position so the object is in front, relative to the current camera direction and position) by moving and rotating the whole scene.
After the repositioning, the raycasting is completely offset and is not casting rays anywhere near where I touch the screen.
Repositioning is done like this (while it works, if there's a better way, let me know!) :
public handleReposition(): void {
const xRotation = Math.abs(this.camera.rotation.x) > Math.PI / 2 ? -Math.PI : 0;
const yRotation = this.camera.rotation.y;
this.scene.rotation.set(xRotation, yRotation, xRotation);
this.scene.position.set(this.camera.position.x, this.camera.position.y, this.camera.position.z);
}
How can I achieve to raycast to the correct new location?
Thanks!
Assuming this.scene is actually the main threejs Scene, it's usually a bad idea to change its rotation or position, since it will affect everything inside the scene, including the controller. I'd suggest moving your object instead, or add your object(s) to a Group and move that.
In my webapp I'm using ThreeJS scenes in different modals/popups/dialogs with different width/height ratios.
Furthermore, I want to use multiple user defined camera settings (rotation, position, lookAt etc.) among these different scenes.
Therefore, I save the camera object via camera.toJSON() when the user clicks a capture camera settings button.
(Before I did this, I saved just the object camera, but unfortunately these objects are quite big and slow down the performance while multiple camera objects get stored. Nevertheless, this approach worked, since I was able to copy all the desired values between the saved camera object and the currently used camera [e.g. current_camera.position.x=saved_camera.position.x and so on])
In every scene I want now to use the saved properties I tried the following:
let m = new THREE.Matrix4();
m.fromArray(saved_camera.object.matrix);
current_camera.applyMatrix(m)
current_camera.updateMatrix();
Unfortunately this doesn't work.
"normal" camera object
camera.toJSON() object
If you're comfortable using matrices, then you can turn off the matrix auto-update that three.js does during the render process, and keep the world matrix up-to-date yourself. (This includes any time you change the camera's orientation, so keep that in mind if you're using some form of mouse interaction to control the camera angle.)
First, turn off automatic matrix updating for your camera by setting the autoUpdateMatrix property to false. You can still use the convenience properties (position, rotation, scale), but you'll have to manually update the world matrix by calling camera.updateMatrixWorld(true);.
Finally, when you're ready to restore a particular camera orientation, simply copy the matrix values using the matrixWorld's copy method.
var origin = new THREE.Vector3();
var theCamera = new THREE.PerspectiveCamera(35, 1, 1, 1000);
theCamera.autoUpdateMatrix = false; // turn off auto-update
theCamera.position.set(10, 10, 10);
theCamera.lookAt(origin);
theCamera.updateMatrixWorld(true); // manually update the matrix!
console.log("Camera original matrix: ", theCamera.matrixWorld.elements.toString());
var saveMatrix = new THREE.Matrix4();
saveMatrix.copy(theCamera.matrixWorld);
// saveMatrix now contains the current value of theCamera.matrixWorld
theCamera.position.set(50, -50, 75);
theCamera.lookAt(origin);
theCamera.updateMatrixWorld(true); // manually update the matrix!
console.log("Camera moved matrix: ", theCamera.matrixWorld.elements.toString());
// theCamera.matrixWorld now holds a value that's different from saveMatrix.
theCamera.matrixWorld.copy(saveMatrix);
// Don't upate the matrix, because you just SET it.
console.log("Camera moved matrix: ", theCamera.matrixWorld.elements.toString());
// theCamera.matrixWorld once again contains the saved value.
<script src="https://threejs.org/build/three.js"></script>
Edit to address OrbitControls:
It looks like OrbitControls uses the convenience properties, rather than gathering the information from the matrix. As such, when you restore a camera position, you'll also need to restore those properties. This is easily done by using decompose on the matrix, and copying the resulting values into the appropriate properties:
var d = new THREE.Vector3(),
q = new THREE.Quaternion(),
s = new THREE.Vector3();
camera.matrixWorld.decompose( d, q, s );
camera.position.copy( d );
camera.quaternion.copy( q );
camera.scale.copy( s );
I have a 3D model in .obj format. However the coordinates for this 3D model are not (0,0,0). This a 3D render of drone imagery so the coordinates are actual georeferenced coordinates.
I'm following the example in Three.js on how to load an obj with its mtl on webgl. I use the original HTML except that I simply replace the obj listed as male02 by CerroPelaoLow and the files are placed in the obj directory. Firefox displays the model correctly but the position is the problem.
Note that this render is generated by a program this way and even though I can manipulate the model with a program such as Meshlab I'd still prefer the minimum manipulation possible.
So how can I use local coordinates of my object or focus the camera and then use a different set of controls?
You can use the boundingSphere or boundingBox of your object's geometry to determine the position and of your camera. I have already implemented a functionality to focus an object or a set objects. So, here I share some code:
// assuming following variables:
// object -> your obj model (THREE.Mesh)
// camera -> PerspectiveCamera
// controls -> I'm also using OrbitControls
// if boundingSphere isn't set yet
object.computeBoundingSphere();
var sphere = object.geometry.boundingSphere.clone();
sphere.applyMatrix4( object.matrixWorld );
// vector from current center to camera position (shouldn't be zero in length)
var s = new THREE.Vector3().subVectors( camera.position, controls.center );
var h = sphere.radius / Math.tan( camera.fov / 2 * Math.PI / 180 );
var newPos = new THREE.Vector3().addVectors( sphere.center, s.setLength(h) );
camera.position.copy( newPos );
controls.center.copy( sphere.center );
Im trying to move camera by changing its world matrix. But it doesen't seem to work. No matter what the camera wont move.
camera.matrixAutoUpdate = false
camera.matrixWorld = portal_view(camera,port1_quad,port2_quad)
i have tried using the matrixupdate = true but still nothing. What am i douing wrong ?
function portal_view(camera, src_portal, dst_portal) {
var inverse_view_to_source = new THREE.Matrix4().getInverse(camera.matrix).multiply(src_portal.matrix);
var new_mat = dst_portal.matrix.clone().multiply(inverse_view_to_source);
new_mat.makeRotationY(3.14);
return new_mat;
}
matrixWorld of an object is computed from its position, quaternion and scale. You cant directly change the 'matrixWorld' of an object. In other words, if you change the matrixWorld, the change wont be reflected on position of the object. You have to change the position of the camera.
What you can do is, extract the translation and rotation from the matrix and change the camera position and quaternion according to it.
How can I set the camera target and zoom to the target ?
I have many 3d Visuals with Point3D positions which of course are
transformed so the camera doens't locate the object acurately.
You Can Used CameraController property to Set Camera in a HelixViewport3D
HelixViewport3D HelixViewport3d_1 = new HelixViewport3D();
// after Add objects to HelixViewport3d_1 then set camera...
//...
//...
//set Camera
HelixViewport3d_1.CameraController.CameraUpDirection = new Vector3D(0, 0, 1); // set CameraUpDirection property is optional to have better view !! :)
HelixViewport3d_1.CameraController.CameraTarget = new Point3D(30, 0, 0); // or your Target Object 3D Coordinate
HelixViewport3d_1.CameraController.AddZoomForce(-0.3); // amount of Zoom
Additional to the answer by user4106274:
Here the AddZoomForce() is method set to -0.3 for zoom, because the Target object was in (+x,+y,+Z) locations, and perhaps the CameraLookDirection property was in a contrary location.
In different CameraLookDirection property we should Zoom by:
HelixViewport3d_1.CameraController.AddZoomForce(+0.3); // amount of Zoom