LensFlare¶
The LensFlare kernel 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) 2024 The Foundry Visionmongers Ltd. All Rights Reserved.
/// LensFlare kernel: Generates a lens flare asset for use in compositing.
kernel LensFlare : ImageComputationKernel<ePixelWise>
{
Image<eWrite, eAccessPoint> dst;
param:
float2 flareHandle;
float2 centre;
float size;
float spread;
float brightness;
int nDots;
int seed;
local:
#define kMaxDots 16
SampleType(dst) colours[kMaxDots];
float2 dotCentres[kMaxDots];
float invSizeSqr[kMaxDots];
int actualDots;
void define() {
defineParam(centre, "Centre", float2(400.0f, 400.0f), eParamProxyScale);
defineParam(flareHandle, "FlareHandle", float2(800.0f, 800.0f), eParamProxyScale);
defineParam(size, "Size", 150.0f, eParamProxyScale);
defineParam(brightness, "Brightness", 1.0f);
defineParam(spread, "Spread", 0.3f);
defineParam(nDots, "NDots", 5);
defineParam(seed, "Seed", 0);
}
#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);
}
void init() {
// Restrict the number of flares we can produce
actualDots = clamp(nDots, 0, kMaxDots);
float2 dist = centre - flareHandle;
for (int i = 0; i < actualDots; ++i) {
// Define the flare centres
dotCentres[i] = flareHandle + dist * spread * RandF(seed + i);
// Define the flare sizes
float thisSize = RandF(seed + i + 1000) * size;
invSizeSqr[i] = 1.0f / (thisSize * thisSize);
// Define the flare colours
for (int c = 0; c < dst.kComps; ++c) {
colours[i][c] = RandF(seed + i + (c + 2) * 1000);
}
}
}
/// Calculate the flares based on the distance from their centres
SampleType(dst) 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);
// Calculate the dots for the flares with their overlaps
for (int i = 0; i < actualDots; ++i) {
sample += flareValue(posf, i);
}
// Adjust the brightness and write out to the dst image
dst() = sample * brightness;
}
};
Footnotes
Note that kernels which call user-defined functions from within kernel() currently cannot be vectorized on the CPU.