Search code examples
javascriptthree.jsgeometrytrigonometryperspectivecamera

How to use view offset and zoom properties on camera in three.js in parallel


I'm trying to program a three.js scene with a PerspectiveCamera. The canvas will show a sub-region of the whole camera view and it will also have a zoom factor. I've double checked that my offset numbers are good and the zoom factor makes sense.

At full vertical fit they are

current zoom 1 
x 714.4099378881989 y 0 w 3755.1801242236024 h 3888

The offset works perfectly when the zoom is 1 but when the zoom factor is changed, everything goes off the rails. The zoom > 1 also works as expected with no view offset and targeting the center of the frustum. I'm using TrackballControls but they shouldn't be at play here since I'm setting all values programatically.

The relevant camera update function that three in the PerspectiveCamera class is

    updateProjectionMatrix: function () {

        var near = this.near,
            top = near * Math.tan( _Math.DEG2RAD * 0.5 * this.fov ) / this.zoom,
            height = 2 * top,
            width = this.aspect * height,
            left = - 0.5 * width,
            view = this.view;

        if ( this.view !== null && this.view.enabled ) {

            var fullWidth = view.fullWidth,
                fullHeight = view.fullHeight;

            left += view.offsetX * width / fullWidth;
            top -= view.offsetY * height / fullHeight;
            width *= view.width / fullWidth;
            height *= view.height / fullHeight;

        }

        var skew = this.filmOffset;
        if ( skew !== 0 ) left += near * skew / this.getFilmWidth();

        this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far );

        this.projectionMatrixInverse.getInverse( this.projectionMatrix );

    },

My initial reaction is that the fov is for the full view but should be adjusted for sub-views or that I should be dividing the zoom by some factor derived from the sub-view size but I'm not sure where to start.


Solution

  • Figured it out.

    In my update function I was doing

        this.zoom = zoom;
    
        this.setViewOffset(
          full.w,
          full.h,
          offset.x,
          offset.y,
          offset.w,
          offset.h
        );
    
        this.controls.update();
    

    but what I needed to do was change the zoom so that it was relative to the offset

    this.zoom = zoom * (offset.h / full.h)