21

I've working on an app which displays some 3D models. We load the models, create the meshes, add them to the scene...standard procedure. After the last mesh is added, we compute the bounding box in order to move the camera and cover all the scene, using the size of the total geometry and the size of the viewport to do the math.

    if (bounds.bx / bounds.by < camera.aspect) {
        /* Vertical max */
        r = bounds.by / (2 * Math.tan(Math.PI / 8));
    } else {
        /* Horizontal max */
        hFOV = 2 * Math.atan(Math.tan(Math.PI / 8) * camera.aspect);
        r = bounds.bx / (2 * Math.tan((hFOV / 2)));
    }

bounds is an object containing the width and height of the bounding box. After this calculation, we move the camera(plus a little ratio, just aesthetics, we want a little room between the geometry and the screen border :) ) and render

    camera.position.z = r * 1.05;

So far this is implemented and runs ok. This has been done with PerspectiveCamera. Now we want to change that and use OrthographicCamera...turns out to be a mess. Models are too small, we lose the mousewheel zoom from the TrackBall Controls and the algorithm to move the camera is not working anymore. Also I don't understand the parameters of the constructor for the camera...these width and height are for the geometry or the viewport?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Leprosy
  • 1,085
  • 4
  • 14
  • 36

3 Answers3

46

The pattern for instantiating an orthographic camera in three.js is:

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

where width and height are the width and height of the camera's cuboid-shaped frustum measured in world-space units.

near and far are the world-space distances to the near and far planes of the frustum. Both near and far should be greater than zero.

To prevent distortion, you will typically want the aspect ratio of the orthographic camera ( width / height ) to match the aspect ratio of the render's canvas. (see *Note below)

It is unfortunate that many of the three.js examples pass window.innerWidth and window.innerHeight as args to this constructor. Doing so only makes sense if the orthographic camera is used for rendering to a texture, or if the world units for your orthographic scene are in pixels.


*Note: Actually, the camera aspect ratio should match the aspect ratio of the renderer's viewport. The viewport can be a sub-region of the canvas. If you do not set the renderer's viewport directly using renderer.setViewport(), the viewport will be the same size as the canvas, and hence have the same aspect ratio as the canvas.

three.js r.73

WestLangley
  • 102,557
  • 10
  • 276
  • 276
  • I understand, but...how can I move the camera on the Z axis, like I did with the above code in Perspective mode? – Leprosy Jul 10 '13 at 17:09
  • 4
    Moving the camera forward or backward does not change the orthographic projection. – WestLangley Jul 10 '13 at 17:30
  • Now I understand. So, we must use camera.setZoom? I'm a little confused here, because the width and height used in the constructor doesn't seem to alter the size of the rendered window. I used, for example (1600, 1200) as w/h, and (16, 12) and the result is the same. – Leprosy Jul 10 '13 at 18:18
  • Please make a new post if you are having problems with your code. Please provide a live example if possible and ask a specific question. – WestLangley Jul 10 '13 at 20:40
  • One of the three.js examples for Orthographic camera has a -500 for the near plane and a 1000 for the far plane. Shouldn't the near be > 0? – AlvinfromDiaspar Sep 17 '14 at 18:51
  • 1
    @AlvinfromDiaspar Yes it should, but it does not have to be. – WestLangley Sep 18 '14 at 21:33
  • what distortions result from not matching the aspect ratio of the orthographic camera ( width / height ) to the aspect ratio of the render's canvas. – expiredninja Oct 11 '14 at 02:55
  • 1
    @expiredninja The scene will appear stretched. – WestLangley Oct 11 '14 at 03:02
14

For future reference: Updated video

var w = container.clientWidth;
var h = container.clientHeight;
var viewSize = h;
var aspectRatio = w / h;

_viewport = {
    viewSize: viewSize,
    aspectRatio: aspectRatio,
    left: (-aspectRatio * viewSize) / 2,
    right: (aspectRatio * viewSize) / 2,
    top: viewSize / 2,
    bottom: -viewSize / 2,
    near: -100,
    far: 100
}

_camera = new THREE.OrthographicCamera ( 
    _viewport.left, 
    _viewport.right, 
    _viewport.top, 
    _viewport.bottom, 
    _viewport.near, 
    _viewport.far 
);

In my specific case, my world units are pixels. Hence, I am using container.clientWidth and container.clientHeight as width and height. You probably don't want to do this.

Ivan Bacher
  • 5,855
  • 9
  • 36
  • 56
  • 1. The orthographic camera parameters are in world units. Are your world units pixels? 2. Also, in spite of what you have seen in the past -- or in the video -- the near plane should be positive, so the frustum is in front of the camera. – WestLangley Feb 05 '15 at 20:36
  • +1 for the video link, -1 for the code (sorry!), specifically: `var viewSize = h;` Instead `viewSize` should be solely dependent on the sizes (in world coords) of the objects in your scene. – Darren Cook Feb 10 '16 at 18:39
  • 1
    @Matteo You seem to have fundamental misconceptions, but this not the proper place to discuss it. Please make a new post if you are unable figure it out yourself via experimentation. A negative near plane will render objects behind the camera. – WestLangley Feb 01 '17 at 18:01
  • Added a new video link – Ivan Bacher Sep 30 '20 at 08:05
  • This solve my problem only by using `near -100` – Yogesh Bangar Mar 02 '23 at 04:49
-4
            camera.top = (.95*camera.top);
            camera.bottom = (.95*camera.bottom);
            camera.left = (.95*camera.left);
            camera.right = (.95*camera.right);
contehhh
  • 122
  • 1
  • 11