Skip to content

feat: order independent transparency - #2564

Open
ArcEarth wants to merge 15 commits into
community-shaders:devfrom
ArcEarth:order_independent_transparency_3
Open

feat: order independent transparency#2564
ArcEarth wants to merge 15 commits into
community-shaders:devfrom
ArcEarth:order_independent_transparency_3

Conversation

@ArcEarth

@ArcEarth ArcEarth commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Order Independent Transparency (OIT) for overlapping transparent surfaces such as water, hair, glass, foliage, smoke, and particles. Rather than relying on Skyrim's transparent-geometry ordering, the feature captures the alpha pass into OIT-specific resources and composites the result after the engine has rendered that pass.

Demonstration

OIT_Test_7_Fast

Integration overview

  • Engine alpha pass: OIT brackets Skyrim's native transparent-geometry pass, captures its transparent output, then resolves it immediately afterward. See Engine integration.
  • Water: Semi-transparent geometry now participates in the historical scene data used by water refraction and reflections instead of disappearing. See Water refraction and reflection.
  • HDR Display: OIT prevents HDR Display's global UI alpha-blend rewrite from modifying OIT accumulation states. This exposes an HDR hook that should be narrowed to UI composition. See HDR blend-state interaction.

OIT implementations

Menu method Implementation Details
Fast Approximation Weighted Blended OIT Accumulates weighted premultiplied color and revealage in FP16 render targets, then resolves them in image space. This is inexpensive and stable for fog, hair, and grass, but is an approximation for dense/opaque layer stacks.
Balanced Adaptive Transparency / A-buffer fragment list Uses an atomic per-pixel linked list backed by a bounded global fragment pool. The resolve reads and depth-sorts the captured fragments; over-budget layers use an approximation. Nodes pack FP16 RGBA color and depth/write-depth state.
Quality Intel Adaptive OIT (AOIT/MLAB) Uses Rasterizer Ordered Views (ROVs) and a bounded per-pixel node array. Insertion maintains ordered depth, cumulative transmittance, and HDR FP16 RGBA color; depth remains full 32-bit float. Requires DirectX 11.3 or newer.

Engine integration

  • Detours Main::RenderWorld::RenderTransparency, which owns Skyrim's alpha-blended geometry pass. The hook initializes OIT collection before the original pass, lets the engine render its normal transparent geometry, then resolves and composites the captured result immediately afterward.
  • Installs SetupGeometry and RestoreGeometry wrappers (vtable slots 0x6 and 0x7) for Lighting, Effect, Water, Utility, Particle, Grass, Distant Tree, Blood Splatter, and Sky shaders. These wrappers apply and clear the per-draw OIT descriptors without depending on the optional Frame Annotations feature.
  • Redirects the output-merger targets during collection while retaining the engine's main, TAA-mask, alpha-only, and appropriate pre-/post-water depth surfaces. This preserves water/refraction handling and allows optional composition-time depth writes.
  • Captures alpha, additive, multiplicative, and multiplicative-alpha materials; provides visualization, distance gating, buffer/layer controls, compatibility controls, timings, shader-cache invalidation, and safe feature shutdown when resource creation fails.

Water refraction and reflection

The engine's water shaders sample prior-frame scene data for their refraction/reflection path. Without OIT-aware handling, semi-transparent geometry captured outside the normal scene color was absent from that sample, making it disappear through water and in water reflections.

  • OIT provisions kMAIN_ONLY_ALPHA as a shader-readable target and writes the composed transparent color and coverage there alongside the main/TAA targets.
  • BeginWater() binds that target at t66; Water.hlsl reconstructs the refraction world position, derives the camera motion vector, and samples the alpha-only target at the previous-frame, dynamic-resolution-adjusted UV.
  • Water composites the reprojected transparent contribution as lerp(refractionColor, alphaOnly.rgb, alphaOnly.a) before calculating its refraction result. The transparent scene content therefore participates in the water refraction/reflection data rather than being treated as invisible.

HDR blend-state interaction

HDR Display globally detours ID3D11DeviceContext::OMSetBlendState to repair alpha blending for its separate UI capture buffer. That broad rewrite is an existing HDR-feature bug for non-UI rendering: it changes the alpha factors requested by an active render pass, including OIT's specialized accumulation states.

This branch contains an interoperability guard: HDR skips its blend-state patch while OrderIndependentTransparency::inAlphaPass is true, preserving OIT collection and composition blend semantics. The underlying HDR hook remains overly broad and should be constrained to its UI-composition scope in follow-up work.

References

Validation

  • cmake --build --preset Dev
  • python tools/extract-i18n.py --check
  • python tools/extract-i18n.py --orphans
  • python tools/sort-i18n.py --check
  • In-game validation of every method, material blend mode, water/refraction, depth writing, HDR emissives, deep overlap, and distance gating.
  • D3D debug-layer validation of AOIT ROV buffer layouts at 4 and 8 layers.

Notes

Quality/AOIT is production-ready but carries a higher performance cost than the other methods. This PR remains a draft while the in-game validation matrix is completed.

Summary by CodeRabbit

  • New Features
    • Added order-independent transparency support with Adaptive, Weighted Blended, visualization, and quality-focused rendering modes.
    • Added configurable transparency thresholds, layer limits, buffer sizing, multiplicative blending, depth writing, and render-target options.
    • Added water and particle transparency integration, including improved compositing and depth handling.
    • Added performance diagnostics for transparency passes and composition.
  • Documentation
    • Added localized settings labels and tooltips across supported languages.
  • Bug Fixes
    • Improved motion-vector reprojection for reflections and water refraction.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a configurable Order Independent Transparency feature with fragment capture, adaptive/rasterizer-ordered and weighted-blended resolve paths, GPU resource management, shader permutation integration, rendering hooks, water/reflection updates, and localized settings.

Changes

Order Independent Transparency

Layer / File(s) Summary
OIT contracts and shared configuration
src/Features/OrderIndependentTransparency.h, package/Shaders/Common/SharedData.hlsli, src/State.h, src/ShaderCache.h, features/Order Independent Transparency/Shaders/OIT/OITCommon.hlsli
Defines OIT settings, shader constants, storage layouts, descriptor flags, shader-cache flags, and shared feature-buffer data.
Fragment capture implementations
features/Order Independent Transparency/Shaders/OIT/*Capture*, features/Order Independent Transparency/Shaders/OIT/FragmentList.hlsli, features/Order Independent Transparency/Shaders/OIT/AOIT.hlsli, features/Order Independent Transparency/Shaders/OIT/DXAOIT.hlsli, features/Order Independent Transparency/Shaders/OIT/WBOIT.hlsli
Adds fragment-list, AOIT, and WBOIT packing, insertion, storage, and capture routines.
Resolve shaders
features/Order Independent Transparency/Shaders/OIT/*Resolve*, features/Order Independent Transparency/Shaders/OIT/Quad.hlsl
Adds AOIT, adaptive, debug, and weighted-blended resolve paths with fullscreen shader output handling.
Runtime lifecycle and GPU resources
src/Features/OrderIndependentTransparency.*, src/Feature*.cpp, src/Globals.*, src/Deferred.cpp, src/Hooks.cpp
Registers the feature, persists settings, allocates resources, manages alpha and resolve passes, integrates water handling, and tracks timing.
Shader permutation and rendering integration
src/State.cpp, src/ShaderCache.*, package/Shaders/{Lighting,Effect,Particle}.hlsl
Propagates OIT descriptor bits and shader defines, adds OIT render targets, and routes pixel shader output through capture helpers.
Supporting shader and localization updates
package/Shaders/Common/MotionBlur.hlsli, package/Shaders/{Water,ISReflectionsRayTracing}.hlsl, src/Features/{HDRDisplay,ExtendedTranslucency}.cpp, package/SKSE/Plugins/CommunityShaders/Translations/*
Adds camera-motion reprojection support, updates depth and refraction sampling, adjusts blend and alpha gating, and adds OIT translations.
Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.32% 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 accurately names the primary change: adding order independent transparency support.
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

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.

@ArcEarth ArcEarth changed the title feat(oit): implement order independent transparency feat: order independent transparency Jul 16, 2026
@github-actions

Copy link
Copy Markdown

No actionable suggestions for changed features.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ArcEarth
ArcEarth force-pushed the order_independent_transparency_3 branch from 3010804 to b66b953 Compare July 17, 2026 00:04
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ArcEarth
ArcEarth marked this pull request as ready for review July 17, 2026 15:28
Copilot AI review requested due to automatic review settings July 17, 2026 15:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new rendering feature—Order Independent Transparency (OIT)—to improve blending correctness for overlapping transparent surfaces (water, hair, particles, etc.) by capturing Skyrim’s transparency pass into OIT resources and compositing the result after the engine’s alpha pass. This integrates into the existing feature system, shader compilation pipeline, and several shader stages (including water refraction/SSR interactions and HDR blend-state interoperability).

Changes:

  • Introduces OrderIndependentTransparency feature with multiple OIT methods (weighted blended, fragment list / adaptive transparency, and ROV-based AOIT), including resource setup, capture, and resolve/composite.
  • Extends shader descriptor/define plumbing so Lighting/Effect/Particle shaders can compile OIT permutations and include OIT capture paths.
  • Adds engine-level hooks/guards for alpha-pass bracketing, water integration (alpha-only reprojection input), and HDR blend-state compatibility during OIT capture.

Reviewed changes

Copilot reviewed 50 out of 50 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/State.h Adds PerfEvent RAII helper and OIT-related extra descriptor flags.
src/State.cpp Integrates OIT into draw flow and shader-lookup descriptor mutations; adds wide perf-marker helpers.
src/ShaderCache.h Adds OIT shader flags (Lighting/Effect) and particle OIT flag bit.
src/ShaderCache.cpp Injects OIT shader defines into Lighting/Effect/Particle compilation define lists.
src/Menu/ThemeManager.h Updates theme JSON documentation comment (status palette).
src/Menu/ThemeManager.cpp Updates disabled text alpha comment.
src/Hooks.cpp Adds OIT feature include and calls OIT pre-dirty-state hook; updates render target hook relocation offsets.
src/Globals.h Registers OrderIndependentTransparency in global feature declarations.
src/Globals.cpp Instantiates global OrderIndependentTransparency feature instance.
src/FrameAnnotations.cpp Removes shader setup/restore annotation hooks and renames an annotation scope label.
src/Features/OrderIndependentTransparency.h New feature interface, settings, buffers, and capture/resolve API.
src/Features/OrderIndependentTransparency.cpp New feature implementation: hooks, resource creation, capture bracketing, resolve/composite, water SRV binding.
src/Features/LightLimitFix.h Renames a LightLimitFix flag constant.
src/Features/InverseSquareLighting.cpp Updates usage of the renamed LightLimitFix flag.
src/Features/HDRDisplay.cpp Adds an OIT guard to avoid HDR blend-state rewrite during OIT alpha pass.
src/Features/ExtendedTranslucency.h Renames enum constants/comments related to “Disabled”.
src/Features/ExtendedTranslucency.cpp Updates translucency alpha detection and enum usage.
src/FeatureBuffer.cpp Adds OIT feature constant-buffer payload to the shared feature buffer.
src/Feature.cpp Registers OIT in the global feature list ordering.
src/Deferred.cpp Hooks water boundary to bind alpha-only SRV for refraction/SSR reprojection.
package/SKSE/Plugins/CommunityShaders/Translations/zh_CN.json Adds OIT UI strings (Chinese).
package/SKSE/Plugins/CommunityShaders/Translations/ru.json Adds OIT UI strings (Russian).
package/SKSE/Plugins/CommunityShaders/Translations/pl.json Adds OIT UI strings (Polish).
package/SKSE/Plugins/CommunityShaders/Translations/nl.json Adds OIT UI strings (Dutch).
package/SKSE/Plugins/CommunityShaders/Translations/ja.json Adds OIT UI strings (Japanese).
package/SKSE/Plugins/CommunityShaders/Translations/fr.json Adds OIT UI strings (French).
package/SKSE/Plugins/CommunityShaders/Translations/es.json Adds OIT UI strings (Spanish).
package/SKSE/Plugins/CommunityShaders/Translations/en.json Adds OIT UI strings (English).
package/SKSE/Plugins/CommunityShaders/Translations/de.json Adds OIT UI strings (German).
package/Shaders/Water.hlsl Adds alpha-only reprojection sampling for water refraction/reflect; adjusts depth texture type and motion-vector usage.
package/Shaders/Particle.hlsl Adds OIT capture include and outputs for blended OIT; enables early depth-stencil for OIT permutations.
package/Shaders/Lighting.hlsl Adds OIT capture include/outputs and early depth-stencil attribute for OIT permutations.
package/Shaders/ISReflectionsRayTracing.hlsl Adjusts depth texture type and updates camera motion vector helper; tweaks SSR alpha integration.
package/Shaders/Effect.hlsl Adds OIT capture include/outputs and early depth-stencil attribute for OIT permutations.
package/Shaders/Common/SharedData.hlsli Adds OIT settings struct into shared shader constant buffer layout.
package/Shaders/Common/MotionBlur.hlsli Adds GetSSMotionVector2 helper for camera motion vector computation.
features/Order Independent Transparency/Shaders/OIT/WBOITWeight.hlsli New WBOIT weight function.
features/Order Independent Transparency/Shaders/OIT/WBOITResolve.hlsli New WBOIT resolve function (with optional depth write).
features/Order Independent Transparency/Shaders/OIT/WBOIT.hlsli New WBOIT capture implementation.
features/Order Independent Transparency/Shaders/OIT/Quad.hlsl New (licensed) fullscreen quad VS helper from Intel sample.
features/Order Independent Transparency/Shaders/OIT/OITResolve.ps.hlsl New pixel-shader resolve/composite entry point selecting OIT method resolve.
features/Order Independent Transparency/Shaders/OIT/OITResolve.cs.hlsl New compute-shader resolve/composite entry point (A-buffer resolve path).
features/Order Independent Transparency/Shaders/OIT/OITCommon.hlsli New shared OIT constants/flags for shader capture/resolve.
features/Order Independent Transparency/Shaders/OIT/OITCapture.hlsli New unified capture wrapper for fragment list / AOIT / WBOIT.
features/Order Independent Transparency/Shaders/OIT/FragmentList.hlsli New fragment-list (linked list) capture implementation.
features/Order Independent Transparency/Shaders/OIT/DXAOITResolve.hlsli New resolve implementation for fragment list (and debug/weighted reference).
features/Order Independent Transparency/Shaders/OIT/DXAOIT.hlsli New AOIT visibility-function implementation (Intel sample-derived).
features/Order Independent Transparency/Shaders/OIT/AOITResolve.hlsli New AOIT resolve implementation (ROV path).
features/Order Independent Transparency/Shaders/OIT/AOIT.hlsli New AOIT capture implementation (ROV/structured buffers).
features/Order Independent Transparency/Shaders/Features/OrderIndependentTransparency.ini New feature shader-version ini for OIT.

Comment thread src/State.h Outdated
Comment on lines +195 to +200
struct PerfEvent
{
PerfEvent(const wchar_t* title);
PerfEvent(const PerfEvent&) = delete;
PerfEvent(PerfEvent&&) = default;
~PerfEvent();
Comment thread src/State.cpp Outdated
// Need to capture pre-water depth
auto& preWaterDepth = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPOST_ZPREPASS_COPY];
dsv = preWaterDepth.readOnlyViews[0];
static constexpr UINT uavcounters[2] = { 1, 1 };
Comment on lines +965 to +977
#if defined(OIT)
#if OIT == 3 && !defined(DEFERRED)
WBOITResult oit = OIT_CaptureWBOIT(int2(input.Position.xy), psout.Diffuse, input.Position.z);
psout.OITFrontAccumalation = oit.accumFront;
psout.OITAccumalation = oit.accumAll;
psout.OITRevealage = oit.revealage;
#else
psout.Diffuse = OIT_Capture(int2(input.Position.xy), psout.Diffuse, input.Position.z);
#if !defined(MOTIONVECTORS_NORMALS)
psout.Color2 = psout.Diffuse;
#endif
#endif
#endif
Comment on lines +24 to +30
// blend alpha only colors with existing color
float4 ecolor = RT_ALPHA[DTid.xy];
ecolor.xyz = ecolor.xyz * ecolor.w + wcolor.xyz;
ecolor.w = ecolor.w * wcolor.w;
wcolor.w = 1.0 - wcolor.w;
if (wcolor.w > 0.f) wcolor.xyz /= wcolor.w;
RT_ALPHA[DTid.xy] = wcolor;
Comment thread package/Shaders/Water.hlsl Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 15

🧹 Nitpick comments (3)
src/Features/OrderIndependentTransparency.cpp (1)

956-960: 📐 Maintainability & Code Quality | 🔵 Trivial

Resolve or remove the unfinished implementation placeholder.

Complete the geometry consolidation, or move the deferred work to a tracked issue and retain only an explanatory comment.

As per coding guidelines, src/**/*.{h,cpp} must “Provide complete, fully functional code without TODO/FIXME placeholders in feature implementations”.

Would you like me to draft the implementation or issue text?

🤖 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 `@src/Features/OrderIndependentTransparency.cpp` around lines 956 - 960, Remove
the TODO placeholder in the geometry handling section of
OrderIndependentTransparency.cpp. Either implement the deferred Z-Buffer Write
geometry consolidation into a single draw call, or replace the TODO block with a
concise explanatory comment referencing a tracked issue for the deferred work;
do not leave TODO/FIXME markers in the feature implementation.

Source: Coding guidelines

package/Shaders/Lighting.hlsl (1)

306-310: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Typo in variable name. The variable names OITFrontAccumalation and OITAccumalation contain a typo ("Accumalation" instead of "Accumulation"). Consider fixing this typo across all shaders to improve maintainability.

  • package/Shaders/Lighting.hlsl#L306-L310: Rename OITFrontAccumalation to OITFrontAccumulation and OITAccumalation to OITAccumulation.
  • package/Shaders/Effect.hlsl#L413-L417: Rename OITFrontAccumalation to OITFrontAccumulation and OITAccumalation to OITAccumulation.
  • package/Shaders/Particle.hlsl#L192-L196: Rename OITFrontAccumalation to OITFrontAccumulation and OITAccumalation to OITAccumulation.
🤖 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/Lighting.hlsl` around lines 306 - 310, Rename
OITFrontAccumalation to OITFrontAccumulation and OITAccumalation to
OITAccumulation in the declarations at package/Shaders/Lighting.hlsl:306-310,
package/Shaders/Effect.hlsl:413-417, and package/Shaders/Particle.hlsl:192-196,
updating all corresponding references in those shaders.
package/Shaders/Particle.hlsl (1)

5-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Typo in macro definition.

The macro OIT_CAPTURE_IGNORE_ALPHA_THRESHOULD contains a typo ("THRESHOULD" instead of "THRESHOLD"). Consider fixing this here and in OITCapture.hlsli to maintain correctness and readability.

🤖 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/Particle.hlsl` around lines 5 - 9, Rename the misspelled
macro OIT_CAPTURE_IGNORE_ALPHA_THRESHOULD to OIT_CAPTURE_IGNORE_ALPHA_THRESHOLD
in Particle.hlsl and update the matching definition or references in
OITCapture.hlsli so all conditional checks use the corrected symbol
consistently.
🤖 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.

Inline comments:
In `@features/Order` Independent Transparency/Shaders/OIT/AOIT.hlsli:
- Around line 160-165: Update the overflow merge in AOIT's [flatten] block to
guard the division by trans[OIT_NODE_COUNT - 2] when that preceding
transmittance is zero. Skip the color contribution or otherwise preserve the
opaque-layer result in that case, while retaining the existing transmittance
update and normal merge behavior for nonzero values.

In `@features/Order` Independent Transparency/Shaders/OIT/FragmentList.hlsli:
- Around line 57-67: Update FL_UnpackDepthAndFlags to detect the packed float’s
sign bit rather than comparing packedDepthAndFlags numerically, so negative zero
from depth 1.0 restores OIT_FLAGS_DEPTH_WRITE while preserving the existing
depth unpacking.

In `@features/Order` Independent Transparency/Shaders/OIT/OITResolve.cs.hlsl:
- Around line 24-30: Update the alpha-only resolve logic to write the composed
ecolor result to RT_ALPHA instead of wcolor. After combining the existing target
color and opacity, convert ecolor to the target’s opacity representation as
needed, then store ecolor so successive dispatches preserve blending with the
existing RT_ALPHA contents.

In `@features/Order` Independent Transparency/Shaders/OIT/WBOITWeight.hlsli:
- Around line 4-8: Update WBOITComputeWeight so the minimum depth factor does
not make ordinary alpha values clamp to the maximum weight; preserve meaningful
depth-based variation for fragments across the normal alpha range. Adjust the
weighting constants or final clamp bounds in this function, ensuring only
genuinely high-weight fragments reach 1.0 while retaining the existing
lower-bound protection.

In `@package/Shaders/Effect.hlsl`:
- Around line 391-396: Update the OIT output declarations and main shader output
logic in Effect.hlsl so DEFERRED with OIT == 3 initializes OITRevealage and
OITFrontAccum despite the existing non-deferred guard. In the final `#else`
branch, avoid assigning psout.Color2 when DEFERRED is defined, and ensure every
PS_OUTPUT member is initialized without referencing undefined members.
- Around line 965-977: Guard the psout.Color2 assignment in the OIT Capture
branch with a DEFERRED check in addition to MOTIONVECTORS_NORMALS, so it only
runs for non-deferred scenarios. Leave the OIT_Capture and psout.Diffuse
handling unchanged.

In `@package/Shaders/ISReflectionsRayTracing.hlsl`:
- Around line 117-119: Update the alpha texture sampling in the reflection
composition to retain the full float4 result from AlphaTex, including its
original w channel, instead of reconstructing it with a hardcoded alpha of 1.0.
Keep the existing reflectionColor blend using alpha.w unchanged.

In `@package/SKSE/Plugins/CommunityShaders/Translations/es.json`:
- Line 129: Localize the final distance-unit sentence in the distance threshold
tooltip at package/SKSE/Plugins/CommunityShaders/Translations/es.json:129-129,
package/SKSE/Plugins/CommunityShaders/Translations/fr.json:145-145,
package/SKSE/Plugins/CommunityShaders/Translations/nl.json:27-27, and
package/SKSE/Plugins/CommunityShaders/Translations/pl.json:111-111, translating
“1 unit = 1.428 cm or 0.5625 in.” into each resource’s language while preserving
the numeric values and tooltip formatting.

In `@src/Features/OrderIndependentTransparency.cpp`:
- Around line 755-838: Update CreateStructBuffer and SetupPixelBuffers to
perform all GPU buffer size, stride, and element-count multiplications in
uint64_t, checking each result against the supported UINT/D3D11 limits before
converting to UINT. Reject overflow or unsupported dimensions before
constructing buffers, including color/depth strides, byte widths, and
fragment-list BufferSize/count calculations, and preserve the existing
resource-failure handling through DisableForResourceFailure().
- Around line 291-297: Update the Disabled radio button in the Method section of
OrderIndependentTransparency’s settings UI to propagate its RadioButton return
value into dirtied.ShaderDefines, matching the Visualize and other method
options. Preserve the existing tooltip and selection behavior while ensuring
selecting Method::OIT_DISABLED invalidates the OIT shader state.
- Around line 674-712: The CompileShaders method must report whether the
selected OIT resolve shader compiled successfully and disable the active OIT
method when it does not. Track compilation failure for the shader corresponding
to the configured method, have CompileShaders return that status, and update the
caller or OIT state so capture and EndAlphaGroup do not proceed with a null
resolve shader.
- Around line 635-650: Update the post-water depth-copy allocation block in
SetupResources() to route failures from CreateTexture2D,
CreateShaderResourceView, and CreateDepthStencilView through the existing
resource-failure handling, invoking DisableForResourceFailure() instead of
allowing ThrowIfFailed exceptions to escape. Preserve the current resource
creation order and descriptors.
- Around line 897-903: Move the distance-gating and drawWriteDepth evaluation
from SetupGeometry() into the descriptor computation performed before
PreDrawHack(), ensuring the resulting OITDisabledDescriptor and depth-write
state are available when PreDrawHack() consumes them. Update the related logic
at the descriptor paths around the shown sections, and preserve the existing
reset behavior after each draw.

In `@src/Globals.h`:
- Line 39: Update the pull request metadata rather than the declaration in
Globals.h: use a conventional commit title such as feat(oit): add order
independent transparency, and include applicable issue references such as Fixes
`#123` in the PR description.

In `@src/State.h`:
- Around line 194-210: The wide-string overload State::BeginPerfEvent(const
wchar_t*) must also create the Tracy zone expected by EndPerfEvent(). Route it
through the existing State::BeginPerfEvent(std::string_view) implementation, or
otherwise add equivalent Tracy setup while preserving the D3D annotation
behavior used by wide titles.

---

Nitpick comments:
In `@package/Shaders/Lighting.hlsl`:
- Around line 306-310: Rename OITFrontAccumalation to OITFrontAccumulation and
OITAccumalation to OITAccumulation in the declarations at
package/Shaders/Lighting.hlsl:306-310, package/Shaders/Effect.hlsl:413-417, and
package/Shaders/Particle.hlsl:192-196, updating all corresponding references in
those shaders.

In `@package/Shaders/Particle.hlsl`:
- Around line 5-9: Rename the misspelled macro
OIT_CAPTURE_IGNORE_ALPHA_THRESHOULD to OIT_CAPTURE_IGNORE_ALPHA_THRESHOLD in
Particle.hlsl and update the matching definition or references in
OITCapture.hlsli so all conditional checks use the corrected symbol
consistently.

In `@src/Features/OrderIndependentTransparency.cpp`:
- Around line 956-960: Remove the TODO placeholder in the geometry handling
section of OrderIndependentTransparency.cpp. Either implement the deferred
Z-Buffer Write geometry consolidation into a single draw call, or replace the
TODO block with a concise explanatory comment referencing a tracked issue for
the deferred work; do not leave TODO/FIXME markers in the feature
implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7c4184ec-85d7-4e09-986b-44bfda9d5527

📥 Commits

Reviewing files that changed from the base of the PR and between 6301d0f and f636288.

📒 Files selected for processing (50)
  • features/Order Independent Transparency/Shaders/Features/OrderIndependentTransparency.ini
  • features/Order Independent Transparency/Shaders/OIT/AOIT.hlsli
  • features/Order Independent Transparency/Shaders/OIT/AOITResolve.hlsli
  • features/Order Independent Transparency/Shaders/OIT/DXAOIT.hlsli
  • features/Order Independent Transparency/Shaders/OIT/DXAOITResolve.hlsli
  • features/Order Independent Transparency/Shaders/OIT/FragmentList.hlsli
  • features/Order Independent Transparency/Shaders/OIT/OITCapture.hlsli
  • features/Order Independent Transparency/Shaders/OIT/OITCommon.hlsli
  • features/Order Independent Transparency/Shaders/OIT/OITResolve.cs.hlsl
  • features/Order Independent Transparency/Shaders/OIT/OITResolve.ps.hlsl
  • features/Order Independent Transparency/Shaders/OIT/Quad.hlsl
  • features/Order Independent Transparency/Shaders/OIT/WBOIT.hlsli
  • features/Order Independent Transparency/Shaders/OIT/WBOITResolve.hlsli
  • features/Order Independent Transparency/Shaders/OIT/WBOITWeight.hlsli
  • package/SKSE/Plugins/CommunityShaders/Translations/de.json
  • package/SKSE/Plugins/CommunityShaders/Translations/en.json
  • package/SKSE/Plugins/CommunityShaders/Translations/es.json
  • package/SKSE/Plugins/CommunityShaders/Translations/fr.json
  • package/SKSE/Plugins/CommunityShaders/Translations/ja.json
  • package/SKSE/Plugins/CommunityShaders/Translations/nl.json
  • package/SKSE/Plugins/CommunityShaders/Translations/pl.json
  • package/SKSE/Plugins/CommunityShaders/Translations/ru.json
  • package/SKSE/Plugins/CommunityShaders/Translations/zh_CN.json
  • package/Shaders/Common/MotionBlur.hlsli
  • package/Shaders/Common/SharedData.hlsli
  • package/Shaders/Effect.hlsl
  • package/Shaders/ISReflectionsRayTracing.hlsl
  • package/Shaders/Lighting.hlsl
  • package/Shaders/Particle.hlsl
  • package/Shaders/Water.hlsl
  • src/Deferred.cpp
  • src/Feature.cpp
  • src/FeatureBuffer.cpp
  • src/Features/ExtendedTranslucency.cpp
  • src/Features/ExtendedTranslucency.h
  • src/Features/HDRDisplay.cpp
  • src/Features/InverseSquareLighting.cpp
  • src/Features/LightLimitFix.h
  • src/Features/OrderIndependentTransparency.cpp
  • src/Features/OrderIndependentTransparency.h
  • src/FrameAnnotations.cpp
  • src/Globals.cpp
  • src/Globals.h
  • src/Hooks.cpp
  • src/Menu/ThemeManager.cpp
  • src/Menu/ThemeManager.h
  • src/ShaderCache.cpp
  • src/ShaderCache.h
  • src/State.cpp
  • src/State.h

Comment thread features/Order Independent Transparency/Shaders/OIT/AOIT.hlsli
Comment on lines +57 to +67
float FL_PackDepthAndFlags(in float depth, in uint flags)
{
float packedDepth = saturate(1.0 - depth);
return (flags & OIT_FLAGS_DEPTH_WRITE) ? -packedDepth : packedDepth;
}

void FL_UnpackDepthAndFlags(in float packedDepthAndFlags, out float depth, out uint flags)
{
depth = 1.0 - abs(packedDepthAndFlags);
flags = packedDepthAndFlags < 0 ? OIT_FLAGS_DEPTH_WRITE : 0;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Read the sign bit so depth 1.0 preserves the write flag.

A depth-writing fragment at exactly 1.0 packs as -0.0; packedDepthAndFlags < 0 is false for negative zero, so the flag is lost.

Proposed fix
 void FL_UnpackDepthAndFlags(in float packedDepthAndFlags, out float depth, out uint flags)
 {
 	depth = 1.0 - abs(packedDepthAndFlags);
-	flags = packedDepthAndFlags < 0 ? OIT_FLAGS_DEPTH_WRITE : 0;
+	flags = (asuint(packedDepthAndFlags) & 0x80000000UL) != 0
+		? OIT_FLAGS_DEPTH_WRITE
+		: 0;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
float FL_PackDepthAndFlags(in float depth, in uint flags)
{
float packedDepth = saturate(1.0 - depth);
return (flags & OIT_FLAGS_DEPTH_WRITE) ? -packedDepth : packedDepth;
}
void FL_UnpackDepthAndFlags(in float packedDepthAndFlags, out float depth, out uint flags)
{
depth = 1.0 - abs(packedDepthAndFlags);
flags = packedDepthAndFlags < 0 ? OIT_FLAGS_DEPTH_WRITE : 0;
}
float FL_PackDepthAndFlags(in float depth, in uint flags)
{
float packedDepth = saturate(1.0 - depth);
return (flags & OIT_FLAGS_DEPTH_WRITE) ? -packedDepth : packedDepth;
}
void FL_UnpackDepthAndFlags(in float packedDepthAndFlags, out float depth, out uint flags)
{
depth = 1.0 - abs(packedDepthAndFlags);
flags = (asuint(packedDepthAndFlags) & 0x80000000UL) != 0
? OIT_FLAGS_DEPTH_WRITE
: 0;
}
🤖 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 `@features/Order` Independent Transparency/Shaders/OIT/FragmentList.hlsli
around lines 57 - 67, Update FL_UnpackDepthAndFlags to detect the packed float’s
sign bit rather than comparing packedDepthAndFlags numerically, so negative zero
from depth 1.0 restores OIT_FLAGS_DEPTH_WRITE while preserving the existing
depth unpacking.

Comment on lines +24 to +30
// blend alpha only colors with existing color
float4 ecolor = RT_ALPHA[DTid.xy];
ecolor.xyz = ecolor.xyz * ecolor.w + wcolor.xyz;
ecolor.w = ecolor.w * wcolor.w;
wcolor.w = 1.0 - wcolor.w;
if (wcolor.w > 0.f) wcolor.xyz /= wcolor.w;
RT_ALPHA[DTid.xy] = wcolor;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Store the combined alpha-target color instead of discarding it.

ecolor receives the existing-target composition, but the shader normalizes and writes wcolor. Consequently, every dispatch replaces RT_ALPHA rather than blending with it. Convert the combined value to the target’s opacity representation and store ecolor.

Proposed fix
 	float4 ecolor = RT_ALPHA[DTid.xy];
 	ecolor.xyz = ecolor.xyz * ecolor.w + wcolor.xyz;
 	ecolor.w = ecolor.w * wcolor.w;
-	wcolor.w = 1.0 - wcolor.w;
-	if (wcolor.w > 0.f) wcolor.xyz /= wcolor.w;
-	RT_ALPHA[DTid.xy] = wcolor;
+	ecolor.w = 1.0 - ecolor.w;
+	if (ecolor.w > 0.f) ecolor.xyz /= ecolor.w;
+	RT_ALPHA[DTid.xy] = ecolor;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// blend alpha only colors with existing color
float4 ecolor = RT_ALPHA[DTid.xy];
ecolor.xyz = ecolor.xyz * ecolor.w + wcolor.xyz;
ecolor.w = ecolor.w * wcolor.w;
wcolor.w = 1.0 - wcolor.w;
if (wcolor.w > 0.f) wcolor.xyz /= wcolor.w;
RT_ALPHA[DTid.xy] = wcolor;
// blend alpha only colors with existing color
float4 ecolor = RT_ALPHA[DTid.xy];
ecolor.xyz = ecolor.xyz * ecolor.w + wcolor.xyz;
ecolor.w = ecolor.w * wcolor.w;
ecolor.w = 1.0 - ecolor.w;
if (ecolor.w > 0.f) ecolor.xyz /= ecolor.w;
RT_ALPHA[DTid.xy] = ecolor;
🤖 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 `@features/Order` Independent Transparency/Shaders/OIT/OITResolve.cs.hlsl
around lines 24 - 30, Update the alpha-only resolve logic to write the composed
ecolor result to RT_ALPHA instead of wcolor. After combining the existing target
color and opacity, convert ecolor to the target’s opacity representation as
needed, then store ecolor so successive dispatches preserve blending with the
existing RT_ALPHA contents.

Comment thread features/Order Independent Transparency/Shaders/OIT/WBOITWeight.hlsli Outdated
Comment on lines +391 to +396
# endif
# if defined(OIT) && OIT == 3 && !defined(MOTIONVECTORS_NORMALS)
float4 OITRevealage: SV_Target1;
# endif
# if defined(OIT) && OIT == 3 && !defined(MOTIONVECTORS_NORMALS) && !defined(NORMALS)
float4 OITFrontAccum: SV_Target2;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

Compilation failure when DEFERRED and OIT == 3 are defined.

When DEFERRED and OIT == 3 are both defined, OITRevealage and OITFrontAccum are added to the PS_OUTPUT struct but are never initialized in the main function (because the main function logic requires !defined(DEFERRED) to write to OIT outputs). In HLSL, failing to initialize all SV_Target struct members results in a compilation error.
Additionally, in the #else block at the end of the shader, psout.Color2 is assigned, but Color2 is not a member of PS_OUTPUT when DEFERRED is defined, which will cause another compilation error.

Please review the OIT capture logic for deferred effect shaders to ensure all struct members are properly initialized and no undefined members are accessed.

🤖 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/Effect.hlsl` around lines 391 - 396, Update the OIT output
declarations and main shader output logic in Effect.hlsl so DEFERRED with OIT ==
3 initializes OITRevealage and OITFrontAccum despite the existing non-deferred
guard. In the final `#else` branch, avoid assigning psout.Color2 when DEFERRED is
defined, and ensure every PS_OUTPUT member is initialized without referencing
undefined members.

Comment on lines +674 to +712
void OrderIndependentTransparency::CompileShaders()
{
// OIT_NODE_COUNT = MaxLayers
uint nodes = GetNodeCount();
char nodesStr[4] = { 0 };
std::to_chars(nodesStr, nodesStr + 4, nodes);
const char* writeDepthDefine = settings.WriteDepth ? "1" : "0";

logger::info("[OIT] Compiling Order Independent Transparency shaders, OIT_NODE_COUNT={}, OIT_WRITE_DEPTH={}...", nodesStr, writeDepthDefine);

if (/*settings.Method == OIT_VISUALIZE && */!psVisualize) {
if (auto rawPtr = reinterpret_cast<ID3D11PixelShader*>(Util::CompileShader(L"Data\\Shaders\\OIT\\OITResolve.ps.hlsl", { { "OIT_DEBUG", "1" } }, "ps_5_0"))) {
psVisualize.attach(rawPtr);
} else {
logger::error("Failed to compile Order Independent Transparency debug pixel shader.");
}
}
if (/*settings.Method == OIT_AT && */!psAT) {
if (auto rawPtr = reinterpret_cast<ID3D11PixelShader*>(Util::CompileShader(L"Data\\Shaders\\OIT\\OITResolve.ps.hlsl", { { "OIT_AT", "1" }, { "OIT_NODE_COUNT", nodesStr }, { "OIT_WRITE_DEPTH", writeDepthDefine } }, "ps_5_0"))) {
psAT.attach(rawPtr);
} else {
logger::error("Failed to compile Order Independent Transparency resolve pixel shader.");
}
}
if (/*settings.Method == OIT_BLENDED && */!psBlend) {
if (auto rawPtr = reinterpret_cast<ID3D11PixelShader*>(Util::CompileShader(L"Data\\Shaders\\OIT\\OITResolve.ps.hlsl", { { "OIT_BLENDED", "1" }, { "OIT_WRITE_DEPTH", writeDepthDefine } }, "ps_5_0"))) {
psBlend.attach(rawPtr);
} else {
logger::error("Failed to compile Order Independent Transparency blend pixel shader.");
}
}
if (/*settings.Method == OIT_RVO && */!psROV) {
if (auto rawPtr = reinterpret_cast<ID3D11PixelShader*>(Util::CompileShader(L"Data\\Shaders\\OIT\\OITResolve.ps.hlsl", { { "OIT_ROV", "1" }, { "OIT_NODE_COUNT", nodesStr }, { "OIT_WRITE_DEPTH", writeDepthDefine } }, "ps_5_0"))) {
psROV.attach(rawPtr);
} else {
logger::error("Failed to compile Order Independent Transparency ROV resolve pixel shader.");
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Disable the active method when its resolve shader fails to compile.

Compilation only logs failures. Capture still runs, then EndAlphaGroup() draws with a null shader, causing transparent geometry to disappear rather than shutting OIT down safely. Make compilation report success and disable OIT when the selected shader is unavailable.

🤖 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 `@src/Features/OrderIndependentTransparency.cpp` around lines 674 - 712, The
CompileShaders method must report whether the selected OIT resolve shader
compiled successfully and disable the active OIT method when it does not. Track
compilation failure for the shader corresponding to the configured method, have
CompileShaders return that status, and update the caller or OIT state so capture
and EndAlphaGroup do not proceed with a null resolve shader.

Comment on lines +755 to +838
static bool CreateStructBuffer(std::optional<Buffer>& buffer, std::string_view name, uint elements, uint size, bool counter = false)
{
CD3D11_BUFFER_DESC bufferDesc(
elements * size,
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS,
D3D11_USAGE_DEFAULT,
0,
D3D11_RESOURCE_MISC_BUFFER_STRUCTURED,
size);
try {
buffer.emplace(bufferDesc);
} catch (const DX::com_exception& e) {
logger::error("Failed to create {} buffer: {}", name, e.what());
return false;
}
buffer->resource->SetPrivateData(WKPDID_D3DDebugObjectName, (UINT)name.size(), name.data());

CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(
D3D11_SRV_DIMENSION_BUFFER,
DXGI_FORMAT_UNKNOWN,
0, elements);

try {
buffer->CreateSRV(srvDesc);
} catch (const DX::com_exception& e) {
logger::error("Failed to create {} SRV: {}", name, e.what());
buffer.reset();
return false;
}
if (!buffer->srv) {
logger::error("Failed to create {} SRV", name);
buffer.reset();
return false;
}

D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc{};
uavDesc.Format = DXGI_FORMAT_UNKNOWN;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.NumElements = elements;
uavDesc.Buffer.Flags = counter ? D3D11_BUFFER_UAV_FLAG_COUNTER : 0;
try {
buffer->CreateUAV(uavDesc);
} catch (const DX::com_exception& e) {
logger::error("Failed to create {} UAV: {}", name, e.what());
buffer.reset();
return false;
}
if (!buffer->uav)
{
logger::error("Failed to create {} UAV", name);
buffer.reset();
return false;
}
return true;
}

bool OrderIndependentTransparency::SetupPixelBuffers(uint numElem)
{
logger::info("[OIT] Requested Setup Pixel Buffers {}", numElem);
if (settings.Method == Method::OIT_RVO)
{
uint NodeCount = GetNodeCount();
uint colorBufferStride = sizeof(uint32_t) * 2 * NodeCount;
uint depthBufferStride = sizeof(float) * 4 * NodeCount;
uint colorBufferBytes = colorBufferStride * numElem;
if (!colorBuffer.has_value() || colorBuffer->desc.ByteWidth != colorBufferBytes || colorBuffer->desc.StructureByteStride != colorBufferStride)
{
logger::info("[OIT] Creating AOIT Buffers {} * {}", numElem, NodeCount);
if (!CreateStructBuffer(colorBuffer, "OIT Color", numElem, colorBufferStride) ||
!CreateStructBuffer(depthBuffer, "OIT Depth", numElem, depthBufferStride)) {
DisableForResourceFailure();
return false;
}
}
}
else if (settings.Method == Method::OIT_AT || settings.Method == Method::OIT_VISUALIZE)
{
uint BufferSize = settings.BufferSize * numElem;
if (!nodesBuffer.has_value() || nodesBuffer->desc.ByteWidth != BufferSize * sizeof(FragmentListNode))
{
logger::info("[OIT] Creating Fragment List Buffers {} * {}", numElem, settings.BufferSize);
featureCB.MaxListNodes = BufferSize;
if (!CreateStructBuffer(nodesBuffer, "OIT Nodes", BufferSize, sizeof(FragmentListNode), true)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Use checked arithmetic for GPU buffer dimensions.

elements * size, layer strides, and fragment-list counts are calculated in 32-bit uint. For example, a 4096×2160 depth buffer with 32 layers exceeds UINT_MAX, wraps ByteWidth, and can create an undersized resource or trigger device failure. Calculate in uint64_t, reject unsupported sizes, then cast to UINT.

🤖 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 `@src/Features/OrderIndependentTransparency.cpp` around lines 755 - 838, Update
CreateStructBuffer and SetupPixelBuffers to perform all GPU buffer size, stride,
and element-count multiplications in uint64_t, checking each result against the
supported UINT/D3D11 limits before converting to UINT. Reject overflow or
unsupported dimensions before constructing buffers, including color/depth
strides, byte widths, and fragment-list BufferSize/count calculations, and
preserve the existing resource-failure handling through
DisableForResourceFailure().

Comment thread src/Features/OrderIndependentTransparency.cpp
Comment thread src/Globals.h
Comment thread src/State.h Outdated
@github-actions

Copy link
Copy Markdown

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@src/Features/OrderIndependentTransparency.cpp`:
- Around line 1105-1108: Guard the OIT resolve draw near GetUpscaleVS() and
upscaleRasterizerState against uninitialized or disabled upscaling. Before
issuing the draw, validate that the required upscaling resources are ready;
otherwise skip the resolve or use the established non-upscaling fallback,
ensuring no null rasterizer state is bound.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 29b72a9d-45e1-4eda-92b3-e6eb441c94d8

📥 Commits

Reviewing files that changed from the base of the PR and between 7eb1b22 and 98b40cd.

📒 Files selected for processing (11)
  • package/SKSE/Plugins/CommunityShaders/Translations/de.json
  • package/SKSE/Plugins/CommunityShaders/Translations/en.json
  • package/SKSE/Plugins/CommunityShaders/Translations/es.json
  • package/SKSE/Plugins/CommunityShaders/Translations/fr.json
  • package/SKSE/Plugins/CommunityShaders/Translations/ja.json
  • package/SKSE/Plugins/CommunityShaders/Translations/nl.json
  • package/SKSE/Plugins/CommunityShaders/Translations/pl.json
  • package/SKSE/Plugins/CommunityShaders/Translations/ru.json
  • package/SKSE/Plugins/CommunityShaders/Translations/zh_CN.json
  • src/Features/OrderIndependentTransparency.cpp
  • src/Features/OrderIndependentTransparency.h
💤 Files with no reviewable changes (10)
  • package/SKSE/Plugins/CommunityShaders/Translations/ru.json
  • package/SKSE/Plugins/CommunityShaders/Translations/en.json
  • package/SKSE/Plugins/CommunityShaders/Translations/ja.json
  • package/SKSE/Plugins/CommunityShaders/Translations/nl.json
  • package/SKSE/Plugins/CommunityShaders/Translations/fr.json
  • package/SKSE/Plugins/CommunityShaders/Translations/pl.json
  • package/SKSE/Plugins/CommunityShaders/Translations/zh_CN.json
  • package/SKSE/Plugins/CommunityShaders/Translations/es.json
  • src/Features/OrderIndependentTransparency.h
  • package/SKSE/Plugins/CommunityShaders/Translations/de.json

Comment on lines +1105 to +1108
context->VSSetShader(globals::features::upscaling.GetUpscaleVS(), nullptr, 0);

// Set up rasterizer and blend states
context->RSSetState(globals::features::upscaling.upscaleRasterizerState.get());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect upscaling VS/rasterizer lifecycle and any load-order guarantees vs OIT.
fd -t f -e cpp -e h -i upscal | sort
echo "---- GetUpscaleVS / upscaleRasterizerState definitions ----"
rg -nP -C3 '\b(GetUpscaleVS|upscaleRasterizerState)\b' --type=cpp --type=cpp
echo "---- upscaling feature loaded/guard usage ----"
rg -nP -C3 'features::upscaling' --type=cpp

Repository: community-shaders/skyrim-community-shaders

Length of output: 292


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file sizes =="
wc -l src/Features/Upscaling.h src/Features/Upscaling.cpp src/Features/OrderIndependentTransparency.cpp

echo "== outlines =="
ast-grep outline src/Features/Upscaling.h --view expanded || true
echo "----"
ast-grep outline src/Features/Upscaling.cpp --view expanded || true
echo "----"
ast-grep outline src/Features/OrderIndependentTransparency.cpp --view expanded || true

echo "== targeted reads =="
sed -n '1,260p' src/Features/Upscaling.h
echo "---- CPP 1 ----"
sed -n '1,340p' src/Features/Upscaling.cpp
echo "---- OIT slice ----"
sed -n '1060,1135p' src/Features/OrderIndependentTransparency.cpp

Repository: community-shaders/skyrim-community-shaders

Length of output: 31837


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== GetUpscaleVS implementation and resource setup =="
rg -n -C4 'GetUpscaleVS\(|upscaleVS|upscaleRasterizerState|upscaleBlendState|upscaleDepthStencilState' src/Features/Upscaling.cpp src/Features/Upscaling.h

echo "== OIT setup/guards around resolve pass =="
rg -n -C4 'OrderIndependentTransparency::SetupResources|DisableForResourceFailure|SetupGeometry|RestoreGeometry|BeginAlphaGroup|EndAlphaGroup|Resolve|GetUpscaleVS|upscaleRasterizerState' src/Features/OrderIndependentTransparency.cpp

echo "== feature enable/load order references =="
rg -n -C3 'globals::features::upscaling|upscaling\.loaded|upscaling\.SetupResources|OrderIndependentTransparency' src/Features/*.cpp src/Features/*.h

Repository: community-shaders/skyrim-community-shaders

Length of output: 46989


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Feature base load semantics =="
rg -n -C4 'bool loaded|loaded =|void Load\(|PostPostLoad\(|SetupResources\(' src/Features/Feature.h src/Features/*.cpp

echo "== upscaling load/init paths =="
rg -n -C4 'Upscaling::Load\(|Upscaling::PostPostLoad\(|Upscaling::SetupResources\(|CheckResources\(' src/Features/Upscaling.cpp

echo "== OIT activation and load dependencies =="
rg -n -C4 'orderIndependentTransparency\.loaded|OrderIndependentTransparency::Load\(|OrderIndependentTransparency::PostPostLoad\(|OrderIndependentTransparency::SetupResources\(' src/Features/OrderIndependentTransparency.cpp src/Features/OrderIndependentTransparency.h

echo "== feature manager/registry ordering =="
rg -n -C4 'features::upscaling|features::orderIndependentTransparency|LoadFeatures|SetupResources' src

Repository: community-shaders/skyrim-community-shaders

Length of output: 25994


Guard the OIT resolve draw against missing upscaling state. GetUpscaleVS() compiles on demand, but upscaleRasterizerState is only created in Upscaling::SetupResources(). If OIT can run before that feature initializes or when upscaling is disabled, this pass will bind a null rasterizer state and misrender. Add a fallback or skip the draw when the dependency isn’t ready.

🤖 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 `@src/Features/OrderIndependentTransparency.cpp` around lines 1105 - 1108,
Guard the OIT resolve draw near GetUpscaleVS() and upscaleRasterizerState
against uninitialized or disabled upscaling. Before issuing the draw, validate
that the required upscaling resources are ready; otherwise skip the resolve or
use the established non-upscaling fallback, ensuring no null rasterizer state is
bound.

ArcEarth and others added 4 commits July 19, 2026 21:37
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
static void WINAPI thunk(ID3D11DeviceContext* This, ID3D11BlendState* pBlendState, const FLOAT BlendFactor[4], UINT SampleMask)
{
if (pBlendState) {
if (pBlendState && !globals::features::orderIndependentTransparency.inAlphaPass) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

does this need to be specific to OIT?

Comment thread src/ShaderCache.h
int blockedKeyIndex = -1; // index in shaderMap; negative value indicates disabled
enum class ParticleShaderFlags : uint32_t
{
OIT = 1UL << 15 // TODO: Find a proper bit for OIT flag, current set by trail & error

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is this fine?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looks fine so far, I haven't notice any mis rendered particles. The concern is I haven't RE for particle shader flags.

float4 color;
float4 wcolor;

//uint firstNodeOffset = FL_GetFirstNodeOffset(screenAddress);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

commented out code?


std::span<const D3D_SHADER_MACRO> OrderIndependentTransparency::GetShaderDefines() const
{
// OIT = OIT_METHOD_DEFINES[settings.Method]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

commented out code?


logger::info("[OIT] Hooking Main_RenderWorld_RenderTransparency");

// std::uintptr_t address = REL::RelocationID(100424, 107142).address() + REL::Relocate(0x3E4, 0x3FE);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

commented out code? needed for dev work?

auto& depthStencilDepthMode = shadowState->GetRuntimeData().depthStencilDepthMode;

// Setup depth write descriptor, depth write will be skipped in capture pass
//using enum RE::BSGraphics::DepthStencilDepthMode;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

commented out code?


if (pass->shaderProperty && pass->shaderProperty->flags.any(RE::BSShaderProperty::EShaderPropertyFlag::kZBufferWrite))
{
// TODO:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

does this need to be done?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, I found the 'segmented' draw calls are not directly related to alpha pass, but coming from skin clusters of SMP bones and outfit studio >_< A separate problem

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No, I found the 'segmented' draw calls are not directly related to alpha pass, but coming from skin clusters of SMP bones and outfit studio >_< A separate problem

auto* renderer = globals::game::renderer;
ID3D11DeviceContext* context = globals::d3d::context;
ID3D11UnorderedAccessView* headerUAV = headerBuffer->uav.get();
// context->OMGetRenderTargets(0, NULL, sceneDSV.put());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

?

auto& alpha = renderer->GetRuntimeData().renderTargets[RE::RENDER_TARGETS::kMAIN_ONLY_ALPHA];
ID3D11ShaderResourceView* srv[] = { alpha.SRV };
context->PSSetShaderResources(66, ARRAYSIZE(srv), srv);
// context->PSSetSamplers(66, 1, &globals::deferred->linearSampler);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

commented out code?

@doodlum

doodlum commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

This looks extremely impressive, just needs minor cleanup and performance/bug testing.

@ArcEarth

Copy link
Copy Markdown
Contributor Author

Thanks for the review 😀 Will do the cleanup and push a new test build around the weekend

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