Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adjusting camera for visible Three.js shape

I have a CubeGeometry which the camera is looking at, and I want the camera to zoom so that the cube is entirely visible, but no larger.

My initial attempt was to convert the cube verticies to the camera coordinate system,

function toScreenXY(position, camera) {
  var pos = position.clone();
  var projScreenMat = new THREE.Matrix4();
  projScreenMat.multiply(camera.projectionMatrix, camera.matrixWorldInverse);
  projScreenMat.multiplyVector3( pos );

  return pos;
}
function ScaleInView() {
  camera.fov = 0.0;
  for (var i=0; i<8; i++) {
    proj2d = toScreenXY(cube.geometry.vertices[i],camera);
    angle = 57.296 * Math.max(Math.atan(proj2d.x/proj2d.z), Math.atan(proj2d.y/proj2d.z));
    camera.fov = Math.max(camera.fov,angle);
  }
  camera.updateProjectionMatrix();
}

I thought this would work, but sometimes it's too small, and other times too large (depending on the position of the camera).

I also need to do this for Orthographic Camera.

Edit: I know how to do this when the cube is facing the camera, I'm looking for a way to do it when the camera is moved to some arbitrary (r, theta, phi) position (spherical polar coordinates; r is actually constant for my purposes).

like image 987
sn6uv Avatar asked Jun 30 '12 13:06

sn6uv


People also ask

What is camera in THREEjs?

The most common camera in three. js and the one we've been using up to this point is the PerspectiveCamera . It gives a 3d view where things in the distance appear smaller than things up close. The PerspectiveCamera defines a frustum. A frustum is a solid pyramid shape with the tip cut off.

How do I add fog to my 3js?

In three. js you add fog by creating Fog or FogExp2 object and setting it on the scene's fog property. Fog lets you choose near and far settings which are distances from the camera. Anything closer than near is unaffected by fog.


2 Answers

Perspective Camera. If the camera is centered and viewing the cube head-on, define

dist = distance from the camera to the front face ( important ! ) of the cube

and

height = height of the cube.

If you set the camera field-of-view as follows

fov = 2 * Math.atan( height / ( 2 * dist ) ) * ( 180 / Math.PI );

then the cube height will match the visible height.

Orthographic Camera. If the camera is centered and viewing the cube head-on, define

aspect = the aspect ratio of your window (i.e., width / height)

and

height = height of the cube.

Then construct your camera this way:

camera = new THREE.OrthographicCamera( -aspect * height/2, aspect * height/2, height/2, -height/2, near, far );

The cube height will match the visible height.

In either case, if the camera is not centered, or is otherwise viewing the cube at an angle, then the problem is more complicated.

Also, if the window is narrower than it is high, then the width is the constraining factor, and the problem is more complicated.

like image 155
WestLangley Avatar answered Oct 01 '22 22:10

WestLangley


Multiplying by camera.matrixWorldInverse gives a vector in the camera's coordinates, but importantly does not apply perspective.

function toCameraCoords(position) {
  return camera.matrixWorldInverse.multiplyVector3(position.clone());
}

We can then find the smallest angle that will fit all the box corners in the scene. arctan(D.x / D.z) gives the angle BCD where B is what the camera is looking at, C is the camera's position, and D the position of an object that you want to be visible in the camera coordinates.

In my case, the following ensures that the the cube boundbox is fully visible.

function ScaleInView() {
  var tmp_fov = 0.0;

  for (var i=0; i<8; i++) {
    proj2d = toCameraCoords(boundbox.geometry.vertices[i]);

    angle = 114.59 * Math.max( // 2 * (Pi / 180)
      Math.abs(Math.atan(proj2d.x/proj2d.z) / camera.aspect),
      Math.abs(Math.atan(proj2d.y/proj2d.z))
    );
    tmp_fov = Math.max(tmp_fov, angle);
 }

 camera.fov = tmp_fov + 5; // An extra 5 degrees keeps all lines visible
 camera.updateProjectionMatrix();
}
like image 32
sn6uv Avatar answered Oct 01 '22 22:10

sn6uv