hdrBloom function

HdrImage hdrBloom(
  1. HdrImage hdr,
  2. {double radius = 0.01,
  3. double weight = 0.1}
)

Applies an HDR bloom filter to the image, in-place.

Implementation

HdrImage hdrBloom(HdrImage hdr, {double radius = 0.01, double weight = 0.1}) {
  double _lerp(double t, double a, double b) => (1.0 - t) * a + t * b;

  //int nPix = xResolution * yResolution;
  // Possibly apply bloom effect to image
  if (radius > 0.0 && weight > 0.0) {
    // Compute image-space extent of bloom effect
    final bloomSupport = (radius * max(hdr.width, hdr.height)).ceil();
    final bloomWidth = bloomSupport ~/ 2;
    // Initialize bloom filter table
    final bloomFilter = Float32List(bloomWidth * bloomWidth);
    for (var i = 0; i < bloomWidth * bloomWidth; ++i) {
      final dist = sqrt(i / bloomWidth);
      bloomFilter[i] = pow(max(0.0, 1.0 - dist), 4.0).toDouble();
    }

    // Apply bloom filter to image pixels
    final bloomImage = Float32List(3 * hdr.width * hdr.height);
    for (var y = 0, offset = 0; y < hdr.height; ++y) {
      for (var x = 0; x < hdr.width; ++x, ++offset) {
        // Compute bloom for pixel _(x,y)_
        // Compute extent of pixels contributing bloom
        final x0 = max(0, x - bloomWidth);
        final x1 = min(x + bloomWidth, hdr.width - 1);
        final y0 = max(0, y - bloomWidth);
        final y1 = min(y + bloomWidth, hdr.height - 1);

        var sumWt = 0.0;
        for (var by = y0; by <= y1; ++by) {
          for (var bx = x0; bx <= x1; ++bx) {
            // Accumulate bloom from pixel $(bx,by)$
            final dx = x - bx;
            final dy = y - by;
            if (dx == 0 && dy == 0) {
              continue;
            }
            final dist2 = dx * dx + dy * dy;
            if (dist2 < bloomWidth * bloomWidth) {
              //int bloomOffset = bx + by * hdr.width;
              final wt = bloomFilter[dist2];

              sumWt += wt;

              bloomImage[3 * offset] += wt * hdr.getRed(bx, by);
              bloomImage[3 * offset + 1] += wt * hdr.getGreen(bx, by);
              bloomImage[3 * offset + 2] += wt * hdr.getBlue(bx, by);
            }
          }
        }

        bloomImage[3 * offset] /= sumWt;
        bloomImage[3 * offset + 1] /= sumWt;
        bloomImage[3 * offset + 2] /= sumWt;
      }
    }

    // Mix bloom effect into each pixel
    for (var y = 0, offset = 0; y < hdr.height; ++y) {
      for (var x = 0; x < hdr.width; ++x, offset += 3) {
        hdr.setRed(x, y,
            _lerp(weight, hdr.getRed(x, y).toDouble(), bloomImage[offset]));
        hdr.setGreen(
            x,
            y,
            _lerp(
                weight, hdr.getGreen(x, y).toDouble(), bloomImage[offset + 1]));
        hdr.setBlue(
            x,
            y,
            _lerp(
                weight, hdr.getBlue(x, y).toDouble(), bloomImage[offset + 2]));
      }
    }
  }

  return hdr;
}