Created
August 29, 2025 14:14
-
-
Save sociofall/951756a413a679c3e4b60f2ff01f6dcc to your computer and use it in GitHub Desktop.
Tricubic Sampling for Unreal Engine – Volumetric Fog modifications
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Unreal Engine – Tricubic Sampling for Volumetric Fog | |
| # This method provides better terminators, hiding the aliasing | |
| ## 1. Paste the function | |
| Navigate to: Engine/Shaders/Private/HeightFogCommon.ush | |
| At the top of the file (ex. after FogStructData struct) insert the following function: | |
| // tricubic interpolation function for sampling the volumetric fog 3D texture | |
| // ported from https://www.shadertoy.com/view/cts3Rj | |
| float4 textureTriCubic(Texture3D sourceTex, SamplerState sourceSampler, float3 texCoords) | |
| { | |
| // setup | |
| uint width, height, depth; | |
| sourceTex.GetDimensions(width, height, depth); | |
| float3 texSize = float3(width, height, depth); | |
| float3 coord_grid = texCoords * texSize - 0.5; | |
| float3 index = floor(coord_grid); | |
| float3 fraction = coord_grid - index; | |
| fraction = saturate(fraction); | |
| float3 one_frac = 1.0 - fraction; | |
| float3 w0 = 1.0/6.0 * one_frac * one_frac * one_frac; | |
| float3 w1 = 2.0/3.0 - 0.5 * fraction * fraction * (2.0 - fraction); | |
| float3 w2 = 2.0/3.0 - 0.5 * one_frac * one_frac * (2.0 - one_frac); | |
| float3 w3 = 1.0/6.0 * fraction * fraction * fraction; | |
| float3 g0 = w0 + w1; | |
| float3 g1 = w2 + w3; | |
| float3 mult = 1.0 / texSize; | |
| float3 h0 = mult * ((w1 / g0) - 0.5 + index); | |
| float3 h1 = mult * ((w3 / g1) + 1.5 + index); | |
| // clamp to valid uv range, since actual uv is located within this rectangle -> View.VolumetricFogUVMax.xy | |
| const float2 actualmaxuv_xy = View.VolumetricFogUVMax.xy; | |
| h0.xy = clamp(h0.xy, 0, actualmaxuv_xy); | |
| h1.xy = clamp(h1.xy, 0, actualmaxuv_xy); | |
| // fetching and weighting is interleaved for potential latency hiding | |
| float4 tex000 = sourceTex.SampleLevel(sourceSampler, h0, 0.0); | |
| float4 tex100 = sourceTex.SampleLevel(sourceSampler, float3(h1.x, h0.y, h0.z), 0.0); | |
| tex000 = lerp(tex100, tex000, g0.x); | |
| float4 tex010 = sourceTex.SampleLevel(sourceSampler, float3(h0.x, h1.y, h0.z), 0.0); | |
| float4 tex110 = sourceTex.SampleLevel(sourceSampler, float3(h1.x, h1.y, h0.z), 0.0); | |
| tex010 = lerp(tex110, tex010, g0.x); | |
| tex000 = lerp(tex010, tex000, g0.y); | |
| float4 tex001 = sourceTex.SampleLevel(sourceSampler, float3(h0.x, h0.y, h1.z), 0.0); | |
| float4 tex101 = sourceTex.SampleLevel(sourceSampler, float3(h1.x, h0.y, h1.z), 0.0); | |
| tex001 = lerp(tex101, tex001, g0.x); | |
| float4 tex011 = sourceTex.SampleLevel(sourceSampler, float3(h0.x, h1.y, h1.z), 0.0); | |
| float4 tex111 = sourceTex.SampleLevel(sourceSampler, h1, 0.0); | |
| tex011 = lerp(tex111, tex011, g0.x); | |
| tex001 = lerp(tex011, tex001, g0.y); | |
| return lerp(tex001, tex000, g0.z); | |
| } | |
| ## 2. Replace fog sampling calls | |
| Inside CombineVolumetricFog() function within same file, replace all instances of: | |
| VolumetricFogLookup = Texture3DSampleLevel(FogStruct.IntegratedLightScattering, SharedIntegratedLightScatteringSampler, VolumeUV, 0); | |
| with: | |
| VolumetricFogLookup = textureTriCubic(FogStruct.IntegratedLightScattering, SharedIntegratedLightScatteringSampler, VolumeUV); | |
| ## 3. Done. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment