I set position and fov of my perspective camera manually in THREE.JS. It behaves as expected. However, once I try to interact with the scene later on, through the TrackBall Controls, it just displays a black screen, no errors.
JS Fiddle
Relevant code:
var bbox = new THREE.Box3().setFromObject(scene);
var center = bbox.getCenter();
var size = bbox.getSize();
// update some controls properties
controls.target.set(center.x, center.y, center.z);
// position the camera on the y axis
camera.position.set(center.x, center.y - size.y, center.z);
// fit FOV
var dist = size.y / 2;
var fov = 2 * Math.atan( size.z / ( 2 * dist ) ) * ( 180 / Math.PI );
camera.fov = fov;
camera.updateProjectionMatrix();
Which step am I missing in order to be able to then interact properly with the scene
Thanks
==== EDITS
Working fiddle based on accepted answer: Fiddle
I think that it is not possible to correctly project a case when the camera "up" position is parallel to the vector defined by the camera position and target. The camera up position should specify how to orient the view in a plane orthogonal to the vector from camera position to the target but if the component of camera.up along that plane is zero it cannot work. In your code:
the camera "up" position is the default (0,1,0)
the vector from camera position to camera target is (0,size.y,0)
The simplest fix is probably to specify a different camera "up", i.e.
camera.up = new THREE.Vector3(0,0,1.);
or any other vector not parallel to the y direction.
Related
My code
//zoom and scaleFactor are both constants
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera = new THREE.OrthographicCamera(
window.innerWidth / - (zoom / scaleFactor),
window.innerWidth / (zoom / scaleFactor),
window.innerHeight / (zoom / scaleFactor),
window.innerHeight / - (zoom / scaleFactor),
-500, 1000
);
scene = new THREE.Scene();
controls = new THREE.TrackballControls(camera, renderer.domElement);
Hello people of stackoverflow, I can't seem to get zoom to work with the trackball control object in Three.js. I used the OrbitControls object and it worked swimmingly, but zoom simply isn't working when i use TrackballControls. I made sure that noZoom is false and played around with zoomSpeed, both to no avail. I also tried debugging the source code for TrackballControls but that didn't get me anywhere.
Is it relevant that I'm using an orthographic camera? It seems plausible to me that the zoom actually just moves the camera forward and back to achieve zoom, hence the zoom doesn't work with orthographic projection, but at the same time that would mess with the perspective of the image using a perspective camera.
I'd appreciate any help. Thank you!
It appears to me that the method of zooming that TrackallControls uses is actually to move the camera back and forth, hence no zoom is achieved when using an orthographic camera. What I did to get zoom is to add the following lines to my source of TrackballControls.js around line 480:
case 2:
// Zoom in pages
_zoomStart.y -= event.deltaY * 0.025;
//add the following 2 lines
object.zoom -= event.deltaY * 0.025;
object.updateProjectionMatrix();
break;
Do the same for the rest of the cases and you now have zoom when you scroll the mouse. It's not as fluid as the normal zoom though. Also, the code you add still runs even when you're using a perspective camera, so you'll have to put a check somewhere in there to prevent that if you want your zoom to work normally with a perspective camera.
I have a scene with multiple elements, say a cube, cylinder, sphere and some more. I have set the camera position for the scene at (0,30,40) and am trying to display all other elements using this camera position.
However, I observe that in the code below, where I display a simple moving cube, it does not work with the camera positioning I need for the rest of the scene, but works with only another camera configuration.
See lines 30-32 in my javascript code below (I have commented it). Basically it works for camera position (0,-400,400) but does not work for camera position (0,30,40) which I what I need as part of my project settings, to accommodate the rest of the elements.
var angularSpeed = 0.2;
var lastTime = 0;
function animate(){
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
var angularChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;
cube.rotation.y -= angularChange;
lastTime = time;
renderer.render(scene, camera);
requestAnimationFrame(function(){
animate();
});
}
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
/* Works */
camera.position.x = 0;
camera.position.y = -400;
camera.position.z = 400;
/* Does not work, but I want these to be the camera settings */
// camera.position.x = 0;
// camera.position.y = 30;
// camera.position.z = 40;
camera.rotation.x = 0.70;
var scene = new THREE.Scene();
var cube = new THREE.Mesh(new THREE.CubeGeometry(200,100,100), new THREE.MeshNormalMaterial());
scene.add(cube);
animate();
I have created a jsbin for the same.
How is this usually done? I know I can also change the position of the cube using it's APIs and by playing around with cube.position.x, cube.position.y and cube.position.z, keeping the camera settings required by the project (0,30,40) in this case, and hope to find some cube position where it gets displayed on screen. But I'm not sure if doing a trial and error on the above three variables is the best way to go about it.
Please advise.
EDIT : I have tried to create a scene which includes the following
var cube,cylinder,sphere,plane,polyhedron,torusknot,torus;
My objective was to display them at the center of the screen irrespective of the camera position I decided for the entire scene (only one camera position for all elements).
This is a jsbin where I was able to display multiple elements.
For a different camera positioning (x,y,z), I was able to display them at the center of the page either by either/or both of the following'
Changing the size of the elements. For example, changing the length, breadth and height of the cube
Changing the y position of the element. For example, cube.position.y
However, though, I was able to get it to work this time, I feel it's helped by the fact that only the position.y needed altering. Had x,y,z all needed change, it would be difficult to come up with the position by trial and error.
Is there another way, this is done?
Finding it slightly difficult to believe that someone who bases all the elements in his scene based on a particular camera position, only needs to alter one coordinate (in my case, the y coordinate) to adjust to any other camera position.
About using camera.lookAt(cube.position) which was also suggested
I am apprehensive about using this, because in the same scene, I'm interested in look'ingAt, not just the cube, but also the cylinder,sphere,plane,polyhedron,torusknot,torus;
Make the camera look at the cube position (after the cube added to the scene):
camera.lookAt (cube.position);
I am using r59 of the three.js lib. Based on the stl loader example i am trying to rotate the camera around one axis of the scene. I use TrackBallControls to interface my scene with the mouse.
When i move the mouse i want the scene to rotate with the objects around the origin z-axis. But i can't manage to find a way to block the others directions. Is it in the trackball or in the three lib ?
For example rotate arround the green axis but keeping the angle of the angle of the camera.
When i do :
var mouseOnBall = new THREE.Vector3(
( clientX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
0.0,
0.0
);
The camera rotates only around the green axis but it's not really straight as you can see on the screenshot. And i would like to keep the camera on the initial angle. See the second screenshot :
I am unable to find the anwser most of them on the internet are deprecated.
Sincerely
Austriker
Is there a way to find out the width of a rendered portion of the scene?
For example, if we have a mesh of width 100, but rendered with a certain level of zoom...how can I calculate the width of the portion of the mesh that is being rendered in the screen?
You have to be precise here.
You can calculate the visible rectangular region given the camera's field-of-view, camera.fov, and a given distance, dist, from the camera.
Since the object presumably has depth, you have to pick one plane through the mesh, and do the calculation at that distance.
Here is how to calculate the visible height and width for a given distance dist from the camera.
var vFOV = THREE.MathUtils.degToRad( camera.fov ); // convert vertical fov to radians
var height = 2 * Math.tan( vFOV / 2 ) * dist; // visible height
var width = height * camera.aspect; // visible width
three.js r.117
For a (perfect) spherical object, it will cover more of the view close up as you need to take the tangent into account i.e. you can't see the 'poles'.
Use the following for a spherical object:
// we're using the following triangle: camera - tangent point on sphere - centre of sphere
var targetAngle = 2 * Math.asin(objectRadius / distanceToCamera);
var vFOV = THREE.Math.degToRad(this.fov);
var normalizedHeight = targetAngle / vFOV;
Multiply this with your viewport width to get screen height. For width you need to apply hFOV - see: 90 degree field of view without distortion in THREE.PerspectiveCamera
This is how a camera is instantiated:
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR
);
What do these values mean?
I was wondering the same thing so I looked it up, it is a view "frustum".
I'll paste here a code comment I wrote in a recent project because it sums it up nicely IMHO.
// "What the f*** is a frustum?" you ask. Well I did.
// Think about it as a truncated pyramid. The tip is the camera. From a certain
// point "down" the pyramid (the "near plane"), stuff can be seen on-screen.
// After the "base" of the pyramid (the "far plane"), stuff is too far to be
// seen. Stuff outside the pyramid is off-screen too. There is also the "aspect
// ratio" (the rectangle that makes up the pyramid's base, so this value is
// width/height) and the "field of view" (think of it as a lens or something,
// it distorts the pyramid so there's more objects on screen - it is set in
// degrees and 45° is more-or-less a "natural" perspective. The bigger the
// number, the more "perspective" there is).
I found this tutorial very useful for understanding all the camera parameters, and the difference between PerspectiveCamera and OrthographicCamera.
PerspectiveCamera
Fov (Field of view) - This is part of scene that can be seen from the position of the camera. As you probably know, we, humans, have almost 180-degree field of view, while some birds might even have a complete 360-degree field of view. However, for computers, we usually use the field of view between 60 and 90 degrees.
Aspect - The aspect ratio is ratio between the horizontal and vertical size of the area where we render the output. As we usually use the entire window, we will just use that ratio. The aspect ratio determines the difference between the horizontal field of view and the vertical field of view as you can see in the figure on the following page. Ordinary value is window.innerWidth / window.innerHeight.
Near - This property defines a min distance from the camera the Three.js renders the scene. Usually, this is a very small value, e.g. 0.1.
Far - This property defines a max distance we see the scene from the position of the camera. If we set this as too low, a part of our scene might not be rendered; if we set it as too high, in some cases, it might affect the rendering performance. Normal value is between 500 and 2000.
OrthographicCamera
Left (Camera frustum left plane) - You should see this as what is the left border of what will be rendered. If we set this value to -100, you won’t see any objects that are farther to the left.
Right (Camera frustum right plane) - Anything farther to the right won't be rendered.
Top (Camera frustum top plane) - The maximum top position to be rendered.
Bottom (Camera frustum bottom plane) The bottom position to be rendered.
Near (Camera frustum near plane) - From this point on, based on the position of the camera, the scene will be rendered.
Far (Camera frustum far plane) - The furthest point, based on the position of the camera, to which the scene will be rendered.
The following picture should be very illustrative:
The main difference between the two camera modes is that in the OrthographicCamera distance plays no role, so all the elements are of the same size, as you can see in the case of the red and yellow ball.
Finally here is some code you can use to switch from one camera to the other:
this.switchCamera = function(SCENE_WIDTH, SCENE_HEIGHT) {
if (camera instanceof THREE.PerspectiveCamera) {
camera = new THREE.OrthographicCamera( SCENE_WIDTH / - 2, SCENE_WIDTH / 2, SCENE_HEIGHT / 2, SCENE_HEIGHT / - 2, 0.1, 1000 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = -1;
camera.lookAt(scene.position);
this.perspective = "Orthographic";
} else {
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = -1;
camera.lookAt(scene.position);
this.perspective = "Perspective";
}
};
Notes:
The function camera.lookAt(scene.position) orients the camera to where the scene is located, so it is visible.
Units in three.js are SI units, so the values of left,right,top,bottom should not assumed to be pixels.
The aspect ratio of the camera's frustum should normally match the canvas' aspect ratio.
SCENE_WIDTH, SCENE_HEIGHT, can be determined through the geometries that are added in the scene. The orthographic frustum could be much larger than the scene but it wouldn't be very parsimonious.
Useful links:
http://www.glprogramming.com/red/chapter03.html
Three.js - Orthographic camera
The first param is FOV means field of view, imagine a camera on a tripod, if you change lens to wide angle you get a higher FOV. Try to imagine a cone coming out from the camera, it can only see objects in that area.
ASPECT means aspect ratio, a widescreen TV is 16/9 and old ones were 4/3, usually just give it the screen width/height or the dims of a DIV you would like three.js to use.
fov: Camera frustum vertical field of view.
aspect: Camera frustum aspect ratio.
near: Camera frustum near plane.
far: Camera frustum far plane.
On these pages there some image for the FOV, NEAR plane, anmd FAR plane.
https://threejsfundamentals.org/threejs/lessons/resources/frustum-3d.svg
https://upload.wikimedia.org/wikipedia/commons/thumb/0/02/ViewFrustum.svg/440px-ViewFrustum.svg.png
https://threejsfundamentals.org/threejs/lessons/threejs-cameras.html
https://en.wikipedia.org/wiki/Viewing_frustum
This is the aspect ratio.
https://en.wikipedia.org/wiki/Aspect_ratio_(image)
This is the official docs.
https://threejs.org/docs/#api/en/cameras/PerspectiveCamera