0

I'm trying to visualize film camera crop and aspect ratio in Three.js. Please bear with me, it's a math problem, and I can't describe it in lesser words...

Instead of just using CameraHelper, I'm using three slightly modified CameraHelper objects for each camera. The helper lines can be seen when looking at a camera (cone), or when looking through a camera, the helper lines effectively create guide lines for the current camera.

  • Frame helper (bluish one with sides rendered). This is configured and supposed to be what an actual camera sees considering it's focal length and sensor or film dimensions. Calculated in getFOVFrame.

  • Monitor helper (white). Our frame aspect ratio here is 1.5. For example, if we plan to do a 2.35 (cinemascope) aspect ratio film with a camera of aspect ratio 1.5, this shows the crop area of the frame. So it needs to exactly fit the frame, with extra space either up and down or at the sides, but not both. Calculated in getFOVMonitor.

  • Screen helper (purple). We want full thing visible in the browser, and if the browser window dimensions/aspect ratio is different, we adjust the actual rendered Three.js camera so that it fits into the browser window and dimensions. So this helper always has the aspect ratio of current browser window, and focal length so that it fits the frame and monitor helper. Calculated in getFOVScreen

So based on our actual preferred camera (frame helper), we need to calculate the monitor camera and adjust it's fov that it exactly fits inside frame camera. Then we also need to calculate the screen camera and adjust it's fov that the frame camera exactly fits inside.

My current solution appears almost correct, but there is something wrong. With long lenses (small fov, big focal length) it seems correct:

  • Looking through, looks correct: http://toppinen.net/projects/so/so_fov/Clipboard-6.png
  • Both the current camera, and the camera in front look about correct: enter image description here
  • Looking through, looks correct: enter image description here

But at wide lenses (big fov, small focal length) the solution starts to break, there is extra space around the white monitor helper, for example:

  • Looking through, the white box should touch the bluish one from the sides: enter image description here
  • Both the current camera, and the camera in front look wrong, the white boxes should touch the sides of blue box (both have very wide lens): enter image description here
  • Looking through (very wide lens), looks wrong, white box should touch blue box and blue box should touch purple box: enter image description here

So I think I'm calculating the various cameras wrong, although the result seems almost "close enough".

Here's the code that returns the vertical FOV, horizontal HFOV and aspect ratio, which are then used to configure the cameras and helpers:

// BLUE camera fov, based on physical camera settings (sensor dimensions and focal length)
var getFOVFrame = function() {
  var fov = 2 * Math.atan( sensor_height / ( focal_length * 2 ) ) * ( 180 / Math.PI );
  return fov;
}
var getHFOVFrame = function() {
  return getFOVFrame() * getAspectFrame();
}

// PURPLE screen fov, should be able to contain the frame
var getFOVScreen = function() {
  var fov = getFOVFrame();
  var hfov = fov * getAspectScreen();
  if (hfov < getHFOVFrame()) {
    hfov = getHFOVFrame();
    fov = hfov / getAspectScreen();
  }  
  return fov;
}
var getHFOVScreen = function() {
  return getFOVScreen() * getAspectScreen();
}

// WHITE crop area fov, should fit inside blue frame camera
var getFOVMonitor = function() {
  var fov = getFOVFrame();      
  var hfov = fov * getAspectMonitor();
  if (hfov > getHFOVFrame())   {
    hfov = getHFOVFrame();
    fov = hfov / getAspectMonitor();
  }
  return fov;
}
var getHFOVMonitor = function() {
  return getFOVMonitor() * getAspectMonitor();
}

var getAspectScreen = function() {
  return  screen_width / screen_height;
}

var getAspectFrame = function() {
  return  sensor_width / sensor_height;
}

var getAspectMonitor = function() {
  return monitor_aspect;
}

Why does this produce incorrect results when using large FOV / wide lenses? getFOVScreen and especially getFOVMonitor are the suspects.

4

1 回答 1

2

你的等式var hfov = fov * getAspectScreen();不正确。

垂直 FOV ( vFOV) 和水平 FOV ( hFOV) 之间的关系由以下等式给出:

hFOV = 2 * Math.atan( Math.tan( vFOV / 2 ) * aspectRatio );

同样,

vFOV = 2 * Math.atan( Math.tan( hFOV / 2 ) / aspectRatio );

在这些方程中,vFOVhFOV以弧度表示;aspectRatio = width / height.

在three.js 中,PerspectiveCamera.fov是垂直的,以度为单位。

三.js r.59

于 2013-07-24T16:59:25.450 回答