Skip to content

refactor(pbr): use feature boundary#2210

Merged
alandtse merged 6 commits into
community-shaders:devfrom
alandtse:pbr_refactor
May 3, 2026
Merged

refactor(pbr): use feature boundary#2210
alandtse merged 6 commits into
community-shaders:devfrom
alandtse:pbr_refactor

Conversation

@alandtse
Copy link
Copy Markdown
Collaborator

@alandtse alandtse commented Apr 26, 2026

Summary by CodeRabbit

  • User Interface

    • Removed "PBR Settings" tab and "Special Features" boot section
    • Streamlined TruePBR settings into a flatter, clearer layout
  • New Features

    • Added TruePBR configuration file and registered TruePBR as a feature
    • Terrain helper installs runtime material hooks
    • Features may inject shader permutations when using disk shader cache
  • Refactor

    • Migrated TruePBR into the feature system and centralized global feature access

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

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: 8aac79bf-1e62-48c8-8ab2-73e6f38d151a

📥 Commits

Reviewing files that changed from the base of the PR and between bb2db1c and 8bb9d52.

📒 Files selected for processing (20)
  • features/TruePBR/CORE
  • features/TruePBR/Shaders/Features/TruePBR.ini
  • src/Deferred.cpp
  • src/Feature.cpp
  • src/Feature.h
  • src/FeatureBuffer.cpp
  • src/Features/TerrainHelper.cpp
  • src/Features/TerrainHelper.h
  • src/Globals.cpp
  • src/Globals.h
  • src/Hooks.cpp
  • src/Menu.cpp
  • src/Menu/AdvancedSettingsRenderer.cpp
  • src/Menu/AdvancedSettingsRenderer.h
  • src/State.cpp
  • src/State.h
  • src/TruePBR.cpp
  • src/TruePBR.h
  • src/TruePBR/BSLightingShaderMaterialPBR.cpp
  • src/XSEPlugin.cpp
💤 Files with no reviewable changes (7)
  • src/FeatureBuffer.cpp
  • src/State.h
  • src/Menu/AdvancedSettingsRenderer.h
  • src/Deferred.cpp
  • src/XSEPlugin.cpp
  • src/Menu/AdvancedSettingsRenderer.cpp
  • src/Menu.cpp
✅ Files skipped from review due to trivial changes (1)
  • features/TruePBR/Shaders/Features/TruePBR.ini
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/Feature.h
  • src/TruePBR/BSLightingShaderMaterialPBR.cpp
  • src/Features/TerrainHelper.h
  • src/State.cpp
  • src/Feature.cpp
  • src/Features/TerrainHelper.cpp
  • src/TruePBR.h
  • src/TruePBR.cpp

📝 Walkthrough

Walkthrough

Refactors TruePBR into a Feature subclass, moves the global TruePBR into globals::features as an instance, adds a Feature hook for shader permutation generation, installs TerrainHelper post-load detours, removes direct TruePBR UI/menu bindings, and decouples direct runtime hooks previously wired through plugin/hook code.

Changes

TruePBR Feature Conversion

Layer / File(s) Summary
Feature type & API
src/Feature.h
Adds virtual Feature::GenerateShaderPermutations(RE::BSShader*) (no-op default).
Feature implementation
src/TruePBR.h, src/TruePBR.cpp
Converts TruePBR into struct TruePBR : Feature; removes singleton/GetSingleton and SetupFrame(); renames PrePassPrepass; adds Feature overrides (metadata, lifecycle, GenerateShaderPermutations); updates internal callsites to use globals::features::truePBR.
Callsite updates
src/TruePBR/BSLightingShaderMaterialPBR.cpp, src/BSLightingShaderMaterialPBR.cpp
Switches access from pointer globals::truePBR-> to instance globals::features::truePBR and corresponding accessor calls.
Hook wiring in feature
src/TruePBR.cpp (later sections)
Adds wrapper thunks for TESObjectLAND_SetupMaterial and BSLightingShader::SetupMaterial and registers them in TruePBR::PostPostLoad().

Global and Feature System Integration

Layer / File(s) Summary
Globals declaration
src/Globals.h, src/Globals.cpp
Replaces globals::TruePBR* truePBR pointer with globals::features::TruePBR truePBR instance and removes OnInit pointer assignment.
Feature registry
src/Feature.cpp
Prepends &globals::features::truePBR to Feature::GetFeatureList() so TruePBR participates in feature iteration.
Feature metadata file
features/TruePBR/Shaders/Features/TruePBR.ini
Adds INI with [Info] Version = 1-0-0.

Hook Decoupling and Shader Permutation Dispatch

Layer / File(s) Summary
Disk-cache permutation dispatch
src/Hooks.cpp
Removes direct globals::truePBR->GenerateShaderPermutations(shader) use; when disk-cache is enabled, iterates loaded features and calls feature->GenerateShaderPermutations(shader).
Deferred / reset hooks
src/Deferred.cpp
Removes TruePBR include and direct globals::truePBR Prepass/SetupFrame calls; leaves Feature::ForEachLoadedFeature("Prepass", ...) driven prepass.
Plugin messaging
src/XSEPlugin.cpp
Removes direct calls to globals::truePBR->PostPostLoad() and ->DataLoaded() from SKSE message handler; feature dispatch remains in place.
FeatureBuffer / includes cleanup
src/FeatureBuffer.cpp, src/Hooks.cpp
Removes unused TruePBR.h includes and deleted material setup hook installations from central Hooks::Install().

TerrainHelper Post-load Hooks

Layer / File(s) Summary
Hook thunks
src/Features/TerrainHelper.cpp
Adds TH_TESObjectLAND_SetupMaterial detour and TH_BSLightingShader_SetupMaterial vfunc thunk that call original first and then invoke terrainHelper handlers conditionally.
Lifecycle registration
src/Features/TerrainHelper.cpp, src/Features/TerrainHelper.h
Adds TerrainHelper::PostPostLoad() and installs the detour/vfunc handlers during post-post-load.

Menu / State UI and Boot Cleanup

Layer / File(s) Summary
Menu callbacks
src/Menu.cpp, src/Menu/AdvancedSettingsRenderer.h, src/Menu/AdvancedSettingsRenderer.cpp
Removes drawTruePBRSettings callback and the PBR settings tab; deletes RenderPBRSection; removes TruePBR.h includes.
State storage
src/State.h, src/State.cpp
Removes specialFeatures map and its boot logging; replaces pointer usages with globals::features::truePBR reference and guards shader resource updates on truePBR.loaded.

Sequence Diagram(s)

sequenceDiagram
    participant BSShaderLoader as "BSShader Loader"
    participant FeatureRegistry as "Feature Registry"
    participant Feature as "Feature (e.g. TruePBR)"
    participant DiskCache as "Disk Cache / Writer"

    BSShaderLoader->>FeatureRegistry: ForEachLoadedFeature("GenerateShaderPermutations")
    FeatureRegistry->>Feature: call GenerateShaderPermutations(shader)
    Feature-->>FeatureRegistry: optionally emit permutation descriptors
    FeatureRegistry->>DiskCache: collect permutations -> write cache
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • doodlum
  • Jonahex

Poem

🐰 I hopped from singleton to Feature bright,
I nudged some hooks and tucked the menu tight.
No tangled pointers, just lifecycles neat,
I twitch my whiskers — the shader dance is complete. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(pbr): use feature boundary' directly describes the main change: refactoring the PBR (TruePBR) system to use the feature framework abstraction, making it a Feature subclass instead of standalone.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Review rate limit: 8/10 reviews remaining, refill in 8 minutes and 33 seconds.

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

@github-actions
Copy link
Copy Markdown

No actionable suggestions for changed features.

@alandtse alandtse changed the title refactor(pbr): adopt feature boundary refactor(pbr): use feature boundary Apr 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/TruePBR.cpp (1)

187-191: Drop redundant nullptr re-checks.

Both Save buttons are already inside if (selectedPbrTextureSet != nullptr) (line 114) and if (selectedPbrMaterialObject != nullptr) (line 201) respectively, so the inner re-checks at lines 187 and 293 are dead branches.

♻️ Proposed cleanup
-			if (selectedPbrTextureSet != nullptr) {
-				if (ImGui::Button("Save")) {
-					PNState::SavePBRRecordConfig("Data\\PBRTextureSets", selectedPbrTextureSetName, *selectedPbrTextureSet);
-				}
+			if (ImGui::Button("Save")) {
+				PNState::SavePBRRecordConfig("Data\\PBRTextureSets", selectedPbrTextureSetName, *selectedPbrTextureSet);
 			}
-			if (selectedPbrMaterialObject != nullptr) {
-				if (ImGui::Button("Save")) {
-					PNState::SavePBRRecordConfig("Data\\PBRMaterialObjects", selectedPbrMaterialObjectName, *selectedPbrMaterialObject);
-				}
+			if (ImGui::Button("Save")) {
+				PNState::SavePBRRecordConfig("Data\\PBRMaterialObjects", selectedPbrMaterialObjectName, *selectedPbrMaterialObject);
 			}

Also applies to: 293-297

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/TruePBR.cpp` around lines 187 - 191, Remove the redundant nullptr checks
inside the inner Save button blocks: the ImGui::Button("Save") handlers that
call PNState::SavePBRRecordConfig already live inside outer guards that ensure
selectedPbrTextureSet and selectedPbrMaterialObject are non-null, so delete the
inner "if (selectedPbrTextureSet != nullptr)" and "if (selectedPbrMaterialObject
!= nullptr)" checks and leave the button + PNState::SavePBRRecordConfig calls
directly under the existing outer guards; this simplifies the control flow while
preserving the same behavior for selectedPbrTextureSet,
selectedPbrTextureSetName and selectedPbrMaterialObject.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/TruePBR.cpp`:
- Around line 187-191: Remove the redundant nullptr checks inside the inner Save
button blocks: the ImGui::Button("Save") handlers that call
PNState::SavePBRRecordConfig already live inside outer guards that ensure
selectedPbrTextureSet and selectedPbrMaterialObject are non-null, so delete the
inner "if (selectedPbrTextureSet != nullptr)" and "if (selectedPbrMaterialObject
!= nullptr)" checks and leave the button + PNState::SavePBRRecordConfig calls
directly under the existing outer guards; this simplifies the control flow while
preserving the same behavior for selectedPbrTextureSet,
selectedPbrTextureSetName and selectedPbrMaterialObject.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 60ebc2fd-d17c-4c01-b3e3-dcb29650b1a2

📥 Commits

Reviewing files that changed from the base of the PR and between 5c2d3d2 and d439a12.

📒 Files selected for processing (20)
  • features/TruePBR/CORE
  • features/TruePBR/Shaders/Features/TruePBR.ini
  • src/Deferred.cpp
  • src/Feature.cpp
  • src/Feature.h
  • src/FeatureBuffer.cpp
  • src/Features/TerrainHelper.cpp
  • src/Features/TerrainHelper.h
  • src/Globals.cpp
  • src/Globals.h
  • src/Hooks.cpp
  • src/Menu.cpp
  • src/Menu/AdvancedSettingsRenderer.cpp
  • src/Menu/AdvancedSettingsRenderer.h
  • src/State.cpp
  • src/State.h
  • src/TruePBR.cpp
  • src/TruePBR.h
  • src/TruePBR/BSLightingShaderMaterialPBR.cpp
  • src/XSEPlugin.cpp
💤 Files with no reviewable changes (7)
  • src/State.h
  • src/XSEPlugin.cpp
  • src/Menu/AdvancedSettingsRenderer.h
  • src/Deferred.cpp
  • src/Menu.cpp
  • src/Menu/AdvancedSettingsRenderer.cpp
  • src/FeatureBuffer.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/Feature.cpp (1)

213-231: Document the TruePBR-before-TerrainHelper ordering.

PostPostLoad() runs in GetFeatureList() order, and both src/TruePBR.cpp and src/Features/TerrainHelper.cpp hook TESObjectLAND / BSLightingShader::SetupMaterial. The current flag-8 coordination only works because truePBR is listed before terrainHelper. A short comment here would make that coupling much harder to break in a future reorder.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Feature.cpp` around lines 213 - 231, Add a brief comment in the feature
list to document the required ordering of truePBR before terrainHelper: explain
that PostPostLoad() runs in GetFeatureList() order and both src/TruePBR.cpp
(truePBR) and src/Features/TerrainHelper.cpp (terrainHelper) hook TESObjectLAND
/ BSLightingShader::SetupMaterial, so the current flag-8 coordination depends on
truePBR appearing before terrainHelper; place this comment adjacent to the
&globals::features::truePBR and &globals::features::terrainHelper entries so
future reorders preserve the dependency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Feature.cpp`:
- Around line 213-231: Add a brief comment in the feature list to document the
required ordering of truePBR before terrainHelper: explain that PostPostLoad()
runs in GetFeatureList() order and both src/TruePBR.cpp (truePBR) and
src/Features/TerrainHelper.cpp (terrainHelper) hook TESObjectLAND /
BSLightingShader::SetupMaterial, so the current flag-8 coordination depends on
truePBR appearing before terrainHelper; place this comment adjacent to the
&globals::features::truePBR and &globals::features::terrainHelper entries so
future reorders preserve the dependency.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 379ab4a2-6163-49c0-9625-02e6dd09fc4a

📥 Commits

Reviewing files that changed from the base of the PR and between d439a12 and bb2db1c.

📒 Files selected for processing (20)
  • features/TruePBR/CORE
  • features/TruePBR/Shaders/Features/TruePBR.ini
  • src/Deferred.cpp
  • src/Feature.cpp
  • src/Feature.h
  • src/FeatureBuffer.cpp
  • src/Features/TerrainHelper.cpp
  • src/Features/TerrainHelper.h
  • src/Globals.cpp
  • src/Globals.h
  • src/Hooks.cpp
  • src/Menu.cpp
  • src/Menu/AdvancedSettingsRenderer.cpp
  • src/Menu/AdvancedSettingsRenderer.h
  • src/State.cpp
  • src/State.h
  • src/TruePBR.cpp
  • src/TruePBR.h
  • src/TruePBR/BSLightingShaderMaterialPBR.cpp
  • src/XSEPlugin.cpp
💤 Files with no reviewable changes (7)
  • src/FeatureBuffer.cpp
  • src/State.h
  • src/Menu/AdvancedSettingsRenderer.h
  • src/XSEPlugin.cpp
  • src/Menu.cpp
  • src/Deferred.cpp
  • src/Menu/AdvancedSettingsRenderer.cpp
✅ Files skipped from review due to trivial changes (1)
  • features/TruePBR/Shaders/Features/TruePBR.ini
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/Features/TerrainHelper.h
  • src/Globals.cpp
  • src/TruePBR/BSLightingShaderMaterialPBR.cpp

@doodlum doodlum marked this pull request as draft April 26, 2026 22:48
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 26, 2026

✅ A pre-release build is available for this PR:
Download

@alandtse alandtse added deferred Defer to next cycle and removed deferred Defer to next cycle labels Apr 29, 2026
@alandtse alandtse marked this pull request as ready for review May 2, 2026 06:43
alandtse and others added 6 commits May 3, 2026 02:40
TruePBR now inherits from Feature and participates in the standard
ForEachLoadedFeature lifecycle instead of being special-cased throughout
the codebase. Removes the singleton pattern, specialFeatures map, and
direct lifecycle calls scattered across State, Deferred, XSEPlugin, and
Menu. Adds IsCore(), GetFeatureSummary(), and correct category/VR flags.
Creates features/TruePBR/CORE marker for AIO packaging.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fold SetupFrame() into Prepass() — removes the direct call from Deferred.cpp
- Add virtual GenerateShaderPermutations(RE::BSShader*) to Feature base;
  Hooks.cpp now calls it via ForEachLoadedFeature instead of a direct
  TruePBR reference, making the hook extensible to any future feature
- Move TESObjectLAND and BSLightingShader material hook installation from
  Hooks::Install() into TruePBR::PostPostLoad(), removing Hooks.cpp's
  dependency on TruePBR entirely
- TerrainHelper installs its own TESObjectLAND and BSLightingShader hooks
  in its new PostPostLoad(), removing TerrainHelper calls from TruePBR's
  hook bodies; TerrainHelper skips PBR land cells via the flag-8 sentinel
  set by TruePBR::TESObjectLAND_SetupMaterial

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Set IsInMenu() = true so TruePBR appears in the regular feature
sidebar under the Materials category, where DrawSettings() is already
called for all loaded features. Remove the dedicated "PBR Settings"
tab from the Advanced menu and its RenderPBRSection helper.

Add Doxygen comment to Feature::GenerateShaderPermutations explaining
its contract and cold-path usage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…messages

Follows the [FEATURE_NAME] convention used across the codebase (e.g.
[SKYLIGHTING]) so hook installation messages are attributable in the
log without ambiguity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Core features still need a version INI so the standard Feature::Load
path (version check, settings load, error reporting) works without any
special-casing. Adding features/TruePBR/Shaders/Features/TruePBR.ini
at version 1-0-0 also registers TruePBR in the CMake-generated
FEATURE_MINIMAL_VERSIONS map, making IsFeatureKnown() return true.

Reverts the incorrect virtual keyword on Feature::Load(json&) and the
TruePBR::Load override that was the original workaround.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@alandtse alandtse merged commit d919016 into community-shaders:dev May 3, 2026
13 checks passed
SkrubbySkrubInAShrub pushed a commit that referenced this pull request May 14, 2026
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ParticleTroned pushed a commit to ParticleTroned/skyrim-community-shaders that referenced this pull request May 15, 2026
Branch-preserving adaptation of upstream community-shaders#2210: keep this branch's combined TruePBR/TerrainHelper material hook path and existing PBR settings UI while routing TruePBR lifecycle through Feature.

Do not add HDR, Exponential Height Fog, or Volumetric Shadows feature wiring.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ParticleTroned pushed a commit to ParticleTroned/skyrim-community-shaders that referenced this pull request May 16, 2026
Branch-preserving adaptation of upstream community-shaders#2210: keep this branch's combined TruePBR/TerrainHelper material hook path and existing PBR settings UI while routing TruePBR lifecycle through Feature.

Do not add HDR, Exponential Height Fog, or Volumetric Shadows feature wiring.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
alandtse added a commit that referenced this pull request May 18, 2026
Hooks.cpp no longer references TruePBR or TerrainHelper directly. Adds
a small multi-subscriber dispatcher in Hooks::MaterialHooks that each
feature registers against from its own PostPostLoad, restoring the
feature boundary that PR #2210 established while keeping a single
detour/vfunc install per address.

Semantics preserved from the prior consolidated thunk:
- TESObjectLAND::SetupMaterial: vanilla first, then post callbacks in
  registration order; first callback to return true claims the result.
  TruePBR registers a claiming post-callback; TerrainHelper observes.
- BSLightingShader::SetupMaterial: interceptors before vanilla (return
  true to skip vanilla and the post chain), post callbacks after.
  TruePBR is an interceptor; TerrainHelper is post.

A single HookChain<Fn> template backs each slot - range-for over a
vector of function pointers, no std::function, no allocation. Adding a
new dispatch slot is a one-liner accessor.

Registration order is deterministic via Feature::GetFeatureList()
(TruePBR ahead of TerrainHelper), so PBR's claim short-circuits
TerrainHelper on PBR land cells. The flag-8 gate stays in
TerrainHelper as a defensive backstop.
alandtse added a commit that referenced this pull request May 18, 2026
Hooks.cpp no longer references TruePBR or TerrainHelper directly. Adds
a small multi-subscriber dispatcher in Hooks::MaterialHooks that each
feature registers against from its own PostPostLoad, restoring the
feature boundary that PR #2210 established while keeping a single
detour/vfunc install per address.

Semantics preserved from the prior consolidated thunk:
- TESObjectLAND::SetupMaterial: vanilla first, then post callbacks in
  registration order; first callback to return true claims the result.
  TruePBR registers a claiming post-callback; TerrainHelper observes.
- BSLightingShader::SetupMaterial: interceptors before vanilla (return
  true to skip vanilla and the post chain), post callbacks after.
  TruePBR is an interceptor; TerrainHelper is post.

A single HookChain<Fn> template backs each slot - range-for over a
vector of function pointers, no std::function, no allocation. Adding a
new dispatch slot is a one-liner accessor.

Registration order is deterministic via Feature::GetFeatureList()
(TruePBR ahead of TerrainHelper), so PBR's claim short-circuits
TerrainHelper on PBR land cells. The flag-8 gate stays in
TerrainHelper as a defensive backstop.
alandtse added a commit that referenced this pull request May 18, 2026
Hooks.cpp no longer references TruePBR or TerrainHelper directly. Adds
a small multi-subscriber dispatcher in Hooks::MaterialHooks that each
feature registers against from its own PostPostLoad, restoring the
feature boundary that PR #2210 established while keeping a single
detour/vfunc install per address.

Semantics preserved from the prior consolidated thunk:
- TESObjectLAND::SetupMaterial: vanilla first, then post callbacks in
  registration order; first callback to return true claims the result.
  TruePBR registers a claiming post-callback; TerrainHelper observes.
- BSLightingShader::SetupMaterial: interceptors before vanilla (return
  true to skip vanilla and the post chain), post callbacks after.
  TruePBR is an interceptor; TerrainHelper is post.

A single HookChain<Fn> template backs each slot - range-for over a
vector of function pointers, no std::function, no allocation. Adding a
new dispatch slot is a one-liner accessor.

Registration order is deterministic via Feature::GetFeatureList()
(TruePBR ahead of TerrainHelper), so PBR's claim short-circuits
TerrainHelper on PBR land cells. The flag-8 gate stays in
TerrainHelper as a defensive backstop.
IgorAlanAlbuquerque pushed a commit to IgorAlanAlbuquerque/skyrim-community-shaders that referenced this pull request May 29, 2026
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

3 participants