GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
fix: scene light is azimuthal wrap-shaded — a vertical light anchors nothing
The first lighting pass chose a near-vertical light with a two-sided
|dot|: the resulting brightness pattern is latitude-dominated and
180-degree symmetric — INVARIANT under a yaw orbit — so it added a strong
shading cue that cannot move while orbiting, reading as the scene turning
with the camera in every mode (worse than unlit). The light is now
strongly azimuthal, wrap-shaded without |dot| (the fill pass culls to
front faces, so the derivative normal's sign is stable): the lit side is
pinned to a world azimuth the orbit visibly sweeps across.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/vk/scene3d.wgsl | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/vk/scene3d.wgsl b/src/vk/scene3d.wgsl
index 035451a..64cbc66 100644
--- a/src/vk/scene3d.wgsl
+++ b/src/vk/scene3d.wgsl
@@ -89,9 +89,16 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4f {
// the camera without it. Two-sided so unculled back faces stay sane.
if (in.lit > 0.5) {
let n = normalize(cross(dpdx(in.world), dpdy(in.world)));
- let l = normalize(vec3f(-0.45, 0.8, 0.35));
- let d = abs(dot(n, l));
- rgb = rgb * (0.62 + 0.38 * d);
+ // A strongly AZIMUTHAL light, wrap-shaded. A near-vertical light (or a
+ // two-sided |dot|) yields a latitude-dominated / 180-degree-symmetric
+ // brightness pattern — invariant under a yaw orbit, which reads as the
+ // scene turning with the camera. The horizontal component pins the lit
+ // side to a world azimuth the orbit visibly sweeps across; the wrap
+ // term keeps a soft floor without |dot|'s ambiguity (the fill pass
+ // culls to front faces, so the derivative normal's sign is stable).
+ let l = normalize(vec3f(-0.55, 0.45, 0.7));
+ let d = clamp(dot(n, l) * 0.5 + 0.5, 0.0, 1.0);
+ rgb = rgb * (0.55 + 0.45 * d);
}
return vec4f(rgb, cov);
}