Dof shader in Mogre        

The "depth of field" (DOF) is the distance between the nearest and farthest objects in a scene that appear acceptably sharp in an image" (Wikipedia). It is a quite impressive technique. It bases on this c++ implementation and the slightly modified version of Polygon9.

Info For questions, bug reports, etc. use this Mogre forum topic or if it's shader related Ogre forum topic.

Showcase and demo

The demo download link (external, c++ version, may not work with dx9)
http://dword.dk/blog/software/ogre/dof/

Screenshots

click for image mode ..... and then ..... click again to switch to the next pictures
click for image mode ..... and then ..... click again to switch to the next pictures
click to enlarge
click to enlarge
click to enlarge
click to enlarge


Implementation

First copy and paste the code below in two code files (you could create an empty code files in VS). There is a VB.Net and a C# version.
The "DepthOfFieldEffect.vb" or "DepthOfFieldEffect.cs" file:

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Mogre;

public class DepthOfFieldEffect : RenderQueue.RenderableListener
{

	//   Inherits CompositorInstance.Listener, RenderTargetListener, RenderQueue.RenderableListener

	private RenderTargetListener RenderTargetListener;
	private CompositorInstance.Listener Listener;
	private RenderQueue.RenderableListener RenderableListenerBackup;
	private uint mWidth;
	private uint mHeight;
	private Viewport mViewPort;
	private Camera mCamera;
	private Viewport mDepthViewport;
	private RenderTexture mDepthTarget;
	private TexturePtr mDepthTexture;
	private MaterialPtr mDepthMaterial;
	private Technique mDepthTechnique;
	private CompositorInstance mCompositor;
	private float mNearDepth;
	private float mFocalDepth;
	private float mFarDepth;

	private float mFarBlurCutoff;


	private const int BLUR_DIVISOR = 4;
	public DepthOfFieldEffect(Viewport Viewport, Camera Camera)
	{
		mViewPort = Viewport;
		mCamera = Camera;
		mNearDepth = 10.0;
		mFocalDepth = 100.0;
		mFarDepth = 190.0;
		mFarBlurCutoff = 1.0;
		mWidth = Convert.ToUInt32(Viewport.ActualWidth());
		mHeight = Convert.ToUInt32(Viewport.ActualHeight());

		mCompositor = null;
		mDepthTechnique = null;
		mDepthTarget = null;
		mDepthViewport = null;
		mDepthTexture = null;
		mDepthMaterial = null;



		createDepthRenderTexture();
		addCompositor();
	}
	public void Destroy()
	{
		removeCompositor();
		destroyDepthRenderTexture();
	}

	//C++ TO VB CONVERTER WARNING: 'const' methods are not available in VB:
	//ORIGINAL LINE: Single getNearDepth() const
	public float getNearDepth()
	{
		return mNearDepth;
	}
	//C++ TO VB CONVERTER WARNING: 'const' methods are not available in VB:
	//ORIGINAL LINE: Single getFocalDepth() const
	public float getFocalDepth()
	{
		return mFocalDepth;
	}
	//C++ TO VB CONVERTER WARNING: 'const' methods are not available in VB:
	//ORIGINAL LINE: Single getFarDepth() const
	public float getFarDepth()
	{
		return mFarDepth;
	}
	public void setFocalDepths(float nearDepth, float focalDepth, float farDepth)
	{
		mNearDepth = nearDepth;
		mFocalDepth = focalDepth;
		mFarDepth = farDepth;
	}
	//C++ TO VB CONVERTER WARNING: 'const' methods are not available in VB:
	//ORIGINAL LINE: Single getFarBlurCutoff() const
	public float getFarBlurCutoff()
	{
		return mFarBlurCutoff;
	}
	public void setFarBlurCutoff(float cutoff)
	{
		mFarBlurCutoff = cutoff;
	}
	//C++ TO VB CONVERTER WARNING: 'const' methods are not available in VB:
	//ORIGINAL LINE: Boolean getEnabled() const
	public bool getEnabled()
	{
		return mCompositor.Enabled();
	}
	public void setEnabled(bool value)
	{
		mCompositor.Enabled = value;
	}

	// Implementation of Ogre::CompositorInstance::Listener

	private void notifyMaterialSetup(UInt32 passId, MaterialPtr material)
	{
		switch ((PassId)passId) {
			case DepthOfFieldEffect.PassId.BlurPass:
				//float pixelSize[2] = {
				//	1.0f / (mViewport->getActualWidth() / BLUR_DIVISOR),
				//	1.0f / (mViewport->getActualHeight() / BLUR_DIVISOR)};

				// Adjust fragment program parameters
				Vector3 ps = new Vector3(1f / (mWidth / BLUR_DIVISOR), 1f / (mHeight / BLUR_DIVISOR), 1f);
				float[] pixelSize = {
					ps.x,
					ps.y,
					ps.z
				};
				GpuProgramParametersSharedPtr fragParams = material.GetBestTechnique().GetPass(Convert.ToUInt16(0)).GetFragmentProgramParameters();
				if ((((fragParams != null))) && (!fragParams._findNamedConstantDefinition("pixelSize").IsNull)) {
					fragParams.SetNamedConstant("pixelSize", ps);
				}

				break; // TODO: might not be correct. Was : Exit Select


				break;
			case DepthOfFieldEffect.PassId.OutputPass:
				float[] pixelSizeScene = {
					1f / mWidth,
					1f / mHeight,
					0
				};
				Vector3 pixelSizeSceneV = new Vector3(pixelSizeScene[0], pixelSizeScene[1], pixelSizeScene[2]);

				float[] pixelSizeBlur = {
					1f / (mWidth / BLUR_DIVISOR),
					1f / (mHeight / BLUR_DIVISOR),
					0
				};
				Vector3 pixelSizeBlurV = new Vector3(pixelSizeBlur[0], pixelSizeBlur[1], pixelSizeBlur[2]);
				// Adjust fragment program parameters
				GpuProgramParametersSharedPtr fragParams = material.GetBestTechnique().GetPass(Convert.ToUInt16(0)).GetFragmentProgramParameters();
				if ((((fragParams != null))) && (!fragParams._findNamedConstantDefinition("pixelSizeScene").IsNull)) {
					fragParams.SetNamedConstant("pixelSizeScene", pixelSizeSceneV);
				}
				if ((((fragParams != null))) && (!fragParams._findNamedConstantDefinition("pixelSizeBlur").IsNull)) {
					fragParams.SetNamedConstant("pixelSizeBlur", pixelSizeBlurV);
				}

				break; // TODO: might not be correct. Was : Exit Select

				break;
		}
	}

	// Implementation of Ogre::RenderTargetListener

	private void preViewportUpdate(RenderTargetViewportEvent_NativePtr evt)
	{
		float[] dofParams = {
			mNearDepth,
			mFocalDepth,
			mFarDepth,
			mFarBlurCutoff
		};
		Vector4 dofParamsM = new Vector4(dofParams[0], dofParams[1], dofParams[2], dofParams[3]);
		// Adjust fragment program parameters for depth pass
		GpuProgramParametersSharedPtr fragParams = mDepthTechnique.GetPass(Convert.ToUInt16(0)).GetFragmentProgramParameters();

		if ((((fragParams != null))) && !(fragParams._findNamedConstantDefinition("dofParams").IsNull)) {
			fragParams.SetNamedConstant("dofParams", dofParamsM);
		}

		// Add 'this' as a RenderableListener to replace the technique for all renderables
		RenderQueue queue = evt.source.Camera().SceneManager().RenderQueue();

		queue.SetRenderableListener(this);
	}
	private void postViewportUpdate(RenderTargetViewportEvent_NativePtr evt)
	{
		// Reset the RenderableListener
		RenderQueue queue = evt.source.Camera.SceneManager().RenderQueue();
		queue.SetRenderableListener(null);
	}

	// Implementation of Ogre::RenderQueue::RenderableListener
	public override bool RenderableQueued(global::Mogre.IRenderable rend, byte groupID, ushort priority, ref global::Mogre.Technique ppTech, global::Mogre.RenderQueue pQueue)
	{
		// Replace the technique of all renderables
		ppTech = mDepthTechnique;
		return true;
	}

	private enum PassId : uint
	{
		BlurPass = 666,
		OutputPass = 667
	}


	private void createDepthRenderTexture()
	{
		// Create the depth render texture
		mDepthTexture = TextureManager.Singleton().CreateManual("DoF_Depth", ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D, mWidth, mHeight, 0, PixelFormat.PF_L8, TextureUsage.TU_RENDERTARGET);

		// Get its render target and add a viewport to it
		mDepthTarget = mDepthTexture.GetBuffer().GetRenderTarget();
		mDepthViewport = mDepthTarget.AddViewport(mCamera);

		// Register 'this' as a render target listener

		mDepthTarget.PreViewportUpdate += preViewportUpdate;
		mDepthTarget.PostViewportUpdate += postViewportUpdate;

		// Get the technique to use when rendering the depth render texture
		mDepthMaterial = MaterialManager.Singleton().GetByName("DoF_Depth");
		mDepthMaterial.Load();
		// needs to be loaded manually
		mDepthTechnique = mDepthMaterial.GetBestTechnique();

		// Create a custom render queue invocation sequence for the depth render texture
		RenderQueueInvocationSequence invocationSequence = Root.Singleton().CreateRenderQueueInvocationSequence("DoF_Depth");

		// Add a render queue invocation to the sequence, and disable shadows for it
		RenderQueueInvocation invocation = invocationSequence.Add(Convert.ToByte(RenderQueueGroupID.RENDER_QUEUE_MAIN), "main");
		invocation.SuppressShadows = true;

		// Set the render queue invocation sequence for the depth render texture viewport
		mDepthViewport.RenderQueueInvocationSequenceName = "DoF_Depth";

		//re-set texture "DoF_Depth"
		MaterialPtr p = MaterialManager.Singleton().GetByName("DoF_DepthOfField");
		p.Load();
		p.GetBestTechnique().GetPass(Convert.ToUInt16(0)).GetTextureUnitState("depth").SetTextureName("DoF_Depth");
		p.Unload();
	}
	private void destroyDepthRenderTexture()
	{
		mDepthViewport.RenderQueueInvocationSequenceName = "";

		Root.Singleton().DestroyRenderQueueInvocationSequence("DoF_Depth");

		mDepthMaterial.Unload();

		mDepthTarget.RemoveAllListeners();
		mDepthTarget.RemoveAllViewports();
		//TextureManager::getSingleton().unload("DoF_Depth");
		TextureManager.Singleton().Remove("DoF_Depth");
	}
	//	void createCompositor();
	//	void destroyCompositor();
	private void addCompositor()
	{
		mCompositor = CompositorManager.Singleton().AddCompositor(mViewPort, "DoF_Compositor_test");

		mCompositor.NotifyMaterialSetup += this.notifyMaterialSetup;


		mCompositor.Enabled = true;
	}
	private void removeCompositor()
	{
		mCompositor.Enabled = false;
		mCompositor.NotifyMaterialSetup -= this.notifyMaterialSetup;

		CompositorManager.Singleton().RemoveCompositor(mViewPort, "DoF_Compositor_test");
	}
}

public class DOFManager
{

	private Camera mCamera;
	private RenderWindow mWindow;
	private SceneManager mSceneManager;
	private float cooldown = 0.25;
	public delegate float RequestFocalDistance();
	public RequestFocalDistance DelegateRequestFocalDistance { get; set; }

	/////////////////////////////////////////////////////////////////////////////////////
	public DOFManager(Viewport Viewport, Camera Camera, RenderWindow RenderWindow, SceneManager SceneManager)
	{
		mCamera = Camera;
		mWindow = RenderWindow;
		mSceneManager = SceneManager;
		mFocusMode = FocusMode.Auto;
		mAutoSpeed = 999;
		mAutoTime = cooldown;
		targetFocalDistance = 5;

		mDepthOfFieldEffect = new DepthOfFieldEffect(Viewport, Camera);
		mLens = new Lens(Camera.FOVy, 1);
		mLens.setFocalDistance(5);
		//mLens->setFStop(10);
		//	mDepthOfFieldEffect->setEnabled(false);


		Root.Singleton.FrameStarted += frameStarted;
		//	MaterialPtr material = MaterialManager::getSingleton().getByName("DoF_DepthDebug");
		//	material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("DoF_Depth");
		//	Overlay* overlay = OverlayManager::getSingleton().getByName("DoF_DepthDebugOverlay");
		//	overlay->show();
	}
	public void Dispose()
	{
		cleanup();
	}


	public void setEnabled(bool enabled)
	{
		mDepthOfFieldEffect.setEnabled(enabled);
		//
		//	// crashes for some reason
		//	if(enabled && !mDepthOfFieldEffect->getEnabled())
		//	{
		//		// turn on
		//		mDepthOfFieldEffect->setEnabled(true);
		//		mRoot->addFrameListener(this);
		//	} else if(!enabled && mDepthOfFieldEffect->getEnabled())
		//	{
		//		// turn off
		//		mDepthOfFieldEffect->setEnabled(false);
		//		mRoot->removeFrameListener(this);
		//	}
		//
	}
	public bool getEnabled()
	{
		return mDepthOfFieldEffect.getEnabled();
	}

	// controls
	public void setFocusMode(FocusMode mode)
	{
		mFocusMode = (FocusMode)mode;
	}
	public void setAutoSpeed(float f)
	{
		mAutoSpeed = f;
	}
	public void zoomView(float delta)
	{
		float fieldOfView = mLens.getFieldOfView().ValueRadians();
		fieldOfView += delta;
		fieldOfView = Convert.ToSingle(System.Math.Max(0.1, System.Math.Min(fieldOfView, 2.0)));
		mLens.setFieldOfView(new Radian(fieldOfView));
		mCamera.FOVy = (new Radian(fieldOfView));
	}
	public void Aperture(float delta)
	{
		if (mFocusMode == FocusMode.Pinhole) {
			return;
		}
		float fStop = mLens.getFStop();
		fStop += delta;
		fStop = Convert.ToSingle(System.Math.Max(0.5, System.Math.Min(fStop, 12.0)));
		mLens.setFStop(fStop);
	}
	public void moveFocus(float delta)
	{
		mLens.setFocalDistance(mLens.getFocalDistance() + delta);
	}
	public void setZoom(float f)
	{
		float fieldOfView = new Degree(f).ValueRadians();
		fieldOfView = Convert.ToSingle(System.Math.Max(0.1, System.Math.Min(fieldOfView, 2.0)));
		mLens.setFieldOfView(new Radian(fieldOfView));
		mCamera.FOVy = new Radian(fieldOfView);
	}
	public void setAperture(float f)
	{
		if (mFocusMode == FocusMode.Pinhole) {
			return;
		}
		float fStop = f;
		fStop = Convert.ToSingle(System.Math.Max(0.5, System.Math.Min(fStop, 12.0)));
		mLens.setFStop(fStop);
	}
	public void setFocus(float f)
	{
		mLens.setFocalDistance(f);
	}

	//C++ TO VB CONVERTER TODO TASK: The implementation of the following method could not be found:
	//	virtual Function frameStarted(ByVal evt As Ogre::FrameEvent) As Boolean

	protected void cleanup()
	{
		Root.Singleton.FrameStarted -= frameStarted;

		mLens.Dispose();
		mLens = null;

		mDepthOfFieldEffect.Destroy();
		mDepthOfFieldEffect = null;
	}
	protected DepthOfFieldEffect mDepthOfFieldEffect;
	protected Lens mLens;
	public enum FocusMode
	{
		Auto,
		Manual,
		Pinhole
	}
	protected FocusMode mFocusMode;
	protected float mAutoSpeed;
	protected float mAutoTime;
	protected float targetFocalDistance = new float();
	private class Result
	{
		public Vector3 Position { get; set; }
		public Entity Entity { get; set; }
		public float Distance { get; set; }
	}
	private Result RaycastFromCamera(RenderWindow window, Camera camera, Vector2 point, SceneManager SceneManager, UInt32 queryMask)
	{
		Result functionReturnValue = null;
		float tx = (point.x / Convert.ToSingle(window.Width));
		float ty = (point.y / Convert.ToSingle(window.Height));
		Ray ray = camera.GetCameraToViewportRay(tx, ty);

		RaySceneQuery raySceneQuery = SceneManager.CreateRayQuery(ray, queryMask);
		raySceneQuery.SetSortByDistance(true);
		raySceneQuery.Execute();
		object Results = raySceneQuery.GetLastResults;
		if (Results == null || Results.IsEmpty) {
			SceneManager.DestroyQuery(raySceneQuery);
			raySceneQuery.Dispose();
			return null;
		} else {
			for (int i = 0; i <= Results.Count - 1; i++) {
				object obj = Results.Item(i);
				if (obj.movable != null && obj.movable is Entity) {
					functionReturnValue = new Result {
						Distance = obj.distance,
						Entity = (Entity)obj.movable,
						Position = ray.GetPoint(obj.distance)
					};
					SceneManager.DestroyQuery(raySceneQuery);
					raySceneQuery.Dispose();
					return functionReturnValue;
				}
			}
			SceneManager.DestroyQuery(raySceneQuery);
			raySceneQuery.Dispose();
			return null;
		}
		return functionReturnValue;
	}
	public bool frameStarted(FrameEvent evt)
	{
		Camera camera = mCamera;
		// Focusing
		if (this.getEnabled() == false)
			return true;
		switch (mFocusMode) {
			case FocusMode.Auto:
				// TODO: Replace with accurate ray/triangle collision detection
				float currentFocalDistance = mLens.getFocalDistance();

				// TODO: Continous AF / triggered
				mAutoTime -= evt.timeSinceLastFrame;
				if (mAutoTime <= 0f) {
					mAutoTime = cooldown;

					targetFocalDistance = currentFocalDistance;

					//' Ryan Booker's (eyevee99) ray scene query auto focus
					//Dim focusRay As New Ray()
					//focusRay.Origin = (camera.DerivedPosition())
					//focusRay.Direction = (camera.DerivedDirection())
					//Dim v As New Vector3()
					//Dim vn As New Vector3()
					//Dim e As Entity
					//Dim d As Single

					if (DelegateRequestFocalDistance != null) {
						targetFocalDistance = DelegateRequestFocalDistance.Invoke();
					} else {
						object r = RaycastFromCamera(mWindow, mCamera, new Vector2(Convert.ToSingle(mWindow.Width / 2), Convert.ToSingle(mWindow.Height / 2)), mSceneManager, 1 << 2);

						if (r != null) {
							targetFocalDistance = r.Distance;
						}
					}


				}

				// Slowly adjust the focal distance (emulate auto focus motor)
				if (currentFocalDistance < targetFocalDistance) {
					mLens.setFocalDistance(System.Math.Min(currentFocalDistance + mAutoSpeed * evt.timeSinceLastFrame, targetFocalDistance));
				} else if (currentFocalDistance > targetFocalDistance) {
					mLens.setFocalDistance(System.Math.Max(currentFocalDistance - mAutoSpeed * evt.timeSinceLastFrame, targetFocalDistance));
				}

				break;


			case FocusMode.Manual:
				break;
			//we set the values elsewhere
		}

		// Update Depth of Field effect
		if (mFocusMode != FocusMode.Pinhole) {
			mDepthOfFieldEffect.setEnabled(true);

			// Calculate and set depth of field using lens
			float nearDepth = 0;
			float focalDepth = 0;
			float farDepth = 0;
			mLens.recalculateDepthOfField(nearDepth, focalDepth, farDepth);
			mDepthOfFieldEffect.setFocalDepths(nearDepth, focalDepth, farDepth);
		} else {
			mDepthOfFieldEffect.setEnabled(false);
		}

		return true;
	}
}


The "Lens.vb" or "Lens.cs" file:

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Mogre;


public class Lens
{
	// NOTE: All units must be the same, eg mm, cm or m etc
	// Primary attributes
		// Film stock/sensor size, arbitrarily selected to help mimic the properties of film, eg 35mm, 3.5cm, 0.035m etc
	protected float mFrameSize = new float();
		// The area within which the depth of field is clear, it's tied to frame size, eg 0.03mm, 0.003cm, 0.0003m etc
	protected float mCircleOfConfusion = new float();
		// The distance to the object we are focusing on
	protected float mFocalDistance = new float();
		// Focal length of the lens, this directly effects field of view, we can do anything from wide angle to telephoto as we don't have the limitations of physical lenses.  Focal length is the distance from the optical centre of the lens to the film stock/sensor etc
	protected float mFocalLength = new float();
		// FStop number, ie aperture, changing the aperture of a lens has an effect of depth of field, the narrower the aperture/higher the fstop number, the greater the depth of field/clearer the picture is.
	protected float mFStop = new float();

	// Secondary attributes
		// The hyperfocal length is the point at which far depth of field is infinite, ie if mFocalDistance is >= to this value everythig will be clear to infinity
	protected float mHyperfocalLength = new float();
		// Field of view of the lens, directly related to focal length
	protected Radian mFieldOfView = new Radian();

	public void Dispose()
	{
	}

	public float getFrameSize()
	{
		return mFrameSize;
	}
	public float getFocalDistance()
	{
		return mFocalDistance;
	}
	public float getFocalLength()
	{
		return mFocalLength;
	}
	public Radian getFieldOfView()
	{
		return mFieldOfView;
	}
	public float getFStop()
	{
		return mFStop;
	}
	public float getHyperfocalLength()
	{
		return mHyperfocalLength;
	}

	public void recalculateDepthOfField(ref float _nearDepth, ref float _focalDepth, ref float _farDepth)
	{
		// Set focalDepth to the current focalDistance
		_focalDepth = mFocalDistance;

		// Recalculate the Hyperfocal length
		recalculateHyperfocalLength();

		// Calculate the numerator of the optics equations
		float numerator = (mFocalDistance * (mHyperfocalLength - mFocalLength));

		float nearClear = Convert.ToSingle(numerator / (mHyperfocalLength + mFocalDistance - (2.0 * mFocalLength)));

		// Adjust the nearDepth relative to the aperture. This is an approximation.
		_nearDepth = System.Math.Min(nearClear - nearClear * mFStop, Convert.ToSingle(0));

		if (mFocalDistance < mHyperfocalLength) {
			// Calculate the far clear plane
			float farClear = numerator / (mHyperfocalLength - mFocalDistance);

			// Adjust the farDepth relative to the aperture. This is an approximation.
			_farDepth = farClear + farClear * mFStop;

		// Far depth of field should be infinite
		} else {
			_farDepth = Math.POS_INFINITY;
		}
	}



	public Lens(float _focalLength, float _fStop, float _frameSize = 3.5, float _circleOfConfusion = 0.003)
	{
		init(_focalLength, _fStop, _frameSize, _circleOfConfusion);
	}
	public Lens(Radian _fieldOfView, float _fStop, float _frameSize = 3.5, float _circleOfConfusion = 0.003)
	{
		init(_fieldOfView, _fStop, _frameSize, _circleOfConfusion);
	}
	public void init(float _focalLength, float _fStop, float _frameSize, float _circleOfConfusion)
	{
		mFocalLength = _focalLength;
		mFStop = _fStop;
		mFrameSize = _frameSize;
		mCircleOfConfusion = _circleOfConfusion;
		recalculateFieldOfView();
	}
	public void init(Radian _fieldOfView, float _fStop, float _frameSize, float _circleOfConfusion)
	{
		mFieldOfView = _fieldOfView;
		mFStop = _fStop;
		mFrameSize = _frameSize;
		mCircleOfConfusion = _circleOfConfusion;
		recalculateFocalLength();
	}
	public void setFrameSize(float _frameSize)
	{
		mFrameSize = _frameSize;
		recalculateFieldOfView();
	}
	public void setFocalDistance(float _focalDistance)
	{
		mFocalDistance = System.Math.Max(_focalDistance, 0f);
	}
	public void setFocalLength(float _focalLength)
	{
		mFocalLength = System.Math.Max(_focalLength, 0.3f);
		recalculateFieldOfView();
	}
	public void setFieldOfView(Radian _fieldOfView)
	{
		Radian n = new Radian(2.8);
		if (n < _fieldOfView) {
			mFieldOfView = n;
		} else {
			mFieldOfView = _fieldOfView;
		}
		recalculateFocalLength();
	}
	public void setFStop(float _fStop)
	{
		mFStop = System.Math.Max(_fStop, 0f);
	}

	private void recalculateHyperfocalLength()
	{
		mHyperfocalLength = (mFocalLength * mFocalLength) / (mFStop * mCircleOfConfusion) + mFocalLength;
	}
	private void recalculateFieldOfView()
	{
		mFieldOfView = 2.0 * Math.Atan(Convert.ToSingle(mFrameSize / (2.0 * mFocalLength)));
	}
	private void recalculateFocalLength()
	{
		mFocalLength = Convert.ToSingle((mFrameSize / System.Math.Tan(mFieldOfView.ValueRadians / 2.0)) / 2.0);
	}
}


There are three classes:
DepthOfField - This is the class which controls the dof shader and the underlying compositor script.
Lens - This is a class which makes it easier to control the DeathOfField class (makes it more natural)
Dofmanager - This class combines both other classes to an automatic dof shader: create a new instance and set mode=automatic and everything runs out of the box

And now you have to download the material file and the other shader files.


Tip Subfolder
Copy the material file in a new folder called "dof". It improves clarity and makes it easier to find.

note Warning
Make sure that the material file is in the media folder or in one of it's subfolders and a reference is added to the "resources.cfg" file.

How to use - The simplest way

Create a dofmanager instance (and set the values you need)

DOFManager dof = new DOFManager(MyViewport, MyCamera, MyRenderWindow, MySceneManager);

How to use - The other way

Create instances of Lens and DepthOfField.

DepthOfFieldEffect mDepthOfFieldEffect = new DepthOfFieldEffect(Viewport, Camera);
Lens mLens = new Lens(Camera.FOVy, 1);


But now you have to adjust the values on your own. Look into the DofManager to get an overview.

Don't forget to call "Dispose" if you stop rendering.

How does the DofManager works

The DofManager hooks into the renderloop (the FrameStarted event) and raycasts each frame from the screen center (You may need to change the query flags). The "DelegateRequestFocalDistance" is delegate which can be used to inect custom focal distances into the manager. If it's null/nothing it will be ignored.

You can stop/resume the manager with getenabled and setenabled.

Combability issues
The dofshader somehow prevents other compositors to work. (Note from Tublii: One example: this happens with the SSAA compositor)

Thanks to

DWORD
polygon9