LensFlareKernel

The LensFlareKernel generates a lens flare whose properties - including size, spread, position, orientation and brightness - can be controlled by the user. It does not require any inputs.

This kernel demonstrates that user-defined functions can be called from within a kernel’s standard functions, such as init() and process(), just as they could in C++.

// Copyright (c) 2012 The Foundry Visionmongers Ltd.  All Rights Reserved.
// Example RIP Kernel

#define kRandMax 32767

/// Platform-consistent PRNG based on SGI rand().
inline int RandI(unsigned int seed) {
  unsigned int next = seed;
  int result;

  next *= 1103515245;
  next += 12345;
  result = (unsigned int) (next / 65536) % 256;

  next *= 1103515245;
  next += 12345;
  result <<= 7;
  result ^= (unsigned int) (next / 65536) % 256;
  return result;
}

inline float RandF(unsigned int seed)
{
  return float(RandI(seed))/float(kRandMax);
}

/// LensFlareKernel: Generates a lens flare on top of the input image.
/// NOTE that this process does not currently vectorize.
kernel LensFlareKernel : ImageComputationKernel<ePixelWise>
{
  Image<eWrite, eAccessPoint> dst;

param:
  float2 flareHandle;
  float2 centre;
  float  size;
  float  spread;
  float  brightness;
  int    nDots;
  int    seed;

local:
  static const int kMaxDots = 10;
  float4 colours[kMaxDots];
  float2 dotCentres[kMaxDots];
  float  invSizeSqr[kMaxDots];
  int actualDots;

  void define() {
    defineParam(centre,      "Centre", float2(400.0f, 400.0f));
    defineParam(flareHandle, "FlareHandle",  float2(800.0f, 800.0f));
    defineParam(size,        "Size",         150.0f);
    defineParam(brightness,  "Brightness",   1.0f);
    defineParam(spread,      "Spread",   0.3f);
    defineParam(nDots,       "NDots",   5);
    defineParam(seed,        "Seed",   0);
  }

  void init() {
    actualDots = nDots > kMaxDots ? kMaxDots : nDots;
    actualDots = actualDots < 0 ? 0 : actualDots;
    float2 dist = centre - flareHandle;
    for(int i = 0; i < actualDots; ++i) {
      float t = float(i) / float(kMaxDots-1);
      dotCentres[i] = flareHandle + dist * spread * RandF(seed + i);
      float thisSize =  RandF(seed + i + 1000) * size;
      invSizeSqr[i] = 1.0f/(thisSize * thisSize);
      colours[i] = float4(RandF(seed + i + 2000),
                          RandF(seed + i + 3000),
                          RandF(seed + i + 4000),
                          RandF(seed + i + 5000));
    }
  }

  float4 flareValue(float2 posf,
                   int index)
  {
    float2 delta = posf - dotCentres[index];
    float dotDelta = dot(delta, delta) * invSizeSqr[index];
    float value = clamp(1.0f - dotDelta, 0.0f, 1.0f);
    value *= value;
    return colours[index] * value;
  }

  void process(int2 pos) {
    float2 posf(pos.x, pos.y);

    SampleType(dst) sample(0.0f);

    float4 value = 0;
    for(int i = 0; i < actualDots; ++i) {
      value += flareValue(posf, i);
    }

    sample.x += value.x * brightness;
    sample.y += value.y * brightness;
    sample.z += value.z * brightness;

    dst() = sample;
  }

};

Footnotes

[1]Note that kernels which call user-defined functions from within kernel() currently cannot be vectorized on the CPU.