run method
Returns linear RGBA for attachment zero. Null discards the fragment.
Implementation
@override
Vector4? run(Float32List v, ShaderBindings b, FragmentContext c) {
final bloom = b.textures['bloom_texture'];
if (bloom == null) return Vector4(0.0, 0.0, 0.0, 1.0);
final params = b.vec4('LensFlareInfo', 'params', Vector4.zero());
final more = b.vec4('LensFlareInfo', 'more', Vector4.zero());
// `Fringed`: the glow at (u, w), its channels taken [spread] apart.
Vector3 fringed(double u, double w, double ax, double ay, double spread) =>
Vector3(
bloom.sample(u + ax * spread, w + ay * spread).x,
bloom.sample(u, w).y,
bloom.sample(u - ax * spread, w - ay * spread).z,
);
final glow = bloom.sample(v[0], v[1]);
final flippedU = 1.0 - v[0];
final flippedW = 1.0 - v[1];
final towardU = (0.5 - flippedU) * params.z;
final towardW = (0.5 - flippedW) * params.z;
final reach = math.sqrt(towardU * towardU + towardW * towardW);
final alongU = reach > 1e-6 ? towardU / reach : 0.0;
final alongW = reach > 1e-6 ? towardW / reach : 0.0;
final spread = more.x;
final flare = Vector3.zero();
final ghosts = (params.y + 0.5).floor();
for (var i = 0; i < 8; i++) {
if (i >= ghosts) break;
final u = flippedU + towardU * i;
final w = flippedW + towardW * i;
flare.add(fringed(u, w, alongU, alongW, spread) * _falloff(u, w, 10.0));
}
final aspect = math.max(more.z, 1e-4);
final haloU = flippedU + alongU / aspect * params.w;
final haloW = flippedW + alongW * params.w;
flare.add(
fringed(haloU, haloW, alongU, alongW, spread) *
(_falloff(haloU, haloW, 5.0) * more.y),
);
final intensity = params.x;
return Vector4(
glow.x + flare.x * intensity,
glow.y + flare.y * intensity,
glow.z + flare.z * intensity,
1.0,
);
}