Sunday, May 6, 2012

Ray-traced trailblazer (Old school revival)

Trailblazer is a video game edited by Gremlin Graphics in 1986. It requires the player to direct a ball along a series of suspended passages. Released originally by Gremlin Graphics for the ZX Spectrum, Commodore 64, Atari 8-bitand Amstrad CPC in 1986 (there was also an enhanced version on Amstrad CPC 3" disc) it was subsequently ported in its original form to the Amiga and Atari ST.

Since I was a big fan of the game, I decided to give it a try with my realtime raytracing engine written in OpenCL. Here is the preview :)


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 );
}