Repository navigation
Fix repeated PBR lighting contributions across light batches - #2999
toaster0123 wants to merge 1 commit into
Conversation
Upload a first-pass marker and add baked light, environment light, and emission only once. Keep direct lighting in every batch and cover the per-draw contract with regression tests.
| Uniform lightData = shader.getUniform("g_LightData"); | ||
| lightData.setVector4Length(numLights * 3);//8 lights * max 3 | ||
| Uniform lightCount = shader.getUniform("g_LightCount"); | ||
| // Emission and indirect lighting belong to the first pass only. |
There was a problem hiding this comment.
Small hardening thought: this logic class can be used by techniques of the MaterialDef whose fragment shader doesn't declare g_IsFirstLightPass (glow/shadow/post variants), and Shader.getUniform() returns null for unknown names — that would turn into an NPE at render time. The other uploads in this method assume their uniforms exist, so a one-line guard here keeps the new uniform safe to add:
| // Emission and indirect lighting belong to the first pass only. | |
| Uniform firstLightPass = shader.getUniform("g_IsFirstLightPass"); | |
| if (firstLightPass != null) { | |
| firstLightPass.setValue(VarType.Boolean, startIndex == 0); | |
| } |
(Uniform is already imported for g_AmbientLightColor below.) Fully optional, but cheap insurance.
There was a problem hiding this comment.
Checked at 2725428: Shader.getUniform() creates and stores a Uniform when the name is absent, then returns it (Shader.java, lines 293–301). It does not return null here. If the GLSL does not declare that uniform, GLRenderer resolves its location to -1 and skips the upload. The existing call is safe for that case, so I’ve left it unchanged.
There was a problem hiding this comment.
Good catch — you're right on both counts, and I checked before answering.
Shader.getUniform(name) creates the Uniform if the name isn't present and returns it, so it never comes back null here. And when the GLSL doesn't declare it, the location resolves to -1 and the upload is skipped, so nothing blows up for a technique like glow/shadow/post.
That also means the existing call already matches the surrounding code (g_LightData, g_LightCount and g_AmbientLightColor are all fetched and set the same way), so the current version is more consistent than my suggestion. Sorry for the churn — good fix, and my previous nit is withdrawn.
jaime-jmebot
left a comment
There was a problem hiding this comment.
Nice fix — the root cause is clear and the solution is minimal and well targeted.
- Moving emission, baked light and environment light behind a "first pass only" guard in
PBRLighting.fragis the right lever: direct lighting still accumulates per pass, so batched lights keep working while static contributions are applied exactly once. - The flag is set unconditionally from
startIndex == 0inupdateLightListUniforms, which also covers objects with no lights at all, so state can't leak into the next material render. - The new regression tests are a good match for the change: they exercise the real
PBR Lightingmaterial through a recording renderer across batch splits, probes and shader reuse, which is exactly the regression class we're guarding against.
Only nit is inline: make the new uniform upload null-safe so a technique without that declaration can't NPE. Otherwise this looks ready to go.
|
Small correction to my review above: I was wrong about the null-guard nit. Everything else in the review stands: applying emission, baked light and environment light only on the first pass is the right fix, and the tests cover the batch-split regression well. Looks good to merge from my side. 👍 |
Problem
PBR objects become brighter when the same lights are split into more batches. Each extra draw adds the material's emission and baked light again, even if those lights are black. Some multi-probe scenes also add environment lighting again.
For example, an emissive RGB value of (0.1, 0.2, 0.3) stays correct with three black directional lights in one batch. Splitting those lights into three batches changes the rendered value to (0.3, 0.6, 0.9).
Fix
Mark the first lighting pass in
SinglePassAndImageBasedLightingLogic. In the final PBR color, add emission, baked lighting, and environment lighting only on that pass. Direct lighting still accumulates on every pass.The marker is reset for each material render, including objects with no direct lights. Material parameters, shader defines, alpha, fog, and debug output behavior are unchanged.
Validation
The native checks are separate from the unit tests. The existing OpenGL ES shader-compilation issue with two or three probes prevents those GLES cases from drawing and is outside this patch. Existing additive alpha accumulation is also unchanged.