Sunday, May 6, 2012

Depth Of Field Effect


In optics, particularly as it relates to film and photography, depth of field (DOF) is the distance between the nearest and farthest objects in a scene that appear acceptably sharp in an image. Although a lens can precisely focus at only one distance at a time, the decrease in sharpness is gradual on each side of the focused distance, so that within the DOF, the unsharpness is imperceptible under normal viewing conditions.


 
 


The following OpenCL kernel demonstrate how to add the effect to a given image. In this example, the original bitmap is passed as an array of float4 to the kernel. The x attribute correspond to the red value of the pixel, y to the green, z to the blue, and w to the actual depth of the pixel. Since OpenCL does not provide any native function for random numbers, an array of floats initialized on the host, is also provided to the kernel. These random numbers simulate the random dispersion of light rays.

OpenCL Kernel

// After effects constants
__constant int gNbDOFIterations = 10;

// Kernel
__kernel void postProcessing_kernel(
  int width,
  int height,
  __global char* bitmap,
  __global float4* depthOfField,
  __global float* randoms,
  int randomIndex)
{
  int x = get_global_id(0);
  int y = get_global_id(1);
  int index = y*width+x;
  float4 color = depthOfField[index];
  float depth = 8.f*depthOfField[index].w;
  int wh = width*height;

  float4 localColor = 0;
  for( int i=0; i<gNbDOFIterations; ++i )
  {
    int ix = (i+randomIndex)%wh;
    int iy = (i+width+randomIndex)%wh;
    int xx = x+4.f*depth*randoms[ix];
    int yy = y+4.f*depth*randoms[iy];
    if( xx>=0 && xx<width && yy>=0 && yy<height )
    {
        int localIndex = yy*width+xx;
        if( localIndex >= 0 && localIndex < wh )
        {
            localColor += depthOfField[localIndex];
        }
    }
  }
  localColor /= gNbDOFIterations;
  localColor.w = 0.f;
  makeOpenGLColor( localColor, bitmap, index );
}