--[[ Second attempt to get something like volumetric fog to work. Adds a bit of basic denoise, and a bit of really conservative temporal denoise. Ideas for later: • Do that 3D voxel thing modern games are doing; • Add noise to the fog (already here, but for Nordschleife to look smooth this thing needs a lot of steps, and even a simple 3D noise is really expensive); • Add even better noise (height-dependent, local variance, etc.); • Triple screen support. ]] if not ScriptSettings.EXTRA_EFFECTS.FOG_VOLUMETRIC then UpdateVolumetricFog = function (dt) end return end local intensity = 0 local texData = {} table.insert(OnResolutionChange, function () table.clear(texData) end) local function createPassData(uniqueKey) local size = render.getRenderTargetSize() local txBase1 = ui.ExtraCanvas(size * 0.5, 1, render.TextureFormat.R16G16.Float):setName('Volumetric fog ('..tostring(uniqueKey)..')') local txBase2 = ui.ExtraCanvas(size * 0.5, 1, render.TextureFormat.R16G16.Float):setName('Volumetric fog ('..tostring(uniqueKey)..')') return { txBase1 = txBase1, txBase2 = txBase2, passRaymarch = { shader = 'shaders/volumetric_fog.fx', textures = { ['txPrev.2'] = txBase2 }, values = {gSeed = 0}, async = true, cacheKey = 1 }, passApply = { blendMode = render.BlendMode.BlendAdd, depthMode = render.DepthMode.ReadOnly, depth = 4, defines = {}, textures = { ['txBase.2'] = txBase1 }, values = { gScale = 2 / math.min(size.x, size.y), gIntensity = intensity }, shader = 'shaders/volumetric_fog_apply.fx', async = true, cacheKey = 1 } } end local function renderFog(passID, frameIndex, uniqueKey) render.measure('Volumetric fog', function (...) local tex = table.getOrCreate(texData, uniqueKey, createPassData, uniqueKey) tex.txBase1, tex.txBase2 = tex.txBase2, tex.txBase1 tex.passRaymarch.values.gSeed = math.random() tex.passRaymarch.textures['txPrev.2'] = tex.txBase2 tex.passApply.values.gIntensity = intensity tex.passApply.textures['txBase.2'] = tex.txBase1 tex.passApply.textures['txRain.1'] = RainHazeMap tex.passApply.defines.USE_RAIN = RainHazeMap ~= nil tex.passApply.cacheKey = RainHazeMap ~= nil and 2 or 1 render.backupRenderTarget() tex.txBase1:updateSceneWithShader(tex.passRaymarch) render.restoreRenderTarget() render.fullscreenPass(tex.passApply) end) end local subscribed ---@type fun()? function UpdateVolumetricFog(dt) intensity = math.lerp(0.02, 0.13, Sim.weatherConditions.humidity) intensity = math.lerp(intensity, 1, math.min(1, CurrentConditions.fog * 3)) intensity = math.lerp(intensity, 1, CurrentConditions.pollution) intensity = intensity * math.lerpInvSat(CurrentConditions.clear, 0.2, 0.5) intensity = intensity * math.lerpInvSat(FinalFog, 1, 0.8) intensity = intensity * math.lerpInvSat(ac.getAltitude(), 10e3, 5e3) intensity = intensity * math.lerpInvSat(SunDir.y, 0.01, 0.03) intensity = intensity * 2 if __monitored then ac.debug('Volumetric fog', intensity) end if intensity == 0 then if subscribed then subscribed() subscribed = nil end return end if not subscribed then subscribed = RenderGeometrySubscribe(render.PassID.Main, renderFog) end end