I just try to use the THREE.OrbitControls to perform zooming in orthographic projection, but i dont get the behave that i want.
I think that is possible change the viewSize that multiply to left, right, top and bottom to create a something near of a zoom
Anyone hava a better idea?
Yes, you can implement a zooming effect with an OrthographicCamera by using the following pattern:
camera.zoom = 1.5;
camera.updateProjectionMatrix();
This works for PerspectiveCamera, too.
three.js r.70
I have a function to zoom the scene. Please try it.
function zoom_all(center,size) {
// get the current lookAt vector of OrthographicCamera camera
var vectorLookAt = new THREE.Vector3(0, 0, -1);
vectorLookAt.applyQuaternion(camera.quaternion);
vectorLookAt.normalize();
// move back along lookat vector to set new position of camera
vectorLookAt.multiplyScalar(-size);
camera.position = new THREE.Vector3().addVectors(center, vectorLookAt);
// get current size of camera
var viewSize = 2 * camera.top;
var aspectRatio = 2 * camera.right / viewSize; // get aspectRatio of camera
// camera = new THREE.OrthographicCamera(
// -aspectRatio * viewSize / 2, aspectRatio * viewSize / 2,
// viewSize / 2, -viewSize / 2,
// 0.1, 1000);
// update new size for camera
viewSize = size;
// now update camera size
camera.left = -aspectRatio * viewSize / 2;
camera.right = aspectRatio * viewSize / 2;
camera.top = viewSize / 2;
camera.bottom = -viewSize / 2;
camera.near = 0.1;
camera.far = 2 * size;
camera.updateProjectionMatrix();
// you can set light to camera position
spotLight.position.set(camera.position.x, camera.position.y, camera.position.z);
// set center point for orbit control
orbitControls.center.set(center.x, center.y, center.z);
orbitControls.target.set(center.x, center.y, center.z);
}
If anyone is still interested, I edited OrbitControls to work with orthographic camera based on WestLangley's answer:
https://github.com/traversc/OrbitControls-orthographic_camera_fix/blob/master/OrbitControls.js
Related
I can't figure out how to properly rotate an object in ThreeJS. The object is a simple box geometry that is rendered from above somewhere on the screen.
Codepen with the full code.
The object is supposed to rotate around it's own Y axis (the vertical axis) to always face the mouse cursor. I can get it to rotate as the cursor moves around the global axis in the middle of the screen, but not when the cursor moves around the object's own local axis.
UPDATE: I got it to work using ray casting. See code further down or in the codepen.
The orthographic camera is set up like this:
camera = new THREE.OrthographicCamera(
window.innerWidth / - 2, // left
window.innerWidth / 2, // right
window.innerHeight / 2, // top
window.innerHeight / - 2, // bottom
0, // near
1000 ); // far
camera.position.set(0, 0, 500)
camera.updateProjectionMatrix()
The object is set up like this:
const geometry = new THREE.BoxGeometry( 10, 10, 10 );
const material = new THREE.MeshBasicMaterial( { color: "grey" } );
const mesh = new THREE.Mesh( geometry, material );
Code for handling rotation at mousemove:
function onMouseMove(event) {
// Get mouse position
let mousePos = new THREE.Vector2();
mousePos.set(
(event.clientX / window.innerWidth) * 2 - 1, // x
-(event.clientY / window.innerHeight) * 2 + 1); // y
// Calculate angle
let angle = Math.atan2(mousePos.y, mousePos.x);
// Add rotation to object
mesh.rotation.set(
0, // x
angle, // y
0) // z
}
I have also tried
mesh.rotateY(angle)
but this only makes the object spinn like a helicopter.
It's obvious the rotation needs to be based on the relationship between the cursor and the local axis rather than the global axis. I just can't figure out how to achieve that.
UPDATE
I have added a codepen at the top of the question.
UPDATE
I got it to work using the following method with ray casting.
let plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
let pointOfIntersection = new THREE.Vector3();
let raycaster = new THREE.Raycaster();
let mousePos = new THREE.Vector2();
mousePos.set(
(event.clientX / window.innerWidth) * 2 - 1, // x
-(event.clientY / window.innerHeight) * 2 + 1))
raycaster.setFromCamera(mousePos, camera);
raycaster.ray.intersectPlane(plane, pointOfIntersection);
mesh.lookAt(pointOfIntersection)
I'm trying to zoom to fit the object to the center point when panned or rotate to different point.
I have tried it by capturing the center point of the object through bounding box and center point of the scene and passing it to the camera, but still it doesn't have a clear output. The object is getting fit to the camera but not to the center point when I load bigger models.
I have attached a fiddle
document.querySelector('button').addEventListener('click', () => {
const boundingBox = new THREE.Box3()
boundingBox.setFromObject(cube)
const center = new THREE.Vector3()
boundingBox.getCenter(center)
camera.position.y = center.y
camera.position.x = center.x
camera.updateProjectionMatrix()
const size = new THREE.Vector3()
boundingBox.getSize(size)
const fov = camera.fov * (Math.PI / 180)
const maxDim = Math.max(size.x, size.y, size.z)
let cameraZ = Math.abs((maxDim / 4) * Math.tan(fov * 2))
camera.position.z = cameraZ
camera.updateProjectionMatrix()
camera.lookAt(center)
})
I have some code that converts a perspective camera to an orthographic camera. The problem is that when I make the conversion, the model becomes very tiny and hard to see.
I have calculated the zoom factor for the orthographic camera, based on the distance and the FOV. Are there any other properties that I need to set on the orthographic camera (e.g. clipping plane, etc..)?
I believe the position remains the same. I'm not sure what else I need to calculate.
fieldOfView = viewInfo.fov;
var getCameraPosition = function() {
return viewer._viewport._implementation.getCamera()._nativeCamera.position;
};
// Calculate the delta position between the camera and the object
var getPositionDelta = function(position1, position2) {
return {
x: position1.x - position2.x,
y: position1.y - position2.y,
z: position1.z - position2.z
}
};
var getDistance = function(positionDelta, cameraDirection) {
return dot(positionDelta, cameraDirection);
};
distance = getDistance(positionDelta, cameraDirection),
var depth = distance;
var viewportWidth = view.getDomRef().getBoundingClientRect().width;
var viewportHeight = view.getDomRef().getBoundingClientRect().height;
var aspect = viewportWidth / viewportHeight;
var height_ortho = depth * 2 * Math.atan( fieldOfView * (Math.PI/180) / 2 )
var width_ortho = height_ortho * aspect;
var near = viewInfo.near, far = viewInfo.far;
var newCamera = new THREE.OrthographicCamera(
width_ortho / -2, width_ortho / 2,
height_ortho / 2, height_ortho / -2,
near, far );
newCamera.position.copy( viewInfo.position );
var sCamera = new vk.threejs.OrthographicCamera(); //framework creatio of threejs cam
sCamera.setZoomFactor(orthoZoomFactor);
sCamera.setCameraRef(newCamera);
view.getViewport().setCamera(sCamera);
I also tried setting the same camera properties (e.g. clipping planes etc) of the perspective for the orthographic and I still had the same problem.
I guess I am missing some property or calculation required to put the object in the same position as when it was in perspective camera view.
Let's assume you have a perspective view with a given vertical field of view angle fov_y (in degrees) and you know the size of the viewport width and height. Furthermore, you have the near and far plane. These are the values which you use to setup the THREE.PerspectiveCamera:
perspCamera = new THREE.PerspectiveCamera( fov_y, width / height, near, far );
Also, you know the position of the object and the position of the camera. An object doesn't have only a single position, but you have to choose a representative position for its depth.
First you have to calculate the depth of the object.
var v3_object = .... // THREE.Vector3 : positon of the object
var v3_camera = perspCamera.position;
var line_of_sight = new THREE.Vector3();
perspCamera.getWorldDirection( line_of_sight );
var v3_distance = v3_object.clone().sub( v3_camera );
depth = v3_distance.dot( line_of_sight );
Then you have to calculate the "size" of the rectangle which is projected to the viewport at the depth:
aspect = width / height;
height_ortho = depth * 2 * Math.atan( fov_y*(Math.PI/180) / 2 )
width_ortho = height_ortho * aspect;
With these values the THREE.OrthographicCamera can be setup like this:
var orthoCamera = new THREE.OrthographicCamera(
width_ortho / -2, width_ortho / 2,
height_ortho / 2, height_ortho / -2,
near, far );
orthoCamera.position.copy( perspCamera.position );
The positon and direction of the perspective camera can be committed to the orthographic camera like this:
orthoCamera.position.copy( perspCamera.position );
orthoCamera.quaternion.copy( perspCamera.quaternion );
See also stackoverflow question Three.js - Find the current LookAt of a camera?
Mathematically I computed the orthogonal matrix for the rotation that I want to apply to the camera. Before that I successfully applied a rotation on a axis. Perhaps the solution is to transform Matrix3 to Matrix4 and then apply it to the camera somehow.
camera = new THREE.PerspectiveCamera(150, window.innerWidth / window.innerHeight, 0.1, 5000);
camera.position.x = myParams.eye_x;
camera.position.y = myParams.eye_y;
camera.position.z = myParams.eye_z;
var m = new Matrix3();
m.set(
-cos(myParams.eye_deg2)*cos(myParams.eye_deg1),
sin(myParams.eye_deg2)*(Math.pow(cos(myParams.eye_deg1),2)-Math.pow(sin(myParams.eye_deg1),2)) ,
cos(myParams.eye_deg2)*sin(myParams.eye_deg1),
-sin(myParams.eye_deg2)*cos(myParams.eye_deg1),
cos(myParams.eye_deg2)*(Math.pow(sin(myParams.eye_deg1),2)-Math.pow(cos(myParams.eye_deg1),2)) ,
sin(myParams.eye_deg2)*sin(myParams.eye_deg1),
-sin(myParams.eye_deg1),
0,
cos(myParams.eye_deg1));
// camera.rotateOnAxis( pos_center.add(pos_camera.negate()).normalize(), -Math.PI / 2);
// >>>> to do: apply rotation matrix m to camera <<<<<
camera.updateProjectionMatrix();
In Three.js, I want that the top of the render area (first row) point to y=0 in the world
Also, the camera need to look straight (lookAt)
This is my values:
camera = PerspectiveCamera
camera.position.z = 1895.8448868133867
camera.fov = 20
screen.width = 1280
screen.height = 689
camera.lookAt( new THREE.Vector3(0,this.camera.position.y,0) )
I know the result is -264 (camera.position.y) but I don't know how to get there...
Thank you for any help! :-)
I figured it out.
var vFOV = camera.fov * Math.PI / 180;
var height = 2 * Math.tan( vFOV / 2 ) * dist;
camera.position.y = (height/2) * -1