REAL-WORLD CAMERA AND
SCENE MATCHING IN BLENDER
© 2007 K. G. Nyman

Part I : BLenses.py, a script for matching real camera characteristics with Blender’s camera
Part II: The theory and math behind BLenses.py, and tips for better scene matching

Addressing a need for accuracy

A thread on the blenderartists.org forum led me to investigate how Blender’s camera settings are related to real-world camera settings. The chief result of my research is the realization that the “Lens” setting of Blender’s camera (as of v.244) does not refer to a lens focal length in millimeters, even though a number of documentation sources refer to it as such, or imply that “Lens” is analogous to a lens focal length. Truth be told, I found a lot of forum comments implying that this setting has little or no relationship to any real-world camera parameter. As a result, many Blender users wishing to match a Blender scene to their film or digital camera images have met with a lot of frustration and confusion. This project is an attempt to remedy that situation.

A few years back I undertook a similar project for a Mac-based 3D modeller (Pixels Studio:3D), producing a script that would provide a field of view setting (FOV) that would match a given set of real-world camera parameters. FOV was that app’s only camera-view control variable at the time (pre-OSX).

Back then I did a lot of research into the concept of FOV as it relates to a number of photographic disciplines, and based my script on matching lenses with film sizes -- chiefly 35mm motion picture and still film formats. Popular digital photography was still an infant industry at the time, though there were many professional concerns beginning to use it. Now that digital photography has become aggressively mainstream, it seems time to update my earlier work to include digital formats, and to provide more accurate real-world camera and scene matching capabilities for Blender.

This site has two main sections, the first of which introduces the BLenses.py script and its operation within Blender. The second part covers all the math and theoretical underpinnings for the script, plus some recommendations about planning and executing live action shots that are intended to be composited with Blender renderings. The information in Part II about using the script with digital cameras is of particular importance, as it provides methods for calibrating the effective dimensions of a digital camera’s sensor, for greater accuracy when using the script.


PART I
BLenses.py, a script that modifies the Blender camera to use real-world camera parameters for scene matching

BLenses.py is a Python script written to automate modifications to the Blender camera. Its purpose is to make matching an actual lens focal length value and a real-world scene in Blender simpler and more accurate. While it does not give Blender a complete optical lens simulation, it does bring the Blender camera closer to the performance of a real-world camera than its default implementation, particularly in terms of perspective matching. In addition to implementing the lens focal length-to-field of view formulas described in Part II, the script has the option to create a useful new camera manipulation constraint, the point-of-interest, and with the addition of another script, BLensAnim.py, provides the means to animate the calculated focal length equivalent (zooms).


Download the BLenses scripts (ZIP archive)

FILE DISTRIBUTION: There are three files included in the ZIP archive, BLenses.py, BLensAnim.py, and BLensProfiles.cfg . The first two should be placed in the default scripts folder for your Blender installation, usually ...Blender\.blender\scripts\ . The third should be placed in the folder provided for Blender Registry Keys, usually ...Blender\.blender\scripts\bpydata\config\ . The script is designed to notify you if these files cannot be found. BLenses.py is registered to appear in the Blender Scripts menu under the Wizards category.

Version History:
V: 0.0.1 - First public release, 30-10-07
V: 0.0.2 - Patch for multi-OS path specifications, 31-10-07; no new functionality
V: 0.0.3 - Another patch for multi-OS path specifications, 5-11-07; no new functionality


As described more fully in Part II, the only parameter that a real-world camera and a virtual camera like Blender’s have in common is the field of view, or FOV. Therefore, the core operation of BLenses.py is to calculate a value for the FOV of a real camera in a specific shot setup, then set the Blender Camera’s FOV to match. This requires input of a number of parameters, and a common unit of metric measurement, usually millimeters.

The BLenses interface

The script will only run when there is a "current" camera in the current scene (see the Blender manual for info about the "current" camera). All BLenses functions operate only on the current camera; multiple cameras can be modified one at a time.

Lens Focal Length specifies the lens to be matched. This value is in millimeters, the common unit for specifying lens focal length (convert English measurements by multiplying a value in inches by 25.38). Blender's built-in value limits require that the range for this value be within 1 and 250 millimeters.

World Scale Unit sets an equivalency between Blender Units (B.U.) and one of three metric units -- the centimeter and meter scales make building large-scale Blender scenes possible by keeping some parameters within Blender's established limits for certain values. However, in all cases, the units for the Lens Focal Length and Image Aperture Width input must be in millimeters. The script uses the World Scale Unit to insure a common measure is used in all calculations, with millimeters being the fundamental unit.

Image Aperture Width is either input manually or chosen from the presets. This value is sometimes called “film width,” but actually refers to the width (larger dimension) of the area of film actually exposed, or the effective sensor width for a digital camera. Use millimeters for this value. Range is 5 to 260, sufficient for most common film or digital camera formats. Image Aperture Height refers to the lesser of the area's two dimensions.

Image Aspect Ratio can be set manually or calculated by BLenses. To calculate, input both Image Aperture Width and Image Aperture Height (making sure to use common units for both), then press the Calculate & Set Image A.R. button. NOTE: This aspect ratio is not the same as that specified in Blender’s Scene>Format panel -- that value refers to pixel proportions only.

Image Aperture / Camera Profile Presets accesses a list of preset values for specific film formats and/or camera specifications. Entries in the list have pre-calculated Image Aspect Ratios. New profiles can be added to the list using the Add Profile option at the top of the list. This is done in the Blender Text Editor. A non-formatting text editor can also be used. New profiles must follow a format that is explained in the profile list text. The list is automatically updated when a new profile is added. Profiles can be found in the BLensProfiles.cfg file in the default ...Blender\.blender\scripts\bpydata\config subfolder for your active Blender installation.

Camera to Subject distance is input in the World Scale Units specified earlier. The script will convert centimeter and meter values to millimeters for internal use. When an FOV is calculated, this value is used to set the current Camera's DoFDist parameter (more about this later).

Use Infinity Focus can be used for most target lenses if the real-world scene focus is at greater than about 30m. It does not require a Camera to Subject distance. When this option is enabled, the Interactive option (see below) is disabled.

Calculate & Set FOV returns a field-of-view (FOV) value in degrees that matches that of the real-world camera and scene described by the inputs. This value is used to set the current Camera's field of view (FOV) -- in scripting terms, it sets the Camera's "angle" attribute. The value is also reported at the bottom of the BLenses interface. See Final Notes, below, for information about how this value is reflected in Blender's native Camera panel. This button also enables the current Camera's Limits option so that the DoFDist mark can be seen, and may set the ClipEnd value to 50 units beyond the DoFDist mark value to insure that anything up to and somewhat beyond the Camera to Subject distance is not clipped.

If the Fixed option is selected, the FOV value will remain as initially set until reset using new BLenses inputs, or in Blender’s “native” Camera panel. The position of the DoFDist mark is unchanged.

If the Interactive option is selected, the FOV value can be recalculated according to any changes in the Blender scene’s camera-to-subject distance, i.e., by moving either the Camera or the POI constraint. Press the Interactive button at any time to recalculate the FOV. The current Camera's DoFDist will also be reset, placing it at the POI location.

Create POI adds a point of interest ( POI ) to the current camera, a TrackTo constraint at which the camera always points. An Empty is added to act as the constraint's target object. Both the constraint and its target Empty are named after the Camera the constraint is applied to. IMPORTANT: Since only one TrackTo constraint can be practically applied to a Camera, this operation replaces any existing TrackTo constraints with a POI constraint. This includes any POI constraints previously created. If a TrackTo constraint on the Camera already exists, you will be prompted to OK its replacement. The POI is required for the script's Interactive operation and Animation Mode (see below).

DeletePOI removes a POI constraint applied to the current camera. Always use this button to remove a camera's POI to insure that proper naming is applied to any replacement POI constraints added later. Any Ipo curves associated with the POI are also deleted.

Anim'n Mode prepares the current camera for animation of its focal length value (i.e., zooms) using the BLenses formulas. Because of current limitations to some of Blender's camera charactertistics, this requires creating an Empty to act as a "zoom proxy," which is named after the current camera ( 'Zoom_<CameraName>' ) -- whatever ScaleX value the zoom proxy has is used as the camera focal length. Creating an Ipo curve for the proxy's Scale thus also animates the camera's focal length.

Focal length animation also requires the establishment of a scriptlink -- a script that is run whenever certain actions take place in Blender. In BLenses Animation Mode a scriptlink to the script BLensAnim.py is set up -- camera FOV is recalculated and set by the linked script whenever the camera or its POI are moved in a 3D window, or when the frame number changes. The camera DoFDist is set to match the position of the camera POI constraint. Thus an animated focal point (e.g., for follow focus and rack focus effects) can be accomplished.

Anim'n Cancel removes the script links and deletes the zoom proxy for the current camera, thus removing the capability to animate its focal length with BLenses. Any Ipo curves associated with the zoom proxy are also removed. POI animations remain until the POI itself is deleted. IMPORTANT: Always use this button to cancel animation mode -- removing the zoom proxy and scriptlink "manually" may affect proper operation of the script.

Save Config saves a BLenses data set (in the form of a Blender Registry Key) to memory and disk, useful for multiple camera setups and for preserving settings between script sessions. Files are saved in the default ...Blender\.blender\scripts\bpydata\config subfolder for your active Blender installation. The default is to name the saved file after the current camera ( i.e., '<CameraName>_Data' ), but uniquely-named data sets can be saved if desired. See also the QUIT button, below.

Load Config replaces all current settings with those from a previously-saved configuration. In some cases, Blenses may ignore a loaded config value -- for example, if the config file did not record the Animation Mode option as enabled, loading it while currently in Animation Mode will not disable the mode, and the toggle will remain set.

QUIT exits the script, with the option to save the current settings to a configuration file as previously mentioned. All interface settings are lost unless saved. POI constraints remain in effect, as does Animation Mode if the script is quit while this mode is enabled. Activate the script again if there is a need to cancel Animation Mode or delete a POI constraint.

Render Width (convenience option) -- The aspect ratio of the image Blender renders must match that of the target camera’s image aperture. To simplify this matching, a Render Width can be input and the proper height to match the target Image Aspect Ratio can be calculated using the Calculate Render Size button. The result is not automatically used to set Blender’s render size; it is simply reported at the bottom of the interface panel. Note that due to rounding operations, the calculated render height may differ from an expected value by +/- one pixel.

IMPORTANT: BLenses.py is intended to simulate camera/lens combinations in scenes where the Camera to Subject distance is greater than 3x the target Lens Focal Length, which describes most scene setups. It should not be used to simulate lenses used for macro or micro shots (i.e., magnification 0.5 or greater), which require a different formula to calculate an accurate FOV. If unusual numbers show up (such as a negative FOV), check to make sure the camera is not too close to the subject, and check that an appropriate World Scale Unit is selected.

The following describes the script operations in more depth.

Using the POI constraint to manipulate Blender’s Camera

When setting up a shot in the real world, the camera is pointed at and focused most sharply on a single point in space, usually on what is of most interest in the scene, the camera’s point-of-interest. This may seem like a simplistic statement, but it describes a fundamental parameter of the lens-matching formula, the camera-to-subject distance, as well as describing the geometry of the relationship between camera and subject.

In Blender there is no default implementation of this aspect of a real world scene setup. The Blender Camera does have a Limits display for doing depth of field calculations, DoFDist, but this mark can’t be manipulated as freely as an object or empty can. It is, however, very useful when thought of as corresponding to the camera-to-subject distance. BLenses.py uses the value of DoFDist as the camera-to-subject distance when calculating a matching FOV.

However, it’s not trivial to use the DoFDist mark and direct Camera transforms to match a real-world setup -- many small tweaks to camera rotation have to be made to bring the DoFDist mark to the spot in the virtual scene that corresponds to the real-world setup, the real camera’s point-of-interest. This is similar to using a tripod and trying to match another setup exactly with only manual adjustments to the tripod head, and no data on the rotation values needed. Modern motion-control camera mounts can solve this problem, but how many Blender users have access to this kind of high-end equipment?

A lower-tech but still accurate solution is to make the camera’s point-of-interest a point in Blender space that can be moved along the Global axes, and have the camera always track to this point. In Blender this can be done with a Track To constraint, set up as shown at left.

This constraint can be made automatically by BLenses. It is named POI_<CameraName> and its target object (an Empty created for this purpose) is called the <CameraName>POI, where <CameraName> is the name of the Blender camera object being modified by BLenses. In the remainder of this text this constraint will be called the POI, and this refers to both the constraint and its target (which is what is actually used for manipulation). With the POI to control exactly where the camera is pointing, all questions of camera rotations are made transparent.

The POI can be used in a variety of ways depending on whether Fixed or Interactive mode is chosen to set the FOV:

For a Fixed FOV, the DofDist mark and the POI both lay along the Camera’s view axis, but do not interact. The POI can be moved to match the DoFDist point in space, for fixed-camera shot setup and the initial setup of a moving-camera and/or moving point-of-interest setup.

Interactively, the relative positions of the Camera and the POI are used to recalculate the DoFDist value, changing the position of the DoFDist mark to match any changes to the POI location. The calculated FOV is updated accordingly.

In Animation Mode, the POI can be moved at will, and the DoFDist mark is moved to its location "on-the-fly," allowing keyframing of the camera's focal point (FDist in the Camera-type Ipo channels list) based on real-time interactive positioning of either the camera or the POI. The FOV for the changing camera-to-subejct distance and the specified (or animated) focal length is calculated both interactively in the 3D window, and frame-by-frame for Timeline playback and renderings. The camera's focal length is animated by keyframing the ScaleX value of the camera's associated zoom proxy (Zoom_<CameraName>)

Image Aperture and Image Aspect Ratio: Putting the “film” in Blender’s camera

In the real world, a film gate (the mechanism that holds the film in place during exposure) and aperture mask (which limits the area of film exposed), or the useful area of a digital sensor chip, describe the physical recording area of a camera. The measure of this area provides the value for the real-world camera’s Image Aperture Width in the FOV formula. But nothing like this exists in Blender’s camera, so some other aspect of the Blender world must correspond to the real camera’s image aperture.

The render size in pixels, which at first may seem to be exactly what’s needed, isn’t directly useful, as this can change depending on the needs of a certain project. Some digital cameras can even provide different pixel dimensions for the same scene. So pixels by themselves can’t be used as an “aperture unit.”

However, regardless of actual pixel dimensions, renderings can share a common value, that of the image’s aspect ratio (AR), mentioned above and described in depth in Part II. A 640x480 and a 1280x960 image both have AR = 1.33 (using the simplest convention for expressing the ratio). Looking at it from the other direction (AR to pixels) a 16x9 widescreen format can have any number of pixel dimensions as long as the ratio of the dimensions = 16 / 9.

Handily, if the image aspect ratio of a rendering matches that of the real-world image aperture, then there’s no need to imitate actual physical dimensions of the real-world image aperture in Blender. Simply input the real-world Image Aperture Width (film or sensor width), specify an Image Aspect Ratio, match that aspect ratio in the rendering, and it all works. The interface has a number of useful presets for values of image aperture that also display the aspect ratio for that film format. Some of these may correspond to Blender’s preset rendering sizes.

Animating focal length: zooms and other camera effects

The "Lens" setting of the Blender camera can be animated directly using an Ipo curve of type "Camera." Unfortunately, this value as currently calculated by the Blender code is inaccurate for use as a focal length that matches a real-world camera lens. Compounding the problem is the lack of an Ipo channel to animate the camera's "angle" attribute, i.e., the FOV. So a workaround is necessary.

BLenses uses a proxy object, an Empty, whose Scale value (which can be animated using an Object-type Ipo curve) acts as a "stand in" for the camera's focal length value. While in Animation Mode, the BLensAnim.py linked script takes the ScaleX value from the "zoom proxy," uses it in the focal length-to-FOV formula, then applies the result to the current camera. The proxy is scripted to always follow the location of the camera it's associated with.

Multiple cameras can be put into Animation Mode, but the script will operate only on the current camera. Switching current cameras, even during Timeline playback or a rendering session, will also immediately enable the script for the new current camera, taking effect at whatever frame the Timeline happens to be at the time of the switch.

Camera effects such as rack focus, follow focus, and contra-zoom (see the bottom of Part II for some examples) can be accomplished by animating the camera, the focal length, and the POI (equivalent to the subject focal point of the lens) all at the same time. Actual focal blur effects are beyond the scope of BLenses, but because the camera's DoFDist attribute is made to follow the position of the POI constraint, this value, used in Blender's focal blur processes, can now be animated more flexibly by repositioning and keyframing the POI constraint target.

Once set up, Animation Mode does not require that the BLenses script be running -- its scriptlinks are independent of the main script. The BLenses main interface can be used to set a new focal length (or any other BLenses parameter) for the current camera if desired (the Interactive option is best for this purpose), but it can also be set by entering the desired value in the ScaleX property of the camera's zoom proxy.

As mentioned earlier, if the Animation Mode setup needs to be removed (zoom proxy deleted and scriptlinks disabled), use the BLenses interface to do so. This will ensure that the objects are removed in a manner that won't interfere with any future sessions using Animation Mode.

Saving BLenses settings as Registry Keys

The settings currently reflected in the BLenses interface can be saved at any time so the settings can be reused in future BLenses sessions. This is useful for multiple-camera setups, and for this reason, the default name of the file the settings are saved in refers to the camera current when the save is done. Any name can be used, but to keep things organized, make sure the names are unique and easily remembered -- there is no "Browse" capability.

IMPORTANT: Due to what may be a small bug in Blender's GUI controls for text input (which is what is used to give the data files their name), if the Escape key is used when the text input dialog is open, the text shown WILL be applied as the saved file's name. Overwrites require answering a prompt, but the guiding rule here is not to use the Escape key and assume the file was not saved -- it will have been. Always answer any pop-up prompts with a definitive click on an option, rather than trying to back out with the Escape key.


Some Final Notes

Once an FOV value is calculated and set by BLenses, Blender’s usual “Lens” setting is updated to reflect the new FOV. However, ignore this value! It will not match the focal length of the target lens because Blender’s calculations for this value are inaccurate for matching a real-world lens focal length. If the "Degrees" option is selected ("D" button), the displayed value will not reflect the actual current camera angle unless the value in the "Lens" setting is actually entered (disable "Degrees," click on the "Lens:" field and hit Return, then re-enable "Degrees"). Though somehwat confusing, this is due to the way the Blender code calculates the values shown in its native Camera panel. For this reason, it's probably best just to ignore these values while using BLenses -- the values shown in the script's interface are accurate.

For real-world scene matching, there doesn’t seem to be any usefulness in reporting a changing focal length based on changing FOV... FOV is not a real-world camera setting. It’s calculated from the geometry of the camera/lens/subject setup. So there is no provision in BLenses for reporting a focal length for a given FOV setting. While it’s quite possible to “run the math backwards,” the result would be of little value, since fractional values of focal length would often be the result. How would one find a 33.653mm lens, for example? If an actual target FOV is desirable, and a matching lens needs to be found, BLenses.py can be useful -- just try a number of “close-to-the-mark” focal length values until the FOV is as close as practical to the target. In this case, use the script’s Use Infinity Focus option, which is the basis for all nominal lens focal length values.



REAL-WORLD CAMERA AND SCENE MATCHING IN BLENDER Part II: The theory and math behind BLenses.py, and tips for better scene matching