contributorLight function

({Vector3 radiance, Vector3 toLight}) contributorLight(
  1. ShaderBindings bindings,
  2. int index,
  3. Vector3 world
)

ContributorLight — N6: light index as world receives it, with no surface to face. A rectangle is read as a point at its centre, as the GLSL reads it.

Implementation

({Vector3 toLight, Vector3 radiance}) contributorLight(
  ShaderBindings bindings,
  int index,
  Vector3 world,
) {
  const block = 'ContributorLightInfo';
  final fromList = index >= kMaxLights;
  final slot = index - kMaxLights;
  final fromCell = fromList && clustered(bindings);
  final row = !fromList
      ? -1
      : fromCell
      ? clusterRow(bindings, world, slot)
      : lightListRow(bindings, slot).round();

  Vector4 read(String member, int column) => fromList
      ? lightListTexel(bindings, row, column)
      : bindings.vec4(block, member, Vector4.zero(), at: index);
  final position = read('light_position', 0);
  final color = read('light_color', 1);
  if (fromList) {
    color.w *= fromCell
        ? (inSlots(bindings, row) ? 0.0 : 1.0)
        : lightListScale(bindings, slot);
  }
  final direction = read('light_direction', 2);
  final cone = read('light_cone', 3);

  final type = position.w;
  final directional = type < 0.5;
  final offset = Vector3(position.x, position.y, position.z) - world;
  final distance = offset.length;
  final aim = Vector3(direction.x, direction.y, direction.z);
  final aimLength = aim.length;
  if (aimLength > 0.0) aim.scale(1.0 / aimLength);

  final degenerate = !directional && distance < 1e-6;
  final toLight = directional
      ? -aim
      : (offset..scale(1.0 / math.max(distance, 1e-6)));

  final ratio = direction.w > 0.0 ? distance / direction.w : 0.0;
  final window = (1.0 - ratio * ratio * ratio * ratio).clamp(0.0, 1.0);
  final falloff = window * window / math.max(distance * distance, 1e-4);

  final spot = type > 1.5 && type < 2.5;
  final linearRamp = spot
      ? ((aim.dot(-toLight) - cone.y) / math.max(cone.x - cone.y, 1e-4)).clamp(
          0.0,
          1.0,
        )
      : 1.0;
  final ramp = linearRamp * linearRamp;

  // A plugin's light type (codes from 16 up) gives nothing here.
  final attenuation = type > 15.5
      ? 0.0
      : (directional ? 1.0 : (degenerate ? 0.0 : falloff * ramp));
  return (
    toLight: toLight,
    radiance: Vector3(color.x, color.y, color.z) * (color.w * attenuation),
  );
}