Ballomatic

The Ballomatic is a pixelwise kernel which does random access on its single input. It warps a circular area of the input image to look as if it’s being viewed through a distorting lens.

Change the Power parameter to alter the distortion applied inside the circle. You can also change the Size of the circle and the position of its Centre.

// Copyright (c) 2024 The Foundry Visionmongers Ltd.  All Rights Reserved.

// Ballomatic kernel: Applies a ball-o-matic effect. Set the power to change the effect.
kernel Ballomatic : ImageComputationKernel<ePixelWise> {
  Image<eRead, eAccessRandom, eEdgeClamped> src;
  Image<eWrite, eAccessPoint> dst;

param:
  float power;    // Ball curvature
  int size;       // Ball radius
  float2 centre;  // Ball centre

local:
  float sizeInvSquared;

  void define() {
    defineParam(power, "Power", -0.2f);
    defineParam(size, "Size", 400, eParamProxyScale);
    defineParam(centre, "Centre", float2(640.0f, 360.0f), eParamProxyScale);
  }

  void init() {
    sizeInvSquared = size > 0 ? 1.0f / size : 0.f;
    sizeInvSquared *= sizeInvSquared;
  }

  void process(int2 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
    float delta = 1.0f - (distanceSquared * sizeInvSquared);

    // Find the minimum number of components between src and dst
    // in order to protect from reading/writing non-existent channels.
    const int minComps = min(src.kComps, dst.kComps);

    if (delta < 0) {
      for (int c = 0; c < minComps; ++c) {
        dst(c) = src(pos.x, pos.y, c);
      }
    }
    else {
      delta = pow(delta, power);
      const float x = centre.x + dx * delta;
      const float y = centre.y + dy * delta;

      for (int c = 0; c < minComps; ++c) {
        dst(c) = bilinear(src, x, y, c);
      }
    }
  }
};