run method
Returns linear RGBA for attachment zero. Null discards the fragment.
Implementation
@override
Vector4? run(Float32List v, ShaderBindings bindings, FragmentContext c) {
final color = bindings.vec4('TransmittanceInfo', 'color', Vector4.zero());
final light = bindings.vec4('TransmittanceInfo', 'light', Vector4.zero());
final params = bindings.vec4('TransmittanceInfo', 'params', Vector4.zero());
final opacity = color.w.clamp(0.0, 1.0);
final transmission = params.x.clamp(0.0, 1.0);
final map = bindings.textures['base_color_texture'];
final texel = map?.sample(v[kVUv], v[kVUv + 1]) ?? Vector4.all(1.0);
double body(double channel, double mapped) =>
(1.0 - opacity) +
opacity * transmission * math.max(channel, 0.0) * mapped;
final normal = Vector3(v[kVNormal], v[kVNormal + 1], v[kVNormal + 2]);
final length = normal.length;
final facing = length > 0.0
? (normal.dot(Vector3(light.x, light.y, light.z)) / length).abs()
: 1.0;
final f0 = params.y.clamp(0.0, 1.0);
final fresnel =
f0 + (1.0 - f0) * math.pow(1.0 - facing.clamp(0.0, 1.0), 5.0);
// What is reflected is lost only as far as it is turned away: 2 cos²θ
// of it, held to one — `shadow_transmittance.frag` has the reasons.
final lost = fresnel * math.min(2.0 * facing * facing, 1.0);
// A caster whose photons are followed stops all of its light here.
final stops = params.z > 0.5;
double through(double channel, double mapped) => stops
? 0.0
: math.sqrt(math.max(body(channel, mapped), 0.0)) * (1.0 - lost);
return Vector4(
0.0,
1.0 - through(color.x, texel.x),
1.0 - through(color.y, texel.y),
through(color.z, texel.z),
);
}