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",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
By:
matt t
[ Editor ]