<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>AK Plugins Blog</title>
        <link>https://unreal-engine-ace7bf.gitlab.io/blog</link>
        <description>AK Plugins Blog</description>
        <lastBuildDate>Fri, 27 Mar 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[The State of Desktop Forward Rendering in Unreal Engine 5.7]]></title>
            <link>https://unreal-engine-ace7bf.gitlab.io/blog/hello-world</link>
            <guid>https://unreal-engine-ace7bf.gitlab.io/blog/hello-world</guid>
            <pubDate>Fri, 27 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[There's a growing discontent with temporal anti-aliasing solutions in game development circles. Communities like r/FuckTAA have emerged as vocal critics of the ghosting and smearing artifacts that plague TAA and other temporal solutions.]]></description>
            <content:encoded><![CDATA[<p>There's a growing discontent with temporal anti-aliasing solutions in game development circles. Communities like <a href="https://www.reddit.com/r/FuckTAA" target="_blank" rel="noopener noreferrer">r/FuckTAA</a> have emerged as vocal critics of the ghosting and smearing artifacts that plague TAA and other temporal solutions.</p>
<p>The issue runs deeper than preference: UE's entire rendering pipeline now <strong>assumes temporal accumulation</strong>. SSGI has grown noisier since UE4, expecting TAA to clean up the result. Lumen's software ray tracing leans on temporal filtering to resolve its noisy probes. Even Nanite's virtualized geometry produces sub-pixel triangles that only resolve cleanly under temporal upscaling. Opting out of TAA means fighting the engine's core assumptions.</p>
<p>For certain scenarios, forward rendering with MSAA remains a compelling option. Dense foliage with a single dominant light source — the sun — is exactly where forward rendering can shine. One directional light and extensive vegetation where geometric edge quality matters more than complex lighting setups.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Personal Motivation</div><div class="admonitionContent_BuS1"><p>My interest is personal: I've always wanted to create a game set in a tropical forest environment. Perhaps this documentation will prove useful to graphics programmers exploring hybrid renderer implementations, or those seeking to understand how forward rendering can coexist with modern engine features.</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="aa-approach-comparisons">AA Approach Comparisons<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#aa-approach-comparisons" class="hash-link" aria-label="Direct link to AA Approach Comparisons" title="Direct link to AA Approach Comparisons">​</a></h2>
<table><thead><tr><th>Configuration</th><th>Notes</th></tr></thead><tbody><tr><td>No AA (Deferred)</td><td>Baseline</td></tr><tr><td>SMAA 1x (Deferred)</td><td>Basic morphological AA</td></tr><tr><td>SMAA 1x + Filmic Filter (Deferred)</td><td>Good result for deferred</td></tr><tr><td><strong>MSAA 2x + SMAA S2x (Forward)</strong></td><td>Preserved edges better than Filmic + SMAA</td></tr></tbody></table>
<p>I recently implemented SMAA S2x mode to work alongside MSAA 2x for my plugin, and the results demonstrate why this combination deserves attention.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="a-note-on-the-filmic-filter">A Note on the Filmic Filter<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#a-note-on-the-filmic-filter" class="hash-link" aria-label="Direct link to A Note on the Filmic Filter" title="Direct link to A Note on the Filmic Filter">​</a></h3>
<p>The SMAA 1x + Filmic Filter combination addresses a core limitation of pure morphological AA: <strong>lack of temporal stability</strong>. Based on Activision's Filmic SMAA research, this filter operates in two distinct modes:</p>
<p><strong>Stationary pixels</strong> accumulate history aggressively (85% history weight by default), using Catmull-Rom bicubic sampling for sharp history reconstruction. When SMAA edge data is available and no significant motion is detected, the filter applies a convergence term <code>m03</code> derived from subpixel positioning — this reconstructs detail between the current frame's left/right neighbors and blends it with history, effectively enhancing perceived resolution on static geometry.</p>
<p><strong>Moving pixels</strong> (velocity &gt; threshold or detected disocclusion) bypass the convergence sharpening entirely and blend toward the current frame, preventing the ghosting artifacts typical of aggressive temporal filters. Fast motion (&gt;3.5 pixels) forces immediate fallback to the raw current frame.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>The Result</div><div class="admonitionContent_BuS1"><p>Temporal smoothing and detail enhancement when the camera is still; instant reversion to sharp single-frame output on motion. This trades the persistent smear of traditional TAA for a "best of both worlds" approach that respects SMAA's geometric edge quality.</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="why-msaa-and-deferred-rendering-dont-mix">Why MSAA and Deferred Rendering Don't Mix<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#why-msaa-and-deferred-rendering-dont-mix" class="hash-link" aria-label="Direct link to Why MSAA and Deferred Rendering Don't Mix" title="Direct link to Why MSAA and Deferred Rendering Don't Mix">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-gbuffer-problem">The GBuffer Problem<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#the-gbuffer-problem" class="hash-link" aria-label="Direct link to The GBuffer Problem" title="Direct link to The GBuffer Problem">​</a></h3>
<p>Deferred rendering stores material properties in multiple render targets called GBuffers. Looking at UE5's <code>SceneTextures.cpp</code>, we can see exactly what gets allocated:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">SceneTextures.cpp — GBuffer allocation</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Bindings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">GBufferA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Index </span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> FRDGTextureDesc Desc </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">FRDGTextureDesc</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token function" style="color:rgb(130, 170, 255)">CreateRenderTargetTextureDesc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Extent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Bindings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">GBufferA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Format</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> FClearValueBinding</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token plain">Transparent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Bindings</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">GBufferA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Flags </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> FlagsToAdd </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> GFastVRamConfig</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">GBufferA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">bRequireMultiView</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">MobileMultiViewRenderTargetNumLayers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">GBufferA </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">CreateTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"GBufferA"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// ... GBufferB, C, D, E, F follow the same pattern</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>UE5's deferred renderer uses up to <strong>six GBuffer textures</strong> (A through F), plus depth. With 4x MSAA, you'd need to store 4 samples per pixel for each of these textures. The memory and bandwidth explosion is already substantial, and the lighting pass would need to read all MSAA samples, perform shading calculations per-sample, and resolve. Modern engines have dozens of passes that would each need MSAA-aware variants.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="deferred-msaa-is-possible--crysis-3s-example">Deferred MSAA Is Possible — Crysis 3's Example<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#deferred-msaa-is-possible--crysis-3s-example" class="hash-link" aria-label="Direct link to Deferred MSAA Is Possible — Crysis 3's Example" title="Direct link to Deferred MSAA Is Possible — Crysis 3's Example">​</a></h3>
<p>Before dismissing MSAA with deferred rendering entirely, it's worth examining how Crytek made it work in Crysis 3. Tiago Sousa's GDC 2013 and SIGGRAPH 2013 presentations document their implementation in detail.</p>
<p><strong>The Core Technique: Stencil-Based Edge Detection</strong></p>
<p>Crytek's approach splits rendering into pixel-frequency and sample-frequency passes:</p>
<ol>
<li>During G-Buffer fill, reserve 1 bit from the stencil buffer for a sub-sample mask.</li>
<li>A resolve pass extracts sample 0 from the G-Buffer and builds a mask indicating whether all samples in a pixel match sample 0.</li>
<li>Pixel-frequency passes read from pre-resolved (non-multisampled) textures, using stencil to process only uniform pixels.</li>
<li>Sample-frequency passes read from multisampled textures, indexing via <code>SV_SAMPLEINDEX</code>, processing only edge pixels.</li>
</ol>
<p>This builds on Intel's Andrew Lauritzen's SIGGRAPH 2010 research on tile-based deferred shading with MSAA. The key insight: store G-Buffer at sample frequency, but <strong>only apply per-sample shading where discontinuities exist</strong>.</p>
<p><strong>The Performance Reality</strong></p>
<p>The technique worked, but the performance cost was substantial. Forum discussions from 2013 show 30–50% frame rate drops when enabling MSAA in Crysis 3. Whether MSAA itself was the bottleneck remains debated — <a href="https://youtu.be/ElBUUMi_L5c" target="_blank" rel="noopener noreferrer">Threat Interactive's analysis of the Crysis 3 pipeline</a> argues otherwise, though their methodology has drawn criticism in technical circles.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="why-ue5-doesnt-do-this">Why UE5 Doesn't Do This<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#why-ue5-doesnt-do-this" class="hash-link" aria-label="Direct link to Why UE5 Doesn't Do This" title="Direct link to Why UE5 Doesn't Do This">​</a></h3>
<p>Epic could theoretically implement stencil-based deferred MSAA. They haven't, likely because:</p>
<ul>
<li>The engineering complexity is significant.</li>
<li>TSR/TAA solve aliasing well enough for most use cases.</li>
<li>Virtual Shadow Maps, Lumen, and Nanite all assume temporal accumulation anyway.</li>
<li>Modern hardware ray tracing changes the cost/benefit calculus.</li>
</ul>
<p>For developers who need MSAA without temporal artifacts, UE5's forward rendering path remains the practical choice.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-industry-shift-toward-visibility-buffers">The Industry Shift Toward Visibility Buffers<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#the-industry-shift-toward-visibility-buffers" class="hash-link" aria-label="Direct link to The Industry Shift Toward Visibility Buffers" title="Direct link to The Industry Shift Toward Visibility Buffers">​</a></h2>
<p>id Software's GPC 2025 presentation on <em>DOOM: The Dark Ages</em> reveals they abandoned their Forward+ pipeline (used in <em>DOOM Eternal</em>) in favor of a <strong>visibility buffer / deferred hybrid</strong>. The core problem? Quad utilization efficiency.</p>
<p>When triangle density increases, forward rendering suffers disproportionately. id Software's profiling showed scenes where helper threads vastly outnumbered active threads — pixels being shaded that would never contribute to the final image. Their visibility buffer approach saved up to <strong>25% GPU time</strong> on target hardware, with performance now scaling almost linearly with resolution.</p>
<p>Epic's trajectory tells a similar story. UE 5.7 deprecated Clustered Deferred Rendering, citing maintenance burden and low adoption — another reason may be the introduction of Megalights. Nanite already uses a visibility buffer internally. Lumen assumes temporal accumulation. The engine architecture increasingly optimizes for deferred-style pipelines with compute-based material evaluation.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-hybrid-approach-remains-viable">The Hybrid Approach Remains Viable<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#the-hybrid-approach-remains-viable" class="hash-link" aria-label="Direct link to The Hybrid Approach Remains Viable" title="Direct link to The Hybrid Approach Remains Viable">​</a></h3>
<p>Despite these trends, hybrid rendering — forward for select object types, deferred for the rest — remains a production-proven approach in 2025. <em>DOOM: The Dark Ages</em> itself ships as a hybrid: Forward+ is still used for transparents and remains available as a fallback path.</p>
<p>Many AAA studios continue to leverage hybrid pipelines precisely because different content types have different optimal rendering strategies. Foliage, hair, and particles often benefit from forward rendering's MSAA integration and simpler transparency handling, while static opaque geometry fits naturally into deferred or visibility buffer workflows.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>Opinion</div><div class="admonitionContent_BuS1"><p>UE5 should preserve this flexibility. The current forward rendering path works. It integrates with MSAA. It handles masked materials without the complexity of compute-based dispatch systems. Rather than treating forward rendering as a checkbox, Epic should integrate it properly for developers who don't want to use "Unreal's Pipeline".</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ue5s-forward-rendering-pipeline">UE5's Forward Rendering Pipeline<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#ue5s-forward-rendering-pipeline" class="hash-link" aria-label="Direct link to UE5's Forward Rendering Pipeline" title="Direct link to UE5's Forward Rendering Pipeline">​</a></h2>
<p>Despite being named <code>FDeferredShadingSceneRenderer</code>, UE5's main renderer handles both deferred and forward paths. The branch happens based on project settings:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">DeferredShadingRenderer.cpp</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">IsForwardShadingEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ShaderPlatform</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Forward-specific path</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">ensureMsgf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">VirtualShadowMapArray</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">IsEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Virtual shadow maps are not supported in the forward shading path"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">RenderShadowDepthMaps</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> InitViewTaskDatas</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">DynamicShadows</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        InstanceCullingManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ExternalAccessQueue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    bShadowMapsRenderedEarly </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">true</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Hair strands rendering</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">bHairStrandsEnable</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">RenderHairPrePass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Scene</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Views</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            InstanceCullingManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> HairStrandsBookmarkParameters</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">CullingResults</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">RenderHairBasePass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Scene</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Views</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            InstanceCullingManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Forward shadow projection</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">RenderForwardShadowProjections</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        ForwardScreenSpaceShadowMaskTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ForwardScreenSpaceShadowMaskHairTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Volumetric fog BEFORE base pass (critical ordering difference)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">ComputeVolumetricFog</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Critical Ordering Constraint</div><div class="admonitionContent_BuS1"><p>Forward rendering requires shadow maps to be rendered <strong>before</strong> the base pass. In deferred, shadows can be calculated later using GBuffer data. This ordering constraint is fundamental to understanding the pipeline.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="forward-rendering-execution-order">Forward Rendering Execution Order<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#forward-rendering-execution-order" class="hash-link" aria-label="Direct link to Forward Rendering Execution Order" title="Direct link to Forward Rendering Execution Order">​</a></h3>
<ol>
<li>Pre-pass / Early Z <em>(required for forward; optional optimization for deferred)</em></li>
<li>Shadow Depth Maps <em>(rendered early in forward)</em></li>
<li>Hair Strands <em>(if enabled)</em></li>
<li>Forward Shadow Projection → <code>ForwardScreenSpaceShadowMaskTexture</code></li>
<li>Volumetric Fog <em>(before base pass in forward)</em></li>
<li>Base Pass <em>(lighting calculated inline)</em></li>
</ol>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="the-base-pass-where-lighting-happens">The Base Pass: Where Lighting Happens<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#the-base-pass-where-lighting-happens" class="hash-link" aria-label="Direct link to The Base Pass: Where Lighting Happens" title="Direct link to The Base Pass: Where Lighting Happens">​</a></h2>
<p>In forward rendering, the base pass does everything. From <code>RenderBasePass</code>:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">DeferredShadingRenderer.h</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">void</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">RenderBasePass</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FDeferredShadingSceneRenderer</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> Renderer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FRDGBuilder</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    TArrayView</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">FViewInfo</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> InViews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FSceneTextures</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> FDBufferTextures</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> DBufferTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FExclusiveDepthStencil</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token plain">Type BasePassDepthStencilAccess</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FRDGTextureRef ForwardShadowMaskTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FInstanceCullingManager</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> InstanceCullingManager</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">bool</span><span class="token plain"> bNaniteEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">struct</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">FNaniteShadingCommands</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> NaniteBasePassShadingCommands</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> TArrayView</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">Nanite</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token plain">FRasterResults</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;</span><span class="token plain"> NaniteRasterResults</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>info</div><div class="admonitionContent_BuS1"><p>Notice <code>ForwardShadowMaskTexture</code> being passed directly to the base pass. Forward materials sample this during shading.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="forward-lighting-the-shader-side">Forward Lighting: The Shader Side<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#forward-lighting-the-shader-side" class="hash-link" aria-label="Direct link to Forward Lighting: The Shader Side" title="Direct link to Forward Lighting: The Shader Side">​</a></h3>
<p>The actual lighting calculations happen in <code>ForwardLightingCommon.ush</code>. The core function is <code>GetForwardDirectLightingSplit</code>:</p>
<div class="language-hlsl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">ForwardLightingCommon.ush</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-hlsl codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">FDeferredLightingSplit GetForwardDirectLightingSplit(</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    uint2 PixelPos,</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    uint GridIndex, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    float3 TranslatedWorldPosition, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    float3 CameraVector, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FGBufferData GBufferData,  // Note: "GBufferData" is an inaccurate term in forward</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    float2 ScreenUV, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    uint PrimitiveId, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    uint EyeIndex, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    float Dither, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    float InDirectionalLightCloudShadow, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    float3 InDirectionalLightAtmosphereTransmittance, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    inout float OutDirectionalLightShadow,</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    bool bSeparateMainDirLightLuminance, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    inout float3 SeparatedMainDirLightLuminance, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    bool bSkipDirLightVirtualShadowMapEvaluation)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="directional-light-handling">Directional Light Handling<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#directional-light-handling" class="hash-link" aria-label="Direct link to Directional Light Handling" title="Direct link to Directional Light Handling">​</a></h3>
<div class="language-hlsl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">ForwardLightingCommon.ush — Directional light path</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-hlsl codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">BRANCH</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">if (DirectionalLightData.HasDirectionalLight</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">#if MATERIALBLENDING_ANY_TRANSLUCENT</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; DirectionalLightData.bAffectsTranslucentLighting &gt; 0</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">#endif</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    )</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    half4 PreviewShadowMapChannelMask = 1;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    uint  DirLightingChannelMask = LIGHTING_CHANNEL_MASK;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FDeferredLightData LightData = ConvertToDeferredLight(DirectionalLightData, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        SpecularScale, PreviewShadowMapChannelMask, DirLightingChannelMask);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    // Shadow factor calculation</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    #if DISABLE_FORWARD_DIRECTIONAL_LIGHT_SHADOW</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        float4 LightAttenuation = float4(1, 1, 1, 1);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    #elif ((MATERIALBLENDING_SOLID || MATERIALBLENDING_MASKED) &amp;&amp; !MATERIAL_SHADINGMODEL_SINGLELAYERWATER)</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        float DynamicShadowing = dot(PreviewShadowMapChannelMask, DynamicShadowFactors);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        float PerObjectShadowing = LightData.DistanceFadeMAD.y &lt; 0.0f ? 1.0f : DynamicShadowing;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        float WholeSceneShadowing = LightData.DistanceFadeMAD.y &lt; 0.0f ? DynamicShadowing : 1.0f;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        float4 LightAttenuation = float4(WholeSceneShadowing.xx, PerObjectShadowing.xx);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    #else</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        // Translucent path - calculates shadows inline</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        float DynamicShadowFactor = ComputeDirectionalLightDynamicShadowing(</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            TranslatedWorldPosition, GBufferData.Depth, bUnused);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    #endif</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="local-lights-clustered-forward">Local Lights: Clustered Forward<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#local-lights-clustered-forward" class="hash-link" aria-label="Direct link to Local Lights: Clustered Forward" title="Direct link to Local Lights: Clustered Forward">​</a></h3>
<p>Forward rendering doesn't mean no local lights. UE5 uses <strong>clustered forward lighting</strong>:</p>
<div class="language-hlsl codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">ForwardLightingCommon.ush — Clustered local lights</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-hlsl codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">#if !DISABLE_FORWARD_LOCAL_LIGHTS</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    const FCulledLightsGridHeader CulledLightsGridHeader = GetCulledLightsGridHeader(GridIndex);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    // Safety clamp to prevent GPU hangs</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    const uint NumLightsInGridCell = min(CulledLightsGridHeader.NumLights, GetMaxLightsPerCell());</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    LOOP</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    for (uint GridLightListIndex = 0; GridLightListIndex &lt; NumLightsInGridCell; GridLightListIndex++)</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        half4 PreviewShadowMapChannelMask = 1;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        uint  LocalLightingChannelMask = LIGHTING_CHANNEL_MASK;</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        const FLocalLightData LocalLight = GetLocalLightDataFromGrid(</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            CulledLightsGridHeader.DataStartIndex + GridLightListIndex, EyeIndex);</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        #if MATERIALBLENDING_ANY_TRANSLUCENT</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        if(UnpackAffectsTranslucentLighting(LocalLight) == 0)</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            continue;  // Skip lights that don't affect translucency</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        #endif</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        FDeferredLightData LightData = ConvertToDeferredLight(LocalLight, SpecularScale, </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            PreviewShadowMapChannelMask, LocalLightingChannelMask);</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The per-cell light limit is controlled by this CVar:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">int32 GMaxCulledLightsPerCell </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">32</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">FAutoConsoleVariableRef </span><span class="token function" style="color:rgb(130, 170, 255)">CVarMaxCulledLightsPerCell</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"r.Forward.MaxCulledLightsPerCell"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    GMaxCulledLightsPerCell</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Controls how much memory is allocated for each cell for light culling. "</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         </span><span class="token string" style="color:rgb(195, 232, 141)">"When r.Forward.LightLinkedListCulling is enabled, this is used to compute "</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         </span><span class="token string" style="color:rgb(195, 232, 141)">"a global max instead of a per-cell limit on culled lights."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    ECVF_Scalability </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> ECVF_RenderThreadSafe</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="msaa-implementation-in-ue5">MSAA Implementation in UE5<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#msaa-implementation-in-ue5" class="hash-link" aria-label="Direct link to MSAA Implementation in UE5" title="Direct link to MSAA Implementation in UE5">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scene-texture-allocation">Scene Texture Allocation<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#scene-texture-allocation" class="hash-link" aria-label="Direct link to Scene Texture Allocation" title="Direct link to Scene Texture Allocation">​</a></h3>
<p>From <code>SceneTextures.cpp</code>, MSAA is configured at texture creation time:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">SceneTextures.cpp — MSAA CVar</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">static</span><span class="token plain"> TAutoConsoleVariable</span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain">int32</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CVarMSAACount</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"r.MSAACount"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token number" style="color:rgb(247, 140, 108)">4</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Number of MSAA samples to use with the forward renderer. "</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         </span><span class="token string" style="color:rgb(195, 232, 141)">"Only used when MSAA is enabled in the rendering project settings.\n"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"0: MSAA disabled (Temporal AA enabled)\n"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"1: MSAA disabled\n"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"2: Use 2x MSAA\n"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"4: Use 4x MSAA"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"8: Use 8x MSAA"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    ECVF_RenderThreadSafe </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> ECVF_Scalability</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="depth-buffer-with-msaa">Depth Buffer with MSAA<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#depth-buffer-with-msaa" class="hash-link" aria-label="Direct link to Depth Buffer with MSAA" title="Direct link to Depth Buffer with MSAA">​</a></h3>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">FMinimalSceneTextures::InitializeViewFamily</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">FRDGTextureDesc Desc </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">FRDGTextureDesc</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token function" style="color:rgb(130, 170, 255)">CreateRenderTargetTextureDesc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Extent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    PF_DepthStencil</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">DepthClearValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">DepthCreateFlags</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">bRequireMultiView</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">MobileMultiViewRenderTargetNumLayers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain">  </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// MSAA sample count</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Depth </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">CreateTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"SceneDepthZ"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// MSAA requires resolve target</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples </span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">StereoDepthRHI </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">FindStereoDepthTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">bSupportsXRTargetManagerDepthAlloc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Extent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ETextureCreateFlags</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token plain">DepthStencilResolveTarget</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">!=</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">nullptr</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Use XR-provided resolve target</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Depth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Resolve </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">RegisterExternalTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> StereoDepthRHI</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"SceneDepthZ"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">bKeepDepthContent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// Create our own resolve target</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Depth</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Resolve </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">CreateTexture</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"SceneDepthZ"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="scene-color-with-msaa">Scene Color with MSAA<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#scene-color-with-msaa" class="hash-link" aria-label="Direct link to Scene Color with MSAA" title="Direct link to Scene Color with MSAA">​</a></h3>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">SceneTextures.cpp — Scene Color creation</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">bool</span><span class="token plain"> bIsMobilePlatform </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ShadingPath </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> EShadingPath</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token plain">Mobile</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">const</span><span class="token plain"> ETextureCreateFlags sRGBFlag </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">bIsMobilePlatform </span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;&amp;</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">IsMobileColorsRGB</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token operator" style="color:rgb(137, 221, 255)">?</span><span class="token plain"> TexCreate_SRGB </span><span class="token operator" style="color:rgb(137, 221, 255)">:</span><span class="token plain"> TexCreate_None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    FRDGTextureDesc Desc </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">FRDGTextureDesc</span><span class="token double-colon punctuation" style="color:rgb(199, 146, 234)">::</span><span class="token function" style="color:rgb(130, 170, 255)">CreateRenderTargetTextureDesc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Extent</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ColorFormat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ColorClearValue</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ColorCreateFlags</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">bRequireMultiView</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">MobileMultiViewRenderTargetNumLayers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> Config</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">NumSamples</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic">// CreateTextureMSAA handles creating both MSAA target and resolve target</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    SceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">Color </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">CreateTextureMSAA</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Desc</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"SceneColorMS"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"SceneColor"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        GFastVRamConfig</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">SceneColor </span><span class="token operator" style="color:rgb(137, 221, 255)">|</span><span class="token plain"> sRGBFlag</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>The <code>FRDGTextureMSAA</code> structure (used for both Color and Depth) contains two members: <code>Target</code> (the MSAA render target) and <code>Resolve</code> (the resolved single-sample texture).</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="limitations-of-forward-rendering-in-ue5">Limitations of Forward Rendering in UE5<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#limitations-of-forward-rendering-in-ue5" class="hash-link" aria-label="Direct link to Limitations of Forward Rendering in UE5" title="Direct link to Limitations of Forward Rendering in UE5">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="virtual-shadow-maps-not-supported">Virtual Shadow Maps: Not Supported<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#virtual-shadow-maps-not-supported" class="hash-link" aria-label="Direct link to Virtual Shadow Maps: Not Supported" title="Direct link to Virtual Shadow Maps: Not Supported">​</a></h3>
<p>This is explicitly enforced in the code:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token function" style="color:rgb(130, 170, 255)">IsForwardShadingEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ShaderPlatform</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">ensureMsgf</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token operator" style="color:rgb(137, 221, 255)">!</span><span class="token plain">VirtualShadowMapArray</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">IsEnabled</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token function" style="color:rgb(130, 170, 255)">TEXT</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"Virtual shadow maps are not supported in the forward shading path"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="post-process-effects-require-resolved-data">Post-Process Effects Require Resolved Data<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#post-process-effects-require-resolved-data" class="hash-link" aria-label="Direct link to Post-Process Effects Require Resolved Data" title="Direct link to Post-Process Effects Require Resolved Data">​</a></h3>
<p>Many post-process effects operate on resolved (single-sample) data, meaning MSAA doesn't help with aliasing they introduce:</p>
<ul>
<li>Screen-Space Reflections (SSR)</li>
<li>Screen-Space Ambient Occlusion (SSAO)</li>
<li>Depth of Field</li>
<li>Motion Blur</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="nanite-works-but-independently">Nanite: Works, But Independently<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#nanite-works-but-independently" class="hash-link" aria-label="Direct link to Nanite: Works, But Independently" title="Direct link to Nanite: Works, But Independently">​</a></h3>
<p>Nanite does work with forward rendering, but operates somewhat independently:</p>
<div class="language-cpp codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-cpp codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">bNaniteEnabled </span><span class="token operator" style="color:rgb(137, 221, 255)">&amp;&amp;</span><span class="token plain"> InViews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token function" style="color:rgb(130, 170, 255)">Num</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token function" style="color:rgb(130, 170, 255)">RenderNanite</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">GraphBuilder</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> InViews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> LocalSceneTextures</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> bIsEarlyDepthComplete</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        InNaniteBasePassVisibility</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> NaniteRasterResults</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> PrimaryNaniteViews</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        FirstStageDepthBuffer</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Forward rendering in UE5 is a <strong>fully functional path</strong>, not a legacy compatibility mode. It's designed for scenarios with simpler lighting requirements where geometric clarity matters.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-works-well">What Works Well<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#what-works-well" class="hash-link" aria-label="Direct link to What Works Well" title="Direct link to What Works Well">​</a></h3>
<table><thead><tr><th>Feature</th><th>Notes</th></tr></thead><tbody><tr><td>Clustered Forward Lighting</td><td>Supports multiple local lights efficiently</td></tr><tr><td>Full MSAA</td><td>Supported at the renderer level</td></tr><tr><td>Nanite</td><td>Works, albeit somewhat independently</td></tr><tr><td>Hair Strands</td><td>Benefits from MSAA coverage more than TAA temporal resolve — less ghosting on fine strands</td></tr><tr><td>Volumetric Fog</td><td>Fully integrated</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="real-trade-offs">Real Trade-offs<a href="https://unreal-engine-ace7bf.gitlab.io/blog/hello-world#real-trade-offs" class="hash-link" aria-label="Direct link to Real Trade-offs" title="Direct link to Real Trade-offs">​</a></h3>
<div class="theme-admonition theme-admonition-danger admonition_xJq3 alert alert--danger"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"></path></svg></span>What You Lose</div><div class="admonitionContent_BuS1"><ul>
<li><strong>No Virtual Shadow Maps</strong> — the engine explicitly asserts against this.</li>
<li><strong>No Lumen GI or Lumen Reflections</strong> — these rely on deferred-specific screen traces and the surface cache.</li>
<li><strong>Limited screen-space effects</strong> — SSR, SSAO, DoF, and motion blur all operate on resolved data.</li>
</ul></div></div>
<p>For the right content type — dense foliage, fine geometry, single dominant light — forward rendering with MSAA remains a genuinely superior choice to temporal solutions. The key is understanding where each pipeline's assumptions align with your rendering goals.</p>]]></content:encoded>
            <category>rendering</category>
            <category>unreal-engine</category>
            <category>msaa</category>
            <category>forward-rendering</category>
            <category>anti-aliasing</category>
            <category>smaa</category>
        </item>
        <item>
            <title><![CDATA[A Deep Dive into PSO Caching in Unreal Engine]]></title>
            <link>https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching</link>
            <guid>https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching</guid>
            <pubDate>Mon, 19 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[In modern real-time rendering, few things break immersion like a shader compilation hitch. You turn a corner, an explosion goes off, and the game freezes for 200ms. This article explores why this happens, how Bungie and Ubisoft solved it, and how to improve PSO Precaching in Unreal Engine 5.]]></description>
            <content:encoded><![CDATA[<p>In modern real-time rendering, few things break immersion like a shader compilation hitch. You turn a corner, an explosion goes off, and the game freezes for 200ms. This article explores why this happens, how Bungie and Ubisoft solved it, and how to improve PSO Precaching in Unreal Engine 5.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="part-1-the-theory--why-do-we-hitch">Part 1: The Theory – Why Do We Hitch?<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#part-1-the-theory--why-do-we-hitch" class="hash-link" aria-label="Direct link to Part 1: The Theory – Why Do We Hitch?" title="Direct link to Part 1: The Theory – Why Do We Hitch?">​</a></h2>
<p>To understand shader hitching, we must understand the <strong>Pipeline State Object (PSO)</strong>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="what-is-a-pso">What is a PSO?<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#what-is-a-pso" class="hash-link" aria-label="Direct link to What is a PSO?" title="Direct link to What is a PSO?">​</a></h3>
<p>A PSO is a monolithic object that describes the state of the graphics pipeline. It is not just the shader code (Vertex/Pixel shader) — it combines the compiled shader bytecode with specific render states, including:</p>
<ul>
<li><strong>Blend State</strong> (Translucency, Additive, etc.)</li>
<li><strong>Rasterizer State</strong> (Wireframe, Culling)</li>
<li><strong>Depth/Stencil State</strong></li>
<li><strong>Input Layouts</strong></li>
</ul>
<p>In modern APIs like DirectX 12 and Vulkan, the GPU cannot draw a single triangle until the specific PSO for that draw call is fully compiled and ready.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-good-old-days-of-directx-11">The "Good Old Days" of DirectX 11<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#the-good-old-days-of-directx-11" class="hash-link" aria-label="Direct link to The &quot;Good Old Days&quot; of DirectX 11" title="Direct link to The &quot;Good Old Days&quot; of DirectX 11">​</a></h3>
<p>If PSOs are necessary, why didn't games hitch as much in the DX11 era?</p>
<p>According to AMD and Ubisoft's analysis (GDC 2017), D3D11 drivers hid significant complexity. When you called <code>SetVertexShader</code> or <code>SetBlendState</code>, the driver didn't compile immediately. It waited until draw time, checked if it had seen that combination before, and if not, <strong>JIT-compiled</strong> (Just-In-Time) the state. The drivers were incredibly optimized to handle this "lazy" compilation without stalling the game thread, effectively managing permutations automatically.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="the-dx12vulkan-reality">The DX12/Vulkan Reality<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#the-dx12vulkan-reality" class="hash-link" aria-label="Direct link to The DX12/Vulkan Reality" title="Direct link to The DX12/Vulkan Reality">​</a></h3>
<p>Modern APIs shifted control from the driver to the developer. Explicit control offers higher performance but removes the safety net. If your engine requests a specific Shader + Blend State combination that hasn't been pre-compiled (Precached), the driver must pause execution to compile it right now.</p>
<div class="theme-admonition theme-admonition-danger admonition_xJq3 alert alert--danger"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"></path></svg></span>Result</div><div class="admonitionContent_BuS1"><p>A hitch.</p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="part-2-the-core-problem--permutation-explosion">Part 2: The Core Problem – Permutation Explosion<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#part-2-the-core-problem--permutation-explosion" class="hash-link" aria-label="Direct link to Part 2: The Core Problem – Permutation Explosion" title="Direct link to Part 2: The Core Problem – Permutation Explosion">​</a></h2>
<p>Why can't we just compile everything at startup? Because of <strong>Shader Permutations</strong>.</p>
<p>Modern material systems allow artists to toggle thousands of options (Static Switches). If you have a shader with 10 boolean switches (Shadows, Fog, Metalness, etc.), that creates <strong>2^10 (1,024) potential variants</strong>.</p>
<p>Unreal Engine historically favors Permutations over Dynamic Branching:</p>
<table><thead><tr><th>Approach</th><th>GPU Performance</th><th>Disk Size</th><th>Compile Time</th></tr></thead><tbody><tr><td><strong>Permutations</strong></td><td>✅ Fast (dedicated variant per combo)</td><td>❌ Large</td><td>❌ Slow</td></tr><tr><td><strong>Dynamic Branching</strong></td><td>❌ Slower (branch divergence)</td><td>✅ Small</td><td>✅ Fast</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="case-study-bungie-destiny">Case Study: Bungie (Destiny)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#case-study-bungie-destiny" class="hash-link" aria-label="Direct link to Case Study: Bungie (Destiny)" title="Direct link to Case Study: Bungie (Destiny)">​</a></h3>
<p>In their 2017 GDC talk, Bungie revealed how they handled Destiny's <strong>18,000+ artist-authored shaders</strong>. They avoided explosion using the <strong>TFX System</strong>:</p>
<ul>
<li><strong>Components:</strong> Encapsulated shader options within code boundaries.</li>
<li><strong>Variant Layers:</strong> Artists created "layers" of overrides in a single file.</li>
<li><strong>Selective Building:</strong> Crucially, they adhered to a strict rule:</li>
</ul>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Bungie's Golden Rule</div><div class="admonitionContent_BuS1"><p><strong>"DON'T build ALL variants."</strong> Only compile the subsets actually used in game content, treating the pipeline as an offline content-bake rather than a runtime discovery.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="case-study-ubisoft-anvilnext-engine">Case Study: Ubisoft (AnvilNext Engine)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#case-study-ubisoft-anvilnext-engine" class="hash-link" aria-label="Direct link to Case Study: Ubisoft (AnvilNext Engine)" title="Direct link to Case Study: Ubisoft (AnvilNext Engine)">​</a></h3>
<p>Moving Assassin's Creed to DX12, Ubisoft found their existing "granular" state management (setting states piecemeal) was incompatible with DX12's "blob" PSOs. They had to rebuild their renderer to pre-calculate these state blobs offline or during loading screens, essentially creating a <strong>database of PSOs linked to material graphs</strong>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="honorable-mention-naughty-dog">Honorable Mention: Naughty Dog<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#honorable-mention-naughty-dog" class="hash-link" aria-label="Direct link to Honorable Mention: Naughty Dog" title="Direct link to Honorable Mention: Naughty Dog">​</a></h3>
<p>Naughty Dog opted for an <strong>Uber-Shader</strong> approach in The Last of Us Part II:</p>
<blockquote>
<p>"The shader is about 48,000 lines of code, which doesn't include generated code."</p>
</blockquote>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="part-3-unreal-engine-5">Part 3: Unreal Engine 5<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#part-3-unreal-engine-5" class="hash-link" aria-label="Direct link to Part 3: Unreal Engine 5" title="Direct link to Part 3: Unreal Engine 5">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="automated-pso-precaching">Automated PSO Precaching<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#automated-pso-precaching" class="hash-link" aria-label="Direct link to Automated PSO Precaching" title="Direct link to Automated PSO Precaching">​</a></h3>
<p>As of <strong>UE 5.3+</strong>, Epic enabled PSO Precaching by default. This system looks at the assets being loaded and compiles the necessary PSOs on background threads before the GPU needs them.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="implementing-the-loading-screen-the-wait-logic">Implementing the Loading Screen (The "Wait" Logic)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#implementing-the-loading-screen-the-wait-logic" class="hash-link" aria-label="Direct link to Implementing the Loading Screen (The &quot;Wait&quot; Logic)" title="Direct link to Implementing the Loading Screen (The &quot;Wait&quot; Logic)">​</a></h3>
<p>Even with background precaching, <strong>Global Shaders</strong> (Post-process, Compute) must be ready before gameplay starts. Gate your gameplay behind a loading screen that checks the compiler status.</p>
<div class="theme-admonition theme-admonition-info admonition_xJq3 alert alert--info"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>Implementation</div><div class="admonitionContent_BuS1"><p>Check <code>FShaderPipelineCache::NumPrecompilesRemaining()</code>. Do <strong>not</strong> remove the loading screen until this returns <code>0</code>.</p></div></div>
<p>Enable precaching via CVar:</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.PSOPrecaching=1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bundled-psos">Bundled PSOs<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#bundled-psos" class="hash-link" aria-label="Direct link to Bundled PSOs" title="Direct link to Bundled PSOs">​</a></h3>
<p>You can also record a <strong>Bundled PSO Cache</strong> — a recording of every shader drawn during a QA playthrough, bundled into the installer.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="console-command-for-diagnosis">Console Command for Diagnosis<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#console-command-for-diagnosis" class="hash-link" aria-label="Direct link to Console Command for Diagnosis" title="Direct link to Console Command for Diagnosis">​</a></h3>
<p>Use <code>stat unitgraph</code> to visualize hitches. If the green line (GPU) or game thread spikes simultaneously with a <code>LogRHI</code> warning in the output log, you missed a PSO.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="step-by-step-creating-a-bundled-pso-cache">Step-by-Step: Creating a Bundled PSO Cache<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#step-by-step-creating-a-bundled-pso-cache" class="hash-link" aria-label="Direct link to Step-by-Step: Creating a Bundled PSO Cache" title="Direct link to Step-by-Step: Creating a Bundled PSO Cache">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-configuration">1. Configuration<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#1-configuration" class="hash-link" aria-label="Direct link to 1. Configuration" title="Direct link to 1. Configuration">​</a></h3>
<p>Set up your project to generate <strong>Stable Keys</strong> — identifiers that persist across builds.</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">DefaultEngine.ini</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">[DevOptions.Shaders]</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">NeedsShaderStableKeys=true</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">[ShaderPipelineCache]</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">LastOpenedMask=0</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.ShaderPipelineCache.StartupMode=1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockTitle_Ktv7">DefaultGame.ini</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">[/Script/UnrealEd.ProjectPackagingSettings]</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">bShareMaterialShaderCode=True</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">bSharedMaterialNativeLibraries=True</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-the-clean-sweep">2. The Clean Sweep<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#2-the-clean-sweep" class="hash-link" aria-label="Direct link to 2. The Clean Sweep" title="Direct link to 2. The Clean Sweep">​</a></h3>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Critical Step</div><div class="admonitionContent_BuS1"><p>Old metadata <strong>poisons</strong> new caches. Always start clean.</p></div></div>
<ol>
<li>Delete <code>Intermediate</code>, <code>Saved/Cooked</code>, and <code>Binaries</code>.</li>
<li>Perform a full Cook/Package of the game.</li>
<li>Locate the generated <code>.shk</code> files in:<!-- -->
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">Saved/Cooked/Windows/[Project]/Metadata/PipelineCaches/</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<strong>Save these files — you will need them.</strong></li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-recording">3. Recording<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#3-recording" class="hash-link" aria-label="Direct link to 3. Recording" title="Direct link to 3. Recording">​</a></h3>
<p>Play the game on the target hardware.</p>
<p>Launch with the following arguments:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">-logPSO -clearPSODriverCache</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>During the session:</p>
<ul>
<li>Open every menu</li>
<li>Fire every weapon</li>
<li>Visit every level</li>
</ul>
<p>Collect the <code>.rec.upipelinecache</code> files from <code>Saved/CollectedPSOs/</code>.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-expanding-the-cache">4. Expanding the Cache<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#4-expanding-the-cache" class="hash-link" aria-label="Direct link to 4. Expanding the Cache" title="Direct link to 4. Expanding the Cache">​</a></h3>
<p>Use the Unreal commandlet to merge the Recording (<code>.rec</code>) with the Stable Keys (<code>.shk</code>) to produce the Pipeline Cache (<code>.spc</code>).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="5-packaging">5. Packaging<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#5-packaging" class="hash-link" aria-label="Direct link to 5. Packaging" title="Direct link to 5. Packaging">​</a></h3>
<ol>
<li>Place the generated <code>.spc</code> file into <code>Build\Windows\PipelineCaches\</code>.</li>
<li>Repackage the game.</li>
</ol>
<p>The engine will now load this cache on startup, pre-compiling the recorded PSOs during your splash screens.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>Further Reading</div><div class="admonitionContent_BuS1"><p><a href="https://www.youtube.com/watch?v=NVoXDgXKS5k&amp;t=89s" target="_blank" rel="noopener noreferrer">Video walkthrough of the full process</a></p></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="advanced-custom-brute-force-preloading-system">Advanced: Custom "Brute Force" Preloading System<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#advanced-custom-brute-force-preloading-system" class="hash-link" aria-label="Direct link to Advanced: Custom &quot;Brute Force&quot; Preloading System" title="Direct link to Advanced: Custom &quot;Brute Force&quot; Preloading System">​</a></h2>
<p>While UE5's native precaching works well for <strong>linear games</strong>, it often falls short in <strong>Open World</strong> or <strong>Level Streaming</strong> scenarios. If the engine streams in a new biome chunk, the native precacher may not compile new foliage shaders fast enough, causing a game-thread spike.</p>
<p>To address this, a "Brute Force" Precompilation System has been prototyped by developers (such as user <code>S_PHIR_H</code> on the Epic forums).</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-the-filter-class-selection">1. The Filter (Class Selection)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#1-the-filter-class-selection" class="hash-link" aria-label="Direct link to 1. The Filter (Class Selection)" title="Direct link to 1. The Filter (Class Selection)">​</a></h3>
<p>Instead of loading everything, the script focuses on the heaviest shader contributors.</p>
<p><strong>Nodes:</strong> <code>Get Asset Registry → Make ARFilter → Get Assets</code></p>
<p><strong>Classes to include:</strong></p>
<ul>
<li><code>StaticMesh</code></li>
<li><code>SkeletalMesh</code></li>
<li><code>NiagaraSystem</code> <em>(VFX are a frequent source of hitches)</em></li>
</ul>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>This check runs in the editor, but can be adapted for runtime use.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-the-grid-loop-positioning">2. The Grid Loop (Positioning)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#2-the-grid-loop-positioning" class="hash-link" aria-label="Direct link to 2. The Grid Loop (Positioning)" title="Direct link to 2. The Grid Loop (Positioning)">​</a></h3>
<p>Spawning thousands of assets at <code>(0, 0, 0)</code> causes physics collisions and debugging nightmares. The script calculates a grid position for each asset:</p>
<table><thead><tr><th>Axis</th><th>Formula</th><th>Result</th></tr></thead><tbody><tr><td><strong>X</strong></td><td><code>(Index % 100) * 200</code></td><td>Creates rows of 100 items</td></tr><tr><td><strong>Y</strong></td><td><code>(Index / 100) * 200</code></td><td>Advances to the next row every 100 items</td></tr><tr><td><strong>Spacing</strong></td><td><code>200 units</code></td><td>Prevents overlap</td></tr></tbody></table>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-spawning-the-asset">3. Spawning the Asset<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#3-spawning-the-asset" class="hash-link" aria-label="Direct link to 3. Spawning the Asset" title="Direct link to 3. Spawning the Asset">​</a></h3>
<p>Use the <strong>Spawn Actor from Object</strong> node, passing Asset Data from the registry search. This spawns the appropriate actor representation (e.g., a <code>StaticMeshActor</code> for a Static Mesh) at the calculated grid location.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-scale-normalization-anti-overlap-logic">4. Scale Normalization (Anti-Overlap Logic)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#4-scale-normalization-anti-overlap-logic" class="hash-link" aria-label="Direct link to 4. Scale Normalization (Anti-Overlap Logic)" title="Direct link to 4. Scale Normalization (Anti-Overlap Logic)">​</a></h3>
<p>Assets range from 1cm screws to 100m skyscrapers. To ensure the camera can see all of them without massive overlaps, the script <strong>normalizes scale</strong> across all spawned actors before the camera sweep begins.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="conclusion">Conclusion<a href="https://unreal-engine-ace7bf.gitlab.io/blog/2026/01/19/pso-precahching#conclusion" class="hash-link" aria-label="Direct link to Conclusion" title="Direct link to Conclusion">​</a></h2>
<p>Shader hitching is a solvable problem, but it requires a <strong>multi-layered defense strategy</strong>:</p>
<table><thead><tr><th>Layer</th><th>Approach</th><th>When</th></tr></thead><tbody><tr><td>🔻 <strong>Reduce Variants</strong></td><td>Minimize Static Switch usage in materials</td><td>Always</td></tr><tr><td>🤖 <strong>Automate</strong></td><td>Use the Brute Force system to catch edge cases</td><td>Dev / Testing</td></tr><tr><td>⏳ <strong>Wait for PSOs</strong></td><td>Show a loading screen until precaching completes (<a href="https://x.com/flassari/status/1996550280251584627" target="_blank" rel="noopener noreferrer">reference</a>)</td><td>Level transitions</td></tr><tr><td>📦 <strong>Record</strong></td><td>Perform a Bundled PSO recording for a smooth end-user experience</td><td>Release</td></tr></tbody></table>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>All four systems can — and should — be used together for maximum coverage.</p></div></div>]]></content:encoded>
            <category>facebook</category>
            <category>hello</category>
            <category>docusaurus</category>
        </item>
        <item>
            <title><![CDATA[PC Gaming Optimization Guide]]></title>
            <link>https://unreal-engine-ace7bf.gitlab.io/blog/optimization</link>
            <guid>https://unreal-engine-ace7bf.gitlab.io/blog/optimization</guid>
            <pubDate>Tue, 13 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[A deep-dive into system-level bottlenecks, OS issues, engine-level tweaks, and GPU-specific fixes for smoother gaming performance.]]></description>
            <content:encoded><![CDATA[<p>Most "optimization" guides just tell you to turn on DLSS or FSR or get new hardware. This guide focuses on the fundamentals:</p>
<ul>
<li>System-level bottlenecks</li>
<li>OS issues</li>
<li>Engine-level tweaks</li>
<li>Red/Green specific fixes</li>
</ul>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-the-clean-environment-protocol">1. The "Clean Environment" Protocol<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#1-the-clean-environment-protocol" class="hash-link" aria-label="Direct link to 1. The &quot;Clean Environment&quot; Protocol" title="Direct link to 1. The &quot;Clean Environment&quot; Protocol">​</a></h2>
<p>Before tweaking settings, eliminate background interference.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="kill-the-overlays">Kill the Overlays<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#kill-the-overlays" class="hash-link" aria-label="Direct link to Kill the Overlays" title="Direct link to Kill the Overlays">​</a></h3>
<p>Disable Steam, Discord, GameBar, and NVIDIA overlays. These create "hooks" that interfere with frame pacing.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cold-boot">Cold Boot<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#cold-boot" class="hash-link" aria-label="Direct link to Cold Boot" title="Direct link to Cold Boot">​</a></h3>
<p>Don't just <strong>Restart</strong>. Perform a full <strong>Shutdown</strong>, let the hardware capacitors clear, and boot fresh.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="bios--drivers">BIOS &amp; Drivers<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#bios--drivers" class="hash-link" aria-label="Direct link to BIOS &amp; Drivers" title="Direct link to BIOS &amp; Drivers">​</a></h3>
<p>Keep your BIOS updated for critical CPU microcode fixes. For AMD, always use the latest chipset drivers directly from their site — not Windows Update.</p>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>Windows Update Reverting AMD Drivers</div><div class="admonitionContent_BuS1"><p>Windows Update sometimes reverts AMD drivers to older, generic versions, breaking features like Radeon Software. To fix this:</p><ol>
<li>Use the <strong>Show/Hide Updates</strong> troubleshooter to block the offending update.</li>
<li>Use <strong>Display Driver Uninstaller (DDU)</strong> in Safe Mode for a clean install of the latest official AMD drivers.</li>
<li>Disable driver updates via <strong>Device Installation Settings</strong> or <strong>Group Policy</strong> to prevent future overwrites.</li>
</ol></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="debloated-os">Debloated OS<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#debloated-os" class="hash-link" aria-label="Direct link to Debloated OS" title="Direct link to Debloated OS">​</a></h3>
<p>While older Windows iterations often feel snappier, staying on an outdated version isn't recommended for security reasons. The best option is <strong>Windows Enterprise</strong>, which receives stable, timely updates and ships with less bloat. LTSC releases have been known to cause compatibility issues.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-antivirus--security-the-stutter-killers">2. Antivirus &amp; Security (The Stutter Killers)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#2-antivirus--security-the-stutter-killers" class="hash-link" aria-label="Direct link to 2. Antivirus &amp; Security (The Stutter Killers)" title="Direct link to 2. Antivirus &amp; Security (The Stutter Killers)">​</a></h2>
<p>Windows Security can cause massive hitches by scanning game files as they are streamed.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="add-av-exclusions">Add AV Exclusions<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#add-av-exclusions" class="hash-link" aria-label="Direct link to Add AV Exclusions" title="Direct link to Add AV Exclusions">​</a></h3>
<p>Add your game's <code>.exe</code> and its installation folder to your antivirus <strong>Exclusions</strong> list.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="exclude-shader-caches">Exclude Shader Caches<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#exclude-shader-caches" class="hash-link" aria-label="Direct link to Exclude Shader Caches" title="Direct link to Exclude Shader Caches">​</a></h3>
<p>This is critical. Add these paths to your exclusions:</p>
<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">%AppData%\Local Low\NVIDIA\PerDriverVersion\DXCache</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">%LocalAppData%\[GameName]\Saved</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cfg-override">CFG Override<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#cfg-override" class="hash-link" aria-label="Direct link to CFG Override" title="Direct link to CFG Override">​</a></h3>
<ol>
<li>Open <strong>Start</strong> and search for <strong>Exploit Protection</strong>.</li>
<li>Go to <strong>Program Settings</strong>.</li>
<li>Add your game's <code>.exe</code>.</li>
<li>Scroll to <strong>Control Flow Guard (CFG)</strong> → <strong>Override</strong> → set to <strong>OFF</strong>.</li>
</ol>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-unreal-engine-5-manual-tuning">3. Unreal Engine 5 Manual Tuning<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#3-unreal-engine-5-manual-tuning" class="hash-link" aria-label="Direct link to 3. Unreal Engine 5 Manual Tuning" title="Direct link to 3. Unreal Engine 5 Manual Tuning">​</a></h2>
<p>UE5 games often suffer from "traversal stutter." You can force better engine behaviour by editing configuration files manually.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="finding-the-config-file">Finding the Config File<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#finding-the-config-file" class="hash-link" aria-label="Direct link to Finding the Config File" title="Direct link to Finding the Config File">​</a></h3>
<ol>
<li>Paste <code>%LocalAppData%</code> into File Explorer.</li>
<li>Find your game's developer folder.</li>
<li>Navigate to: <code>Saved &gt; Config &gt; Windows</code> (or <code>WindowsClient</code> / <code>WinGDK</code>).</li>
<li>Open <code>Engine.ini</code>.</li>
</ol>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="pso-precaching">PSO Precaching<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#pso-precaching" class="hash-link" aria-label="Direct link to PSO Precaching" title="Direct link to PSO Precaching">​</a></h3>
<p>Add the following at the bottom of <code>Engine.ini</code>:</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">[/Script/Engine.RendererSettings]</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.PSOPrecaching=1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><code>r.PSOPrecaching=1</code> works for games built with <strong>UE5.3 and later</strong>. This CVAR forces the game to pre-compile shaders, reducing shader-compile stutter during gameplay.</p></div></div>
<p>You can also use this file to lower the graphics API or disable specific features on a per-game basis.</p>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="4-fastvram-console-level-memory-logic">4. FastVRam: Console-Level Memory Logic<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#4-fastvram-console-level-memory-logic" class="hash-link" aria-label="Direct link to 4. FastVRam: Console-Level Memory Logic" title="Direct link to 4. FastVRam: Console-Level Memory Logic">​</a></h2>
<p>In Unreal Engine, <strong>Fast VRAM</strong> is a specialized optimization flag within the Render Dependency Graph (RDG). It acts as a "VIP pass" for GPU memory allocation, instructing the renderer to place the most performance-critical resources — such as Depth Buffers, GBuffers, and Shadow Maps — into the hardware's fastest available memory pool.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="why-use-it">Why Use It?<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#why-use-it" class="hash-link" aria-label="Direct link to Why Use It?" title="Direct link to Why Use It?">​</a></h3>
<p>On consoles, <strong>bandwidth is king</strong>. By forcing the GBuffer (world normals, color, roughness) and Depth Buffers into high-speed VRAM, you reduce the time the GPU spends waiting for data. This mimics console-level stability on PC.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="configuration">Configuration<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#configuration" class="hash-link" aria-label="Direct link to Configuration" title="Direct link to Configuration">​</a></h3>
<p>Add the following under <code>[/Script/Engine.RendererSettings]</code> in your <code>Engine.ini</code>:</p>
<div class="language-ini codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ini codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.DBufferA=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.DBufferB=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.DBufferC=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.DBufferMask=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferA=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferB=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferC=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferD=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferE=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferF=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.GBufferVelocity=1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">r.FastVRam.SceneDepth=1</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="5-hardware-specific-tweaks">5. Hardware-Specific Tweaks<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#5-hardware-specific-tweaks" class="hash-link" aria-label="Direct link to 5. Hardware-Specific Tweaks" title="Direct link to 5. Hardware-Specific Tweaks">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="nvidia">NVIDIA<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#nvidia" class="hash-link" aria-label="Direct link to NVIDIA" title="Direct link to NVIDIA">​</a></h3>
<p>In <strong>NVIDIA Control Panel → Manage 3D Settings</strong>, set <strong>CUDA – System Fallback Policy</strong> to <strong>Prefer No System Fallback</strong>. This prevents the game from falling back to slow system RAM when VRAM fills up.</p>
<div class="theme-admonition theme-admonition-caution admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>caution</div><div class="admonitionContent_BuS1"><p>This setting is volatile and may reset after driver updates.</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="amd">AMD<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#amd" class="hash-link" aria-label="Direct link to AMD" title="Direct link to AMD">​</a></h3>
<p>If you have a Ryzen CPU and experience unexplained performance drops, try disabling <strong>Core Isolation</strong> in Windows Security settings.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="resizable-bar-rebar">Resizable BAR (ReBar)<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#resizable-bar-rebar" class="hash-link" aria-label="Direct link to Resizable BAR (ReBar)" title="Direct link to Resizable BAR (ReBar)">​</a></h3>
<table><thead><tr><th>GPU Generation</th><th>Method</th></tr></thead><tbody><tr><td>NVIDIA Turing / GTX 1600</td><td>Use <a href="https://github.com/xCuri0/ReBarUEFI" target="_blank" rel="noopener noreferrer">NvStrapsReBar</a> to enable ReBar on older cards</td></tr><tr><td>AMD Polaris / Vega</td><td>Enable SAM via Registry by setting <code>KMD_EnableReBarForLegacyASIC</code> to <code>1</code></td></tr></tbody></table>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="6-the-nuclear-option">6. The "Nuclear" Option<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#6-the-nuclear-option" class="hash-link" aria-label="Direct link to 6. The &quot;Nuclear&quot; Option" title="Direct link to 6. The &quot;Nuclear&quot; Option">​</a></h2>
<p>If you're still experiencing stuttering after everything above:</p>
<ul>
<li><strong>DDU (Display Driver Uninstaller):</strong> Run in Safe Mode to fully wipe your GPU drivers, then reinstall the latest version from scratch.</li>
<li><strong>Disable Overclocks:</strong> UE5.0–5.3 is extremely sensitive to instability. If you're crashing, return your CPU and GPU to stock speeds.</li>
<li><strong>Clear Shader Caches:</strong> Manually delete the <code>DXCache</code> folders mentioned in <a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#2-antivirus--security-the-stutter-killers">Section 2</a> to force a clean rebuild.</li>
<li><strong>Set Virtual Memory to 0:</strong> If you have sufficient RAM, disabling the page file can remove a source of latency. <em>(Tip via @GameDevMicah)</em></li>
</ul>
<hr>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="summary">Summary<a href="https://unreal-engine-ace7bf.gitlab.io/blog/optimization#summary" class="hash-link" aria-label="Direct link to Summary" title="Direct link to Summary">​</a></h2>
<p>True optimization isn't just about upscaling — it's about <strong>removing software friction</strong> and <strong>managing memory like a console</strong>. Fix the foundation first.</p>]]></content:encoded>
            <category>gaming</category>
            <category>unreal-engine</category>
            <category>optimization</category>
            <category>ue5</category>
            <category>nvidia</category>
            <category>amd</category>
        </item>
    </channel>
</rss>