fix(render): A7 Fix D D-3/D-4 — two-path lighting (objects plain-Lambert+sun, EnvCell wrap+no-sun) (#140)
mesh_modern unified all meshes into one calc_point_light path: it applied the bake's half-Lambert wrap to objects (lighting character backs from a torch behind them) and added the sun to EnvCell building shells (warm facade wash). Retail splits these: objects = hardware plain Lambert max(0,N.L) + sun; EnvCell walls = baked wrap, dynamics only, NO sun (minimize_envcell_lighting). Add a per-draw uLightingMode (WbDrawDispatcher=0 object, EnvCellRenderer=1 envcell) selecting the angular term (wrap vs plain Lambert) and gating the sun. Per-light cap + D-1 clamp unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
156dc453c9
commit
0980bea48d
3 changed files with 26 additions and 15 deletions
|
|
@ -122,6 +122,7 @@ uniform mat4 uViewProjection;
|
||||||
// _opaqueDrawCount before the transparent MDI call, matching WorldBuilder's
|
// _opaqueDrawCount before the transparent MDI call, matching WorldBuilder's
|
||||||
// uDrawIDOffset pattern in BaseObjectRenderManager.cs line 845.
|
// uDrawIDOffset pattern in BaseObjectRenderManager.cs line 845.
|
||||||
uniform int uDrawIDOffset;
|
uniform int uDrawIDOffset;
|
||||||
|
uniform int uLightingMode; // A7 Fix D: 0 = OBJECT (plain Lambert + sun), 1 = ENVCELL (half-Lambert wrap, no sun)
|
||||||
|
|
||||||
// SceneLighting UBO — binding=1 in the UBO namespace (GL keeps the SSBO and UBO
|
// SceneLighting UBO — binding=1 in the UBO namespace (GL keeps the SSBO and UBO
|
||||||
// binding tables separate, so this coexists with the binding=1 BatchBuffer SSBO
|
// binding tables separate, so this coexists with the binding=1 BatchBuffer SSBO
|
||||||
|
|
@ -157,16 +158,19 @@ vec3 pointContribution(vec3 N, vec3 worldPos, GlobalLight L) {
|
||||||
float d = sqrt(distsq);
|
float d = sqrt(distsq);
|
||||||
float range = L.dirAndRange.w; // falloff_eff = Falloff × 1.3
|
float range = L.dirAndRange.w; // falloff_eff = Falloff × 1.3
|
||||||
if (d >= range || range <= 1e-4) return vec3(0.0);
|
if (d >= range || range <= 1e-4) return vec3(0.0);
|
||||||
// Half-Lambert WRAP: (1/1.5)·(N·D + 0.5·d). N·D = d·cosθ (D un-normalised); the
|
// A7 Fix D D-3: angular term by lighting path. ENVCELL bake (mode 1) keeps the
|
||||||
// +0.5·d bias lets a face angled AWAY from the torch still catch light (retail's
|
// half-Lambert wrap (lights surfaces angled away, retail calc_point_light); OBJECT
|
||||||
// soft terminator). wrap≤0 = fully shadowed. TwoLpr=1.5, WrapBias=0.5.
|
// mode (0) uses plain Lambert max(0,N·L) so a torch BEHIND a character contributes
|
||||||
float wrap = (1.0 / 1.5) * (dot(N, toL) + 0.5 * d);
|
// nothing (retail's hardware path). toL is un-normalised (length d).
|
||||||
if (wrap <= 0.0) return vec3(0.0);
|
float angular = (uLightingMode == 1)
|
||||||
|
? (1.0 / 1.5) * (dot(N, toL) + 0.5 * d) // half-Lambert wrap (EnvCell bake)
|
||||||
|
: max(0.0, dot(N, toL)); // plain Lambert (object/hardware)
|
||||||
|
if (angular <= 0.0) return vec3(0.0);
|
||||||
// NORM branch (distance-cube): >1 m → distsq·d ≈ inverse-square soft far halo;
|
// NORM branch (distance-cube): >1 m → distsq·d ≈ inverse-square soft far halo;
|
||||||
// <1 m → just d (dodge the near singularity). "Punchy near, soft far."
|
// <1 m → just d (dodge the near singularity). "Punchy near, soft far."
|
||||||
float norm = (distsq > 1.0) ? (distsq * d) : d;
|
float norm = (distsq > 1.0) ? (distsq * d) : d;
|
||||||
float intensity = L.colorAndIntensity.w;
|
float intensity = L.colorAndIntensity.w;
|
||||||
float scale = (1.0 - d / range) * intensity * (wrap / norm);
|
float scale = (1.0 - d / range) * intensity * (angular / norm);
|
||||||
if (kind == 2) {
|
if (kind == 2) {
|
||||||
// Spotlight: hard-edged cos-cone gate layered on the point ramp.
|
// Spotlight: hard-edged cos-cone gate layered on the point ramp.
|
||||||
vec3 Ldir = toL / max(d, 1e-4);
|
vec3 Ldir = toL / max(d, 1e-4);
|
||||||
|
|
@ -183,15 +187,18 @@ vec3 pointContribution(vec3 N, vec3 worldPos, GlobalLight L) {
|
||||||
vec3 accumulateLights(vec3 N, vec3 worldPos, int instanceIndex) {
|
vec3 accumulateLights(vec3 N, vec3 worldPos, int instanceIndex) {
|
||||||
vec3 lit = uCellAmbient.xyz;
|
vec3 lit = uCellAmbient.xyz;
|
||||||
|
|
||||||
// SUN / directional — material-lit term (added with ambient, NOT into the
|
// SUN / directional — OBJECT path only (mode 0). retail's EnvCell path
|
||||||
// torch sum), unchanged.
|
// (minimize_envcell_lighting) enables only dynamic lights, NEVER the sun, so
|
||||||
int activeLights = int(uCellAmbient.w);
|
// EnvCell walls (mode 1) get no directional sun wash (A7 Fix D D-4).
|
||||||
for (int i = 0; i < 8; ++i) {
|
if (uLightingMode == 0) {
|
||||||
if (i >= activeLights) break;
|
int activeLights = int(uCellAmbient.w);
|
||||||
if (int(uLights[i].posAndKind.w) != 0) continue; // directional only
|
for (int i = 0; i < 8; ++i) {
|
||||||
vec3 Ldir = -uLights[i].dirAndRange.xyz;
|
if (i >= activeLights) break;
|
||||||
float ndl = max(0.0, dot(N, Ldir));
|
if (int(uLights[i].posAndKind.w) != 0) continue; // directional only
|
||||||
lit += uLights[i].colorAndIntensity.xyz * uLights[i].colorAndIntensity.w * ndl;
|
vec3 Ldir = -uLights[i].dirAndRange.xyz;
|
||||||
|
float ndl = max(0.0, dot(N, Ldir));
|
||||||
|
lit += uLights[i].colorAndIntensity.xyz * uLights[i].colorAndIntensity.w * ndl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POINT / SPOT torches: their OWN accumulator (A7 Fix D, D-1). Retail's
|
// POINT / SPOT torches: their OWN accumulator (A7 Fix D, D-1). Retail's
|
||||||
|
|
|
||||||
|
|
@ -877,6 +877,7 @@ public sealed unsafe class EnvCellRenderer : IDisposable
|
||||||
// WB EnvCellRenderManager.cs:406-409: uniform state setup.
|
// WB EnvCellRenderManager.cs:406-409: uniform state setup.
|
||||||
_shader.SetInt("uRenderPass", (int)renderPass);
|
_shader.SetInt("uRenderPass", (int)renderPass);
|
||||||
_shader.SetInt("uFilterByCell", 0);
|
_shader.SetInt("uFilterByCell", 0);
|
||||||
|
_shader.SetInt("uLightingMode", 1); // A7 Fix D D-3/D-4: EnvCell bake (wrap points, no sun)
|
||||||
|
|
||||||
// Phase U.4 ROOT-CAUSE FIX (cell-shell flicker / "transparent walls when
|
// Phase U.4 ROOT-CAUSE FIX (cell-shell flicker / "transparent walls when
|
||||||
// moving"): upload uViewProjection HERE rather than inheriting it from
|
// moving"): upload uViewProjection HERE rather than inheriting it from
|
||||||
|
|
|
||||||
|
|
@ -893,6 +893,9 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
||||||
_indoorProbeFrameCounter++;
|
_indoorProbeFrameCounter++;
|
||||||
var vp = camera.View * camera.Projection;
|
var vp = camera.View * camera.Projection;
|
||||||
_shader.SetMatrix4("uViewProjection", vp);
|
_shader.SetMatrix4("uViewProjection", vp);
|
||||||
|
// A7 Fix D D-3/D-4: object path — plain Lambert points + sun. MUST set
|
||||||
|
// explicitly (shared GL uniform; EnvCellRenderer sets it to 1).
|
||||||
|
_shader.SetInt("uLightingMode", 0);
|
||||||
|
|
||||||
// #128 self-heal: fresh re-request dedup per Draw pass.
|
// #128 self-heal: fresh re-request dedup per Draw pass.
|
||||||
_missRequested.Clear();
|
_missRequested.Clear();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue