Feedback

What's your question?

By: [ Editor ] Asked from United Kingdom

Simulating defocus in a theoretical lens

Hi all,

I'm trying to figure out some maths at the moment, and was hoping someone might know what happens inside the theoretical camera lens...

What I'm trying to get a function for is, for a specified focal length/aperture, focused to a specified distance away, what sized area on the image plane will a point at a different specified distance be.

I'm planning on making a Defocus node where you set the defocus based on camera, lens and location information rather than just a pixel size.

I need to do a bit more checking on this, but this is what I understand so far:

The f/stop is defined as a ratio between the physical aperture and the focal length of the lens. So the actual aperture opening is the equivalent of:

aperture diameter = focal length x f-stop aperture distance (from image plane) = focal length

My question is this:

In this simplified model of the lens, where is the theoretical refraction point? There has to be some plane where the light rays are bent to ensure that they converge on the image plane. Is this fixed down, or can it vary between lenses? If it can vary between lenses, does this mean that different makes of lenses at the same focal length and aperture can have different sized bokeh?

I'm hoping that it will turn out that a lens can be simulated by bending the rays at the actual aperture plane, but it may well be a little more complex than that.

Thanks for any advice on this!

Edit: Solution

Thanks to Matt T for help on this one. I've put my Shake node below, for anyone who's interested.

This node allows you to specify the size and resolution of the sensor/film back. I didn't have the specs of the 35mm film back size to hand - I made it default to 24mmx18mm, which is close enough for now. You can also specify from a drop-down list what your units for focus and object distance are (all other units - sensor size, focal length - are assumed to be in mm)

CameraDefocus.h:

image CameraDefocus(image in = 0, float focalLength = 50, float fStop = 2.8, string distanceUnits = "feet", float focusDistance = 25.0, float objectDistance = 10.0, int sensorPixelsX = GetDefaultWidth(), int sensorPixelsY = GetDefaultHeight(), float sensorWidth = 24, float sensorHeight = 18.0)
{
Defocus1 = Defocus(in, defocusDiameter / pixelWidth, defocusDiameter / pixelHeight,
"rgba", 100, "circle", 0.95, 1,
    float pixelWidth = sensorWidth / sensorPixelsX,
    float pixelHeight = sensorHeight / sensorPixelsY,
    float distanceMultiplier = distanceUnits=="meters"?1000:distanceUnits=="feet"?304.8:distanceUnits=="inches"?25.4:1,
    float focusDistanceMM = focusDistance * distanceMultiplier,
    float objectDistanceMM = objectDistance * distanceMultiplier,
    float m = ((focusDistanceMM * focalLength) / (focusDistanceMM - focalLength)) / focusDistanceMM,
    float defocusDiameter = ((focalLength * m) / fStop) * (fabs(objectDistanceMM - focusDistanceMM) / objectDistanceMM)
    );

    return Defocus1;
}

CameraDefocusUI.h:

nuiPushMenu("Tools");
nuiPushToolBox("Filter");
    nuiToolBoxItem("@CameraDefocus",CameraDefocus());
nuiPopToolBox();
nuiPopMenu();

nuiDefSlider("CameraDefocus.focalLength",0,500,1);
nuiDefSlider("CameraDefocus.fStop",0,50,0.1);
nuxDefMultiChoice("CameraDefocus.distanceUnits", "meters|millimeters|feet|inches");
nuiDefSlider("CameraDefocus.focusDistance",0,1000,-1);
nuiDefSlider("CameraDefocus.objectDistance",0,1000,-1);
nuxDefSlider("CameraDefocus.sensorPixelsX",0,GetDefaultWidth(),1);
nuxDefSlider("CameraDefocus.sensorPixelsY",0,GetDefaultHeight(),1);
nuxDefSlider("CameraDefocus.sensorWidth", 0, 50, 0.1);
nuxDefSlider("CameraDefocus.sensorHeight", 0, 50, 0.1);

Add comment viewed 955 times Latest activity 7 months ago

or Cancel

4 answers

  • 4

matt t [ Editor ]

Hi Hugh,

I wrote a macro for Shake to do what you are asking a few years back using a modified 'Defocus' node. I agree with Andrew that you can treat any lens in this case as a simple thin lens. There are however slight variations in the maths depending on what sort of imaging you are using. ie the maths for macro work is different to telephoto work. However I found the differences are pretty negligable in practice so a general formula is fine.

A good reference site http://www.dofmaster.com/equations.html

General notes on the macro below.

1) All measurements in meters except focal length in mm 2) This is currently setup for 2k scans (2048x1556) of 35mm film. 3) I have arguably assumed the coc (circle of confusion) to be the width of a pixel at this resolution. Therefore this is an editable parameter. Any thoughts on this assumption would be welcome. 4) I have calculated the actual diameter of the blur spot as a ratio to coc so it should be flexible for all image formats. This means as I used a pixel to define my coc then the ratio equates to size in pixels of defocus. 5) I would love to get a definitive coc value for this macro by testing with real cameras and lenses, until then it it best to try the default value. 6) Disclaimer - I am not a programmer or a writer of code and this was created using Shake's internal macro maker. So apologies if the code is shabby:-). This has however been used on many top live action and cg movies over the last couple of years.

image CameraFocus(
image In=0,
float f_stop=4,
float focal_length=35,
float FocusDistance=5,
float ObjectDistance=5,
const char *channels="rgba",
const char *shape="circle",
float boostPoint=0.95,
float superWhite=1,
)
{
Defocus1 = Defocus(In, blur_spot_diam<CoC? 1 : blur_spot_diam/CoC, 
    xPixels, channels, 100, shape, boostPoint, superWhite, float CoC = 0.01215, 
    float f_stop = f_stop, float focal_length = focal_length, 
    float Hyperfocal = H/1000, float NearDistance = Dn/1000, 
    float FarDistance = Df/1000, float FocusDistance = FocusDistance, 
    float ObjectDistance = ObjectDistance, float H = (f*f)/(N*CoC), 
    float f = focal_length, float s = FocusDistance*1000, float Dn = (H*s)/(H+s), 
    float Df = (H*s)/(H-s), float N = f_stop, float blur_spot_diam = ((f*m)/N)*((fabs(o-s))/o), 
    float m = ((s*f)/(s-f))/s, float o = ObjectDistance*1000);

return Defocus1;

}

and the UI

nuiPushMenu("Tools");
nuiPushToolBox("User");
    nuiToolBoxItem(",CameraFocus());
nuiPopToolBox();
nuiPopMenu();

nuiDefSlider("CameraFocus.f_stop",0,64,0.1);
nuiDefSlider("CameraFocus.focal_length",0,500,1);
nuiDefSlider("CameraFocus.FocusDistance",0,1000,-1);
nuiDefSlider("CameraFocus.ObjectDistance",0,1000,-1);
nuiDefControlAlias("CameraFocus.shape","shape");
nuiDefSlider("CameraFocus.boostPoint",0,1,0);
nuiDefSlider("CameraFocus.superWhite",1,20,0);

Hopefully this will get you in the ballpark even if you are not working in Shake. I can deconstruct it a bit if you need it simplified. If you are using shake and would like the ZCameraFocus macro that uses a Z channel to create depth of field then give me a shout.

Cheers,

Matt

NN comments
hugh_gid
-

Very cool stuff, Matt! Thanks for posting that. I am, I think, going to want to try to understand what you’re doing there rather than just using it straight-off, but it’s good to see! I was (am) going to give the user controls for sensor size and resolution (so that they can still defocus an oversized image as if it were 2k 35mm)

I’m not sure I can give you more than one up vote, but if I could, I would!

matt t
-

Hugh, the main key to understanding it for me was that all equations you find are for systems in focus! Therefore I created a variable called ‘blurspotdiam’ which is the size of the coc circle of a system that is not in focus. The rest comes from using the known equations and a bit of pythagoras. Good luck!

hugh_gid
-

I’ve just edited my question with my own node that I’ve put together for this. It’s a little more extensive than yours – allowing different units for focus and object distance, and allowing you to specify the sensor size/resolution.

Thanks for the help!

or Cancel
  • 2

andrew marshall [ Editor ]

Usually image formation models make a simplifying assumption known as the "thin lens approximation". This assumption requires that the diameter of the lens is much greater than its curvature, which is true for most real lenses.

The point of this is that the model doesn't have to take account of the fact that the lens has two refraction points, one on entering and one on leaving the lens. Instead we assume that the lens is 'thin', and so the light is only refracted once. the plane of refraction is usually taken to lie through the centre of the lens.

Think of the image plane as slicing through a double cone representing the light coming through the lens, where the apex of the cone lies at a distance from the lens given by the thin lens equation ( the parameters of the equation are the focal length of the lens and the distance from the lens to the subject ). The amount of defocus is given by the cross section of the image cone.

or Cancel
  • 1

matt t [ Editor ]

Hugh,

here is another site with a better diagram and the equations you need to start with.

http://www.dof.pcraft.com/dof.cgi

In the first diagram what we are trying to find is what 'c' would be when we know all the other information and how it changes when we put in different values for 'f' focal_length, 'a' f-stop, 's' focus_distance and something I called object_distance (the distance from the lens of the object you are defocussing).

Cheers,

Matt

or Cancel