--[[ Sol - fog calculation modul Author: Peter Boese The basic model: Cam position material mist pollusion humidity distant | | | | | | | | | | | | | | | | | O | | | | | | | | | | | ################################################################################################################################### Mix: variable variable variable variable 100% Mix hierarchy 1 2 3 4 5 Fog values are interpolated by modulators like: __humidity : humidity strenght __smog : main smog value, generated by track adaptions / sky__smog : smog multiplier in sol_config __fog_dense : mist strenght __inair_material.dense : dense of the inair material to create a resulting fog. ]] -- distance fog, higher absorbtion of low frequencies local _l_dist_fog = { distance = 30000, -- the distance in meters blend = 0.90, -- at the full distance, the fog is mixed by this value density = 1.75, -- a multiplier for the mixing exponent = 1.20, -- lower values will make the near fog denser backlit = 0.05, -- fog is litten from behind by the sun sky = 0.0, -- maximum pollution of the sky by this particular fog sun = 1.0, night = 0.0, -- an offset to be more visible in the night color = hsv(220, 0.5, 2.5):toRgb() -- the fog's color, HSV model --[[ HSV Model: H: Hue (0=red, 60=yellow, 120=green, 180=cyan, 240=blue, 315=magenta) S: Saturation V: Value ]] } -- humidity fog, light is absorbed by humid air in the distant -- can be used also for diffusing horizontal line local _l_humidity_fog = { distance = 18000, blend = 1.00, density = 2.0, exponent = 1.0, backlit = { 0.60, 0.05 }, -- { value with zero dense, value with full dense } sky = 0.0, night = 0.25, color_low = hsv(215, 0.45, 6):toRgb(), color_high = hsv(215, 0.65, 4.0):toRgb() } -- smog fog, light is absorbed by pollusion local _l_smog_fog = { distance = 20000, blend = 1.7, density = 1.5, exponent = 0.45, backlit = { 0.1, 0.001 }, sky = 0.9, night = 0.5, color_low = hsv(215, 0.15, 25):toRgb(), color_high = hsv(225, 0.25, 2.50):toRgb() } -- mist fog, ligth is absorbed by steam, steam is litten by the sun local _l_mist_fog = { distance = 1700, blend = 1.35, density = 2.0, exponent = 0.4, backlit = { 0.7, 0.01 }, sky = 1.0, night = 0.5, color_low = hsv(225, 0.20, 16.00):toRgb(), color_high = hsv(225, 0.00, 3.50):toRgb() } -- material filled air, light is absorbed by a material in the air local _l_material_fog = { distance = 1500, blend = 1.2, density = 1.0, exponent = 0.3, backlit = { 0.1, 0.001 }, sky_low = 0.10, sky_high = 1.00, night = 0.125, color = hsv(225, 0.0, 1.0):toRgb() } -- A simple LUT to control distant and smog fog while transition to night local _l_sunangle_multi_LUT = { -- gain, { -90, 0.00 }, { -18, 0.00 }, { -12, 0.07 }, { -6, 0.15 }, { -3, 0.20 }, { 0, 0.25 }, { 3, 0.35 }, { 6, 0.50 }, { 9, 0.65 }, { 12, 0.80 }, { 20, 1.00 }, { 90, 1.00 }, } local _l_SunangleMulti_lut local _l_SunangleMultiCPP = LUT:new(_l_sunangle_multi_LUT) -- basic temperature dependency curve -- Index is temperature local _l_fog_temp_LUT = { -- dist humi mist level { 0, 1.05, 1.10, 0.70, 1.50 }, { 5, 1.04, 1.08, 1.85, 1.20 }, { 10, 1.03, 1.06, 1.20, 0.75 }, { 17, 1.02, 1.04, 1.00, 0.90 }, { 24, 1.00, 1.00, 1.00, 1.00 }, { 32, 1.03, 1.05, 1.00, 1.10 }, { 40, 1.20, 1.15, 1.00, 1.20 }, } local _l_FogTemp_lut local _l_FogTempCPP = LUT:new(_l_fog_temp_LUT) local _l_mist = 0 -- a little LUT to translate the real humidity into the linear technical humidity fog local _l_humidity_LUT = { -- { 0.00, 0.00, }, { 0.10, 0.01, }, { 0.20, 0.03, }, { 0.30, 0.06, }, { 0.40, 0.11, }, { 0.50, 0.15, }, { 0.60, 0.20, }, { 0.70, 0.35, }, { 0.80, 0.45, }, { 0.90, 0.70, }, { 1.00, 1.00, }, } local _l_humid = 0 local _l_humidCPP = LUT:new(_l_humidity_LUT) local _l_smog = 0 local light_distance_filter = rgb(0,0,0) local f_dist = 40000 local f_blend = 1.0 local f_exponent = 1.0 local _l_FOG_COLOR = hsv(0,0,1) function GFX__get_fog_color_HSV() return hsv(_l_FOG_COLOR.h,_l_FOG_COLOR.s,_l_FOG_COLOR.v) end function GFX__set_fog_color_HSV(color) ac.setFogColor( color:toRgb() ) end -- main function to retrieve the fog mix value by a given distance function gfx__get_fog_dense(radius) return math.pow((1-((f_dist-radius)/math.max(1,f_dist)))*f_blend, f_exponent * (1 + __inair_material.granulation)) end function gfx__get_smog_dense() if __CW__.CustomWeather__.use then return __CW__.CustomWeather__Pollutions.Smog else return math.min(1, __smog * SOL__config("sky", "smog")) end end function gfx__get_humidity() return _l_humid end function gfx__get_distance_spectral_filter() return light_distance_filter end function gfx__get_custom_distant_fog() return _l_dist_fog end function gfx__set_custom_distant_fog( custom_distant_fog ) _l_dist_fog = { distance = custom_distant_fog.distance , blend = custom_distant_fog.blend , density = custom_distant_fog.density , exponent = custom_distant_fog.exponent , backlit = custom_distant_fog.backlit , sky = custom_distant_fog.sky , sun = custom_distant_fog.sun , night = custom_distant_fog.night , color = custom_distant_fog.color , } --compensate custom distant fog with other fog inputs local comp_sky = math.min(1, math.max( _l_humid, math.max(_l_smog, __inair_material.dense * 1.75))) _l_dist_fog.sky = math.lerp(_l_dist_fog.sky, 0, comp_sky) _l_dist_fog.exponent = math.lerp(_l_dist_fog.exponent, 1, comp_sky) _l_dist_fog.color = math.lerp(_l_dist_fog.color, hsv(220, 0.5, 2.5):toRgb(), comp_sky) end function gfx__update_fog() local _l_night_slow_fade = __IntN(0,1,10) if SOL__config("nerd__fog_custom_distant_fog", "use") then local _l__custom_distant_fog = { distance = SOL__config("nerd__fog_custom_distant_fog", "distance") , blend = SOL__config("nerd__fog_custom_distant_fog", "blend") , density = SOL__config("nerd__fog_custom_distant_fog", "density") , exponent = SOL__config("nerd__fog_custom_distant_fog", "exponent") , backlit = SOL__config("nerd__fog_custom_distant_fog", "backlit") , sky = SOL__config("nerd__fog_custom_distant_fog", "sky") , sun = SOL__config("nerd__fog_custom_distant_fog", "sun") , night = SOL__config("nerd__fog_custom_distant_fog", "night") , color = hsv(SOL__config("nerd__fog_custom_distant_fog", "Hue"), SOL__config("nerd__fog_custom_distant_fog", "Saturation"), SOL__config("nerd__fog_custom_distant_fog", "Level") ):toRgb() -- the fog's color, HSV model } gfx__set_custom_distant_fog(_l__custom_distant_fog) end -- modulate ambient light with temperature _l_FogTemp_lut = _l_FogTempCPP:get(__temperature) --interpolate__plan(_l_fog_temp_LUT, nil, __temperature) -- translate humidity _l_humid = (_l_humidCPP:get(__humidity) or {0,0})[1] --(interpolate__plan(_l_humidity_LUT, nil, __humidity) or {0,0})[1] -- translate fog/mist _l_mist = math.pow(__fog_dense, 2) -- main smog calculation _l_smog = math.pow(gfx__get_smog_dense(), 1.25) -- lower distance with high smog values _l_smog_fog.distance = 25000-20000*math.pow(_l_smog, 2) local _l_granulation_ratio = math.pow(1-__inair_material.granulation, 0.1) local _l_humidity_ratio = math.pow(_l_humid * _l_FogTemp_lut[2], 1) * _l_night_slow_fade --compensate mist distant look with negative distant.sky --_l_mist_fog.sky = 0.15 * math.pow(math.max(0, _l_dist_fog.sky*-1), 0.35) -- create material fog color and make it dependent to ambient and sun ligth _l_material_fog.color = hsv(__inair_material.color.h, __inair_material.color.s, __inair_material.color.v * math.pow(__ambient_color.v * 0.05 + #__lightColor * 0.025, 0.7)):toRgb() local PPoff_fog_color_gain = 1 if nopp__use_sol_without_postprocessing then --compensate ambient brightness calculations with PPoff adjustments PPoff_fog_color_gain = 0.75 end --### distance ### _l_dist_fog.distance = math. min(_l_dist_fog.distance, ta_dome_size) f_dist = _l_dist_fog.distance * ta_fog_distance f_dist = math.lerp( f_dist, math.min(f_dist, _l_humidity_fog.distance), _l_humidity_ratio) f_dist = math.lerp( f_dist, math.min(f_dist, _l_smog_fog.distance), _l_smog) f_dist = math.lerp( f_dist, math.min(f_dist, _l_mist_fog.distance * _l_FogTemp_lut[3]), math.pow(_l_mist, 0.5)) f_dist = math.lerp( f_dist, math.min(f_dist, _l_material_fog.distance), __inair_material.dense) ac.setFogDistance( f_dist ) --### blend ### f_blend = _l_dist_fog.blend * ta_fog_blend * _l_FogTemp_lut[1] _l_material_fog.blend = 1.15 * _l_granulation_ratio f_blend = math.lerp( f_blend, math.max(f_blend, _l_humidity_fog.blend), _l_humidity_ratio) f_blend = math.lerp( f_blend, math.max(f_blend, _l_smog_fog.blend), _l_smog) f_blend = math.lerp( f_blend, math.max(f_blend, _l_mist_fog.blend), _l_mist) f_blend = math.lerp( f_blend, math.max(f_blend, _l_material_fog.blend * _l_granulation_ratio), __inair_material.dense) ac.setFogBlend( f_blend ) --### density ### local f_density = _l_dist_fog.density * (1 + 0.2 * (__overcast + __badness) * from_twilight_compensate(0)) f_density = math.lerp( f_density, math.max(f_density, _l_humidity_fog.density), _l_humidity_ratio) f_density = math.lerp( f_density, math.max(f_density, _l_smog_fog.density), _l_smog) f_density = math.lerp( f_density, math.max(f_density, _l_mist_fog.density), _l_mist) f_density = math.lerp( f_density, math.max(f_density, _l_material_fog.density), __inair_material.dense) ac.setFogDensity( f_density ) --### exponent ### f_exponent = _l_dist_fog.exponent f_exponent = math.lerp( f_exponent, _l_humidity_fog.exponent, _l_humidity_ratio) f_exponent = math.lerp( f_exponent, _l_smog_fog.exponent, _l_smog) f_exponent = math.lerp( f_exponent, _l_mist_fog.exponent, _l_mist) f_exponent = math.lerp( f_exponent, _l_material_fog.exponent, __inair_material.dense) ac.setFogExponent( f_exponent ) --### height ### ac.setFogHeight(8000) --### color ### _l_SunangleMulti_lut = _l_SunangleMultiCPP:get() --interpolate__plan(_l_sunangle_multi_LUT) local pollute_fog = hsv(__light_pollution.h, __light_pollution.s * 4 * _l_mist, __light_pollution.v * (1-0.65*__extern_illumination_offset))--__extern_illumination local f_sun_level = _l_SunangleMulti_lut[1] local _l_overcast_blue = math.max(0, math.min(1, (-0.80+__overcast)*5)) local _l_temp_dist_color = _l_dist_fog.color:toHsv() _l_temp_dist_color.s = _l_temp_dist_color.s * (1 - (0.25-0.5*_l_overcast_blue)*__overcast + (-0.25-0.15*__overcast)*__badness) _l_temp_dist_color.v = _l_temp_dist_color.v * math.max(0, (1 + (0.5-0.5*_l_overcast_blue)*__overcast - (0.3 + 1.00 * __overcast)*__badness )) local _l_night_distance_damper = (1-from_twilight_compensate(0)) * (1-(__extern_illumination_radius/20000)) --* math.min(1, __light_pollution.v*5) _l_night_distance_damper = math.lerp(_l_night_distance_damper, 1, math.min(1,_l_mist*1.5)) local f_color = _l_temp_dist_color:toRgb() * ta_fog_level * f_sun_level --- __IntD(0.4 + 0.1*__night__brightness_adjust + math.lerp(__moonlight_color.v*day_compensate(12), 0, __night__brightness_adjust*0.75), 0, 20) -- darken distance fog more to mask litten area -- _l_night_distance_damper --f_color = math.lerp( __ambient_color:toRgb()*-0.75/math.max(1,__light_pollution.v*0.5)*(0.5+0.5*_l_night_distance_damper), f_color, day_compensate(0)) f_color = math.lerp((-2*(0.20+0.80*_l_night_distance_damper)+__night__brightness_adjust)+__ambient_color:toRgb()*-0.5/math.max(1,__light_pollution.v*2), f_color, day_compensate(0)) -- measure the sky's color and add it to the different fogs - most with low sunangles local sky_color_calculation_point = temp_interpol(25,1.25,1.0) * interpolate_day_time(6.5,5.0,6.0) local measured_sky_color = gfx__get_sky_color(sphere2vec3(__sun_heading, sky_color_calculation_point), true) * temp_interpol(25,1.00,0.85) measured_sky_color = measured_sky_color:toHsv() measured_sky_color.s = measured_sky_color.s * 5 measured_sky_color = measured_sky_color:toRgb() local f_mix = (1-0.75*sun_compensate(0)) f_color = math.lerp(f_color, measured_sky_color, 0.25 * f_mix * math.pow(_l_humidity_ratio, 0.5)) local _l_temp_humid_color = math.lerp(_l_humidity_fog.color_low, _l_humidity_fog.color_high, _l_humidity_ratio) _l_temp_humid_color = math.lerp(_l_temp_humid_color, measured_sky_color, 0.3 * f_mix * (1-0.75*_l_humidity_ratio)) local _l_smog_color_calc = math.lerp(_l_smog_fog.color_low, _l_smog_fog.color_high, math.pow(_l_smog, 0.33)) local _l_temp_smog_color = math.lerp(_l_smog_color_calc, measured_sky_color, 0.7 * f_mix * (1-0.75*_l_smog)) local _l_mist_color_calc = math.lerp(_l_mist_fog.color_low, _l_mist_fog.color_high, _l_mist) local _l_temp_mist_color = math.lerp(_l_mist_color_calc, measured_sky_color, 0.5 * f_mix * (1-0.75*_l_mist)) ---------------------------------------------------------------------------------------------------------------------------- f_color = math.lerp(f_color, _l_temp_humid_color * math.max(f_sun_level, _l_humidity_fog.night), _l_humidity_ratio) f_color = f_color * _l_FogTemp_lut[4] f_color = math.lerp(f_color, _l_temp_smog_color * math.max(f_sun_level, _l_smog_fog.night ), _l_smog) f_color = math.lerp(f_color, (_l_temp_mist_color * math.max(f_sun_level, _l_mist_fog.night*_l_mist) ):add(pollute_fog:toRgb()), math.pow(_l_mist, 0.5)) f_color = f_color * math.pow(__ambient_color.v * 0.04 + #__lightColor * 0.02, 0.7) * (1-0.5*__overcast) local _l_sun_light_add = 1 if _l_dist_fog and _l_dist_fog.sun then _l_sun_light_add = _l_dist_fog.sun end f_color:add(__lightColor*0.08*_l_sun_light_add) f_color = f_color * math.max(0, 1-#__lightColor*0.02*math.pow(_l_sun_light_add, 0.33)) --f_color = f_color * night_compensate(sun_compensate(1-math.max(0.5*_l_smog, 0.0*_l_humidity_ratio))) f_color = math.lerp(f_color, (_l_material_fog.color * math.max(f_sun_level, _l_material_fog.night)):add(pollute_fog:toRgb() * (#_l_material_fog.color*sun_compensate(0.1))), __inair_material.dense) f_color = f_color * __PPoff__brightness__regulation * PPoff_fog_color_gain f_color = f_color * (1-0.7*__badness*(1-0.9*__overcast)) f_color:adjustSaturation((1+0.25*__badness)) --f_color:adjustSaturation(0) ac.setFogColor( f_color ) _l_FOG_COLOR = f_color:toHsv() --ac.debug("####", pollute_fog:toRgb()) --### backlit ### local f_backlit = _l_dist_fog.backlit * (1 - 0.75 * sun_compensate(0)) f_backlit = math.lerp( f_backlit, math.lerp(_l_humidity_fog.backlit[1], _l_humidity_fog.backlit[2], _l_humidity_ratio), __humidity *__IntD(1, 0.25, 0.6)) f_backlit = math.lerp( f_backlit, math.lerp(_l_smog_fog.backlit[1], _l_smog_fog.backlit[2], _l_smog), _l_smog) f_backlit = math.lerp( f_backlit, math.lerp(_l_mist_fog.backlit[1], _l_mist_fog.backlit[2], _l_mist), _l_mist) f_backlit = math.lerp( f_backlit, math.lerp(_l_material_fog.backlit[1], _l_material_fog.backlit[2], __inair_material.dense) * #_l_material_fog.color, __inair_material.dense) ac.setFogBacklitMultiplier(f_backlit * (math.pow(SOL__config("sun", "fog_bloom"), 2) * 0.5)) ac.setFogBacklitExponent(4-3*f_backlit) --### sky fog ### __sky_fog = _l_dist_fog.sky __sky_fog = math.lerp( __sky_fog, math.max(__sky_fog, _l_humidity_fog.sky), _l_humidity_ratio * math.max(0, 1-2*_l_smog)) local _l_humidity_top_clearer = 6 * math.max(0, 1-2*__inair_material.dense) local _l_sky__fog_calc = math.lerp( 0-_l_humidity_top_clearer*math.pow(_l_humidity_ratio, 3), __sky_fog, math.min(1, math.abs(__sky_fog))) __sky_fog = math.lerp(__sky_fog, _l_sky__fog_calc, sun_compensate(0) * math.max(0, (1-1.5*_l_mist))) __sky_fog = math.lerp( __sky_fog, math.max(__sky_fog, _l_smog_fog.sky), math.pow(_l_smog, 1)) __sky_fog = math.lerp( __sky_fog, math.max(__sky_fog, _l_mist_fog.sky), math.pow(_l_mist, 4)) local _l_material_sky_mix = math.lerp(_l_material_fog.sky_low, _l_material_fog.sky_high, __inair_material.dense) __sky_fog = math.lerp( __sky_fog, math.max(__sky_fog, _l_material_sky_mix), __inair_material.dense) --local _l_sky__fog_calc = math.lerp( 0-7*math.pow(_l_humidity_ratio, 3), __sky_fog, math.min(1, math.abs(__sky_fog))) --_d(_l_sky__fog_calc) ac.setSkyFogMultiplier(__sky_fog * (1-0.8*__inair_material.granulation)) --### horizont fog ### local f_hori = 0.4--don't start with 0 f_hori = math.max( f_hori, math.pow(_l_humidity_ratio, 0.3) * 0.95) f_hori = math.max( f_hori, math.pow(_l_mist, 0.5) * 4) f_hori = math.max( f_hori, math.pow(_l_smog , 0.2) * 1.05) f_hori = f_hori * _l_FogTemp_lut[1] f_hori = math.max( f_hori, math.pow(__inair_material.dense , 0.33) * 1.10) f_hori = math.min(1, f_hori) local h_fog local h_fog_exp local h_fog_height local h_smog_mod = math.pow(_l_smog, 0.5) local h_material_mod = math.pow(__inair_material.dense, 0.3) h_fog = f_hori * math.lerp(_l_night_distance_damper, 1, _l_night_slow_fade) * (1 + 0.25*__overcast*day_compensate(0)) h_fog = math.pow(h_fog, 1.5) h_fog_exp = 0.30 + math.max(1.5*h_material_mod , math.max(1.0*h_smog_mod , math.max(1.00*_l_mist, 0.00*_l_humidity_ratio))) h_fog_height = 1.15 - math.max(0.2*h_material_mod , math.max(0.4*h_smog_mod , math.max(0.40*__fog_dense, 0.20*_l_humidity_ratio))) ac.setHorizonFogMultiplier(h_fog, h_fog_exp, h_fog_height) -- calculate a filter for the lights travel through air/polluted air local spectrum_filter__smog = math.pow(_l_smog, 2) local spectrum_filter__humid = _l_humidity_ratio light_distance_filter = hsv(205 - math.min(25*spectrum_filter__smog, 40*spectrum_filter__humid), (1 - 0.25*spectrum_filter__smog), 3 + math.max(23*spectrum_filter__smog, 6*spectrum_filter__humid)):toRgb() light_distance_filter = light_distance_filter * sun_compensate(0) * (1 - __overcast) end