Skip to content

fix(water): stop double-counting specular in LLF - #368

Merged
alandtse merged 2 commits into
devfrom
fix/water-llf-specular-doublecount
Aug 2, 2026
Merged

fix(water): stop double-counting specular in LLF#368
alandtse merged 2 commits into
devfrom
fix/water-llf-specular-doublecount

Conversation

@alandtse

@alandtse alandtse commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes water specular double-counting when Light Limit Fix is enabled, correcting a gap in an unmerged upstream fix.

Water's vanilla per-light specular loop and LLF's own clustered specular loop both light the same water surface from the same light list, via separate additive BSRenderPasses -- any light both passes see gets its specular counted twice. Gating the vanilla loop off under LIGHT_LIMIT_FIX (mirroring Lighting.hlsl's existing convention) fixes that.

Doing only that would introduce a real regression: LLF's own clustered water loop continues past any Shadow-flagged light instead of sampling its shadow, so once it becomes the sole water specular source, every shadow-casting point/spot light (torches, lanterns -- the nearest, most visually significant lights) would lose water specular entirely. This mirrors RunGrass.hlsl's shadow-sampling pattern to sample the shadow instead of dropping the light.

Background

Based on upstream community-shaders/skyrim-community-shaders#2403, which only gated the vanilla loop and has been sitting unmerged since May. A maintainer (doodlum) left CHANGES_REQUESTED there, correctly flagging that water renders as an extra pass and that the PR as written breaks specular on lights it silently drops. Verified against our fork's code (via two independent supervisor passes plus an adversarial review) before writing this: the additive multi-pass premise checks out (src/ShaderCache.cpp's GetWaterShaderDefines bakes light count into the compiled technique, and LightLimitFix::Hooks::BSWaterShader_SetupGeometry fires per BSRenderPass, not per water surface per frame), and the actual mechanism behind the regression is the LightFlags::Shadow continue at Water.hlsl's LLF block, not a portal/room-index issue -- so this PR fixes that specific gap rather than importing community-shaders#2403 as-is.

Testing

  • hlslkit-compile against Water.hlsl's full permutation set: 672 SE variants + 696 VR variants, 0 errors, 0 new warnings on both.
  • Runtime SE+VR verification (torch/campfire near water, LLF on, before/after) still pending before merge, per the project's runtime test gate.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01Fk5GzLkFvm9Z7KsHFKS51t

Summary by CodeRabbit

  • Bug Fixes
    • Improved water lighting to prevent clustered specular lights from being counted twice.
    • Fixed shadowed clustered lights so their shadows now correctly affect water reflections and highlights.

Water's vanilla per-light specular loop and LightLimitFix's own
clustered specular loop light the same surface from the same light
list via separate additive render passes, doubling specular for any
light both see. Gate the vanilla loop off under LIGHT_LIMIT_FIX, as
Lighting.hlsl already does for its own vanilla loop.

Doing that alone would silently drop specular from every
shadow-casting light, since LLF's water loop `continue`s past
Shadow-flagged lights instead of sampling their shadow. Mirror
RunGrass.hlsl's shadow-sampling pattern so those lights still
contribute.

Based on upstream community-shaders#2403,
which only did the first half; a maintainer review there flagged the
narrower regression this commit also fixes.
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d78546ec-bd32-4d6a-8fc3-22f79af2a58c

📥 Commits

Reviewing files that changed from the base of the PR and between 45809e6 and 6c07387.

📒 Files selected for processing (1)
  • package/Shaders/Water.hlsl
🚧 Files skipped from review as they are similar to previous changes (1)
  • package/Shaders/Water.hlsl

📝 Walkthrough

Walkthrough

Water lighting excludes the vanilla specular loop when LIGHT_LIMIT_FIX is enabled. Clustered shadow-casting lights now receive shadow sampling, and their specular contributions use the sampled shadow factor.

Changes

Water lighting

Layer / File(s) Summary
Vanilla specular loop guard
package/Shaders/Water.hlsl
When LIGHT_LIMIT_FIX is defined, the separate vanilla specular-light loop is disabled.
Clustered specular shadow sampling
package/Shaders/Water.hlsl
Clustered lighting initializes shadow data, samples shadows for shadow-casting lights, and applies the shadow factor to specular lighting.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the water specular double-counting fix when Light Limit Fix is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/water-llf-specular-doublecount

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
package/Shaders/Water.hlsl (1)

1180-1183: 📐 Maintainability & Code Quality | 🔵 Trivial

Use a conventional PR title and issue reference.

If the PR title is not already conventional, use fix(water): avoid duplicate water specular.

Add Related to community-shaders#2403`` if upstream PR #2403 is the applicable linked record. Add `Fixes #...` when a regression issue exists.

As per path instructions, use type(scope): description titles and add appropriate GitHub keywords for bug fixes or features.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package/Shaders/Water.hlsl` around lines 1180 - 1183, Update the pull request
metadata rather than the shader code: use the conventional title “fix(water):
avoid duplicate water specular” and add “Related to `#2403`” when applicable;
include a “Fixes #...” reference only if a regression issue exists.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@package/Shaders/Water.hlsl`:
- Around line 1180-1183: Update the pull request metadata rather than the shader
code: use the conventional title “fix(water): avoid duplicate water specular”
and add “Related to `#2403`” when applicable; include a “Fixes #...” reference
only if a regression issue exists.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ed4fa81a-ef58-4461-9b23-54fd68c876d5

📥 Commits

Reviewing files that changed from the base of the PR and between 043b7ac and 45809e6.

📒 Files selected for processing (1)
  • package/Shaders/Water.hlsl

@github-actions

Copy link
Copy Markdown

No actionable suggestions for changed features.

@alandtse alandtse changed the title fix(water): stop double-counting specular under LLF fix(water): stop double-counting specular in LLF Aug 1, 2026
GetShadowLightShadow reconstructs world position from this pixel's
camera-relative position, which is the mirrored reflection camera
during a reflection pass, not the main view -- sampling the shadow
map there would look up the wrong location. Gate it on inWorld and
!inReflection, matching Lighting.hlsl's equivalent call.
@alandtse
alandtse merged commit 66c6e44 into dev Aug 2, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant