Skip to main content

Camera Types

Threebox supports two camera types: Perspective (default) and Orthographic. Each offers different visual characteristics for your 3D scene.

Perspective Camera (Default)

The default camera type uses Three.js PerspectiveCamera with customizable field of view (FOV).

Field of View (FOV)

Control the camera’s FOV to adjust the viewing angle:
Threebox.js:79-80
this.fov = this.options.fov;
this.orthographic = this.options.orthographic || false;
window.tb = new Threebox(
  map,
  map.getCanvas().getContext('webgl'),
  {
    defaultLights: true,
    fov: 37  // Default from ThreeboxConstants.FOV_DEGREES
  }
);

FOV Property

The fov property can be set dynamically:
Threebox.js:585-596
get fov() {
  return this.options.fov;
}

set fov(value) {
  if (this.camera instanceof THREE.PerspectiveCamera && this.options.fov !== value) {
    this.map.transform.fov = value;
    this.camera.fov = this.map.transform.fov;
    this.cameraSync.setupCamera();
    this.map.repaint = true;
    this.options.fov = value;
  }
}
FOV Limitations:
  • Valid range: 0.01 to 60 degrees (Mapbox limitation)
  • Below 2.5 degrees: Serious polygon and depth issues
  • Above 45 degrees: Clipping and performance problems
  • Minimum value of 0 becomes 0.01 automatically

Orthographic Camera

Orthographic projection displays objects without perspective distortion, useful for architectural or technical visualizations.

Enabling Orthographic View

window.tb = new Threebox(
  map,
  map.getCanvas().getContext('webgl'),
  {
    defaultLights: true,
    orthographic: true  // Enable orthographic camera
  }
);

Implementation Details

Threebox.js:598-620
get orthographic() {
  return this.options.orthographic;
}

set orthographic(value) {
  const h = this.map.getCanvas().clientHeight;
  const w = this.map.getCanvas().clientWidth;
  
  if (value) {
    // Switch to orthographic camera
    this.map.transform.fov = 0;
    this.camera = new THREE.OrthographicCamera(
      w / -2, w / 2, h / 2, h / -2, 0.1, 1e21
    );
  } else {
    // Switch to perspective camera
    this.map.transform.fov = this.fov;
    this.camera = new THREE.PerspectiveCamera(
      this.map.transform.fov, w / h, 0.1, 1e21
    );
  }
  
  this.camera.layers.enable(0);
  this.camera.layers.enable(1);
  
  this.cameraSync = new CameraSync(this.map, this.camera, this.world);
  this.map.repaint = true;
  this.options.orthographic = value;
}

Runtime Camera Switching

// Start with perspective
window.tb = new Threebox(map, gl, { orthographic: false });

// Switch to orthographic
tb.orthographic = true;

// Switch back to perspective
tb.orthographic = false;
Switching camera types at runtime recreates the camera and camera sync objects.

Camera Compatibility

With Fill-Extrusions

Orthographic + Fill-Extrusions:Pure orthographic view (FOV = 0) is not fully supported by Mapbox and causes:
  • Polygon rendering issues
  • Depth calculation problems
  • Fill-extrusion artifacts
Solution: Use orthographic: false with fov: 2.5 for near-orthographic view compatible with fill-extrusions.
// Orthographic-like view compatible with fill-extrusions
window.tb = new Threebox(
  map,
  map.getCanvas().getContext('webgl'),
  {
    defaultLights: true,
    orthographic: false,  // Keep perspective camera
    fov: 2.5              // Minimal FOV for near-orthographic look
  }
);

Camera Configuration Matrix

Use CaseorthographicfovNotes
Default 3Dfalse37Standard perspective view
Wide Anglefalse45-60Wider view, may have clipping
Narrow Viewfalse15-30Closer to orthographic feel
Near-Ortho + Fill-Extrusionsfalse2.5Minimal perspective, compatible
Pure OrthographictrueN/ANo fill-extrusions support
Technical/ArchitecturaltrueN/APure orthographic, 3D objects only

Best Practices

3D Models Only

Use orthographic: true when working exclusively with 3D models

With Fill-Extrusions

Use orthographic: false, fov: 2.5 for near-orthographic with fill-extrusions

Wide Scenes

Use moderate FOV (30-45) for large area visualization

Detail Work

Use lower FOV (15-30) for focused, detailed views

Advanced Example

let map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v11',
  center: [-74.0066, 40.7135],
  zoom: 16,
  pitch: 60
});

let tb = new Threebox(
  map,
  map.getCanvas().getContext('webgl'),
  {
    defaultLights: true,
    orthographic: false,
    fov: 28  // Comfortable middle ground
  }
);

// Camera control UI
const cameraControls = {
  perspective: () => {
    tb.orthographic = false;
    tb.fov = 37;
  },
  
  nearOrthographic: () => {
    tb.orthographic = false;
    tb.fov = 2.5;
  },
  
  orthographic: () => {
    tb.orthographic = true;
  },
  
  wideAngle: () => {
    tb.orthographic = false;
    tb.fov = 50;
  }
};

// Bind to UI buttons
document.getElementById('perspective').onclick = cameraControls.perspective;
document.getElementById('ortho').onclick = cameraControls.orthographic;

Camera Sync

Both camera types use the CameraSync class to synchronize with Mapbox camera:
Threebox.js:612-616
this.cameraSync = new CameraSync(
  this.map,
  this.camera,
  this.world
);
The CameraSync handles:
  • Camera movement synchronization
  • Zoom level adjustments
  • Pitch and bearing updates
  • Projection matrix calculations
Camera changes trigger map.repaint = true automatically to ensure the scene re-renders.

Build docs developers (and LLMs) love