Swirlomatic¶
The Swirlomatic is a component-wise kernel which does random access on its single input. It warps a circular area of the input image around in a swirl.
Change the Amount parameter to vary the tightness of the swirl. You can also change the Radius of the swirl and the position of its Centre.
// Copyright (c) 2024 The Foundry Visionmongers Ltd. All Rights Reserved.
/// Swirlomatic kernel: Does a nice swirl. Amount is in degrees.
kernel Swirlomatic : ImageComputationKernel<eComponentWise> {
// Input and output images
Image<eRead, eAccessRandom, eEdgeClamped> src; // randomly accessing and edge clamping
Image<eWrite, eAccessPoint> dst;
// Parameters are made available to the user as knobs.
param:
float amount; // Swirl amount in degrees
int size; // Swirl radius
float2 centre; // Swirl centre
// Local variables can be initialised once in init() and used from all pixel positions.
local:
float sizeInvSquared;
// In define(), parameters can be given labels and default values.
// Size and Centre are affected by the proxy scaling.
void define() {
defineParam(amount, "Amount", 180.0f);
defineParam(size, "Radius", 320, eParamProxyScale);
defineParam(centre, "Centre", float2(640.0f, 320.0f), eParamProxyScale);
}
// The init() function is run once before any calls to process().
void init() {
sizeInvSquared = size > 0 ? 1.0f / size : 0.f;
sizeInvSquared *= sizeInvSquared;
}
// The process() function runs over all pixel positions of the output image.
// The int3 pos parameter is used to indicate positions x, y and the component.
void process(int3 pos) {
// Calculate the distance from the swirl's centre.
const float dx = float(pos.x) - centre.x;
const float dy = float(pos.y) - centre.y;
const float distanceSquared = dx * dx + dy * dy;
// Calculate delta as quadratic distance from the centre
// in order to rotate proportionally to the swirl amount.
float delta = 1.0f - ((distanceSquared) * sizeInvSquared);
if (delta < 0.f) delta = 0.f; // exclude points outside the radius
// Calculate sine and cosine for the rotation.
const float toRadians = PI / 180.0f;
const float angle = delta * amount * toRadians;
const float sine = sin(angle);
const float cosine = cos(angle);
// Find the sampling pixel positions for anti-clockwise rotation.
const float x = centre.x + dx * cosine + dy * sine;
const float y = centre.y - dx * sine + dy * cosine;
// If src has less components than dst, protect from reading non-existent channels.
const int component = pos.z;
if (component < src.kComps) {
// Apply bilinear interpolation to sample from the input.
dst() = bilinear(src, x, y);
}
}
};