Functions to calculate the visible width / height at a given z-depth from a perspective camera

Looks like some of the above codepens I posted broke. I need to update them. Nowadays I make sure to use versioned URLs to make sure demos don’t break.

I updated all the above pens so they work now. I used specific versions in the code to make sure they rely on the proper versions, like this:

import * as THREE from 'https://unpkg.com/three@0.116.1/build/three.module.js'
import {OrbitControls} from 'https://unpkg.com/three@0.116.1/examples/jsm/controls/OrbitControls.js'

@looeee Do you mind updating your two codepens above? These are your pens updated to use specific versions:

1 Like

Hi
I am new to 3d graphics/rendering so apologies in advance
Do you think this is possible for orthographic camera

This fits good on Mobile device, both Android WebView and iOS webkit. You definitely knows the logic behind it. Good job, man.

1 Like

With an OrthographicCamera, objects don’t get smaller when they go further away from the camera so this trick doesn’t work.

What you would need to do is make sure the ortho camera box dimensions are the size of the object, or scale the object to fit the size of the camera box. This is easier than the above with perspective camera, you just need a multiplier.

For example, if your ortho cam width and height are both 10, and the object width/height is 5, then you need to scale the object by 2 so it fits on the screen (or reduce the camera width/height to 5). Simple as that.

In case it helps anyone, here’s how to fit an object (most likely a flat plane) on the screen so that it “fits” depending on aspect ratio. For example, if we have an object taller than it is wide we want the Y dimension (the tall dimension) to fit within the view, but if the object is wider than it is tall we want the X dimension (the width dimension) to fit within view.

The following distanceToFitObjectToView function will tell you at what distance to place the object so that it fits within view regardless which dimension is bigger:

(The code has TypeScript type annotations, but you can remove them, f.e. the : number stuff)

/**
 * Convert vertical field of view to horizontal field of view, given an aspect
 * ratio. See https://arstechnica.com/civis/viewtopic.php?f=6&t=37447
 *
 * @param vfov - The vertical field of view.
 * @param aspect - The aspect ratio, which is generally width/height of the viewport.
 * @returns - The horizontal field of view.
 */
function vfovToHfov(vfov: number, aspect: number): number {
  const {tan, atan} = Math
  return atan(aspect * tan(vfov / 2)) * 2
}

/**
 * Get the distance from the camera to fit an object in view by either its
 * horizontal or its vertical dimension.
 *
 * @param size - This should be the width or height of the object to fit.
 * @param fov - If `size` is the object's width, `fov` should be the horizontal
 * field of view of the view camera. If `size` is the object's height, then
 * `fov` should be the view camera's vertical field of view.
 * @returns - The distance from the camera so that the object will fit from
 * edge to edge of the viewport.
 */
function _distanceToFitObjectInView(size: number, fov: number): number {
  const {tan} = Math
  return size / (2 * tan(fov / 2))
}

function distanceToFitObjectToView(
  cameraAspect: number,
  cameraVFov: number,
  objWidth: number,
  objHeight: number
): number {
  const objAspect = objWidth / objHeight
  const cameraHFov = vfovToHfov(cameraVFov, cameraAspect)

  let distance: number = 0

  if (objAspect > cameraAspect) {
    distance = _distanceToFitObjectInView(objHeight, cameraVFov)
  } else if (objAspect <= cameraAspect) {
    distance = _distanceToFitObjectInView(objWidth, cameraHFov)
  }

  return distance
}
1 Like

Oops! I forgot to include the vfovToHfov function. Updated the above post.