diff --git a/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli b/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli index 5358ad026..bc8347e8e 100644 --- a/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli +++ b/features/Wetness Effects/Shaders/WetnessEffects/WetnessEffects.hlsli @@ -2,6 +2,8 @@ namespace WetnessEffects { + Texture2D TexPrecipOcclusion : register(t31); + // https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile float2 EnvBRDFApproxWater(float3 F0, float Roughness, float NoV) { @@ -58,15 +60,15 @@ namespace WetnessEffects const float rippleBreadthRcp = rcp(wetnessEffectsSettings.RippleBreadth); float2 gridUV = worldPos.xy * wetnessEffectsSettings.RaindropGridSizeRcp; - gridUV += normal.xy * 0.5; + gridUV += normal.xy; int2 grid = floor(gridUV); gridUV -= grid; float3 rippleNormal = float3(0, 0, 1); float wetness = 0; - if (wetnessEffectsSettings.EnableSplashes || wetnessEffectsSettings.EnableRipples) - for (int i = -1; i <= 1; i++) + if (wetnessEffectsSettings.EnableSplashes || wetnessEffectsSettings.EnableRipples) { + for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { int2 gridCurr = grid + int2(i, j); float tOffset = float(Random::iqint3(gridCurr)) * uintToFloat; @@ -122,12 +124,7 @@ namespace WetnessEffects } } } - - if (wetnessEffectsSettings.EnableChaoticRipples) { - float3 turbulenceNormal = Random::perlinNoise(float3(worldPos.xy * wetnessEffectsSettings.ChaoticRippleScaleRcp, t * wetnessEffectsSettings.ChaoticRippleSpeed)); - turbulenceNormal.z = turbulenceNormal.z * .5 + 5; - turbulenceNormal = normalize(turbulenceNormal); - rippleNormal = normalize(rippleNormal + float3(turbulenceNormal.xy * wetnessEffectsSettings.ChaoticRippleStrength, 0)); + } } wetness *= wetnessEffectsSettings.SplashesStrength; diff --git a/package/Shaders/Common/SharedData.hlsli b/package/Shaders/Common/SharedData.hlsli index 7852b293c..0acabc24a 100644 --- a/package/Shaders/Common/SharedData.hlsli +++ b/package/Shaders/Common/SharedData.hlsli @@ -70,6 +70,8 @@ struct LightLimitFixSettings struct WetnessEffectsSettings { + row_major float4x4 OcclusionViewProj; + float Time; float Raining; float Wetness; @@ -92,26 +94,20 @@ struct WetnessEffectsSettings bool EnableSplashes; bool EnableRipples; - bool EnableChaoticRipples; - float RaindropFxRange; - float RaindropGridSizeRcp; float RaindropIntervalRcp; + float RaindropChance; float SplashesLifetime; - float SplashesStrength; float SplashesMinRadius; + float SplashesMaxRadius; float RippleStrength; - float RippleRadius; float RippleBreadth; - float RippleLifetimeRcp; - float ChaoticRippleStrength; - float ChaoticRippleScaleRcp; - float ChaoticRippleSpeed; + float RippleLifetimeRcp; }; struct SkylightingSettings diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index ba5fe5ed4..072399a5b 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -1783,16 +1783,23 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif float4 raindropInfo = float4(0, 0, 1, 0); - if (worldSpaceNormal.z > 0 && wetnessEffectsSettings.Raining > 0.0f && wetnessEffectsSettings.EnableRaindropFx && - (dot(input.WorldPosition, input.WorldPosition) < wetnessEffectsSettings.RaindropFxRange * wetnessEffectsSettings.RaindropFxRange)) { - if (wetnessOcclusion > 0.0) + if (worldSpaceNormal.z > 0 && wetnessEffectsSettings.Raining > 0.0f && wetnessEffectsSettings.EnableRaindropFx) { + float4 precipOcclusionTexCoord = mul(wetnessEffectsSettings.OcclusionViewProj, float4(input.WorldPosition.xyz, 1)); + precipOcclusionTexCoord.y = -precipOcclusionTexCoord.y; + float2 precipOcclusionUV = precipOcclusionTexCoord.xy * 0.5 + 0.5; + + if (saturate(precipOcclusionUV.x) == precipOcclusionUV.x && saturate(precipOcclusionUV.y) == precipOcclusionUV.y) { + float precipOcclusionZ = WetnessEffects::TexPrecipOcclusion.SampleLevel(SampColorSampler, precipOcclusionUV, 0).x; + + if (precipOcclusionTexCoord.z < precipOcclusionZ + 0.1) # if defined(SKINNED) - raindropInfo = WetnessEffects::GetRainDrops(input.ModelPosition.xyz, wetnessEffectsSettings.Time, worldSpaceNormal); + raindropInfo = WetnessEffects::GetRainDrops(input.ModelPosition.xyz, wetnessEffectsSettings.Time, worldSpaceNormal); # elif defined(DEFERRED) - raindropInfo = WetnessEffects::GetRainDrops(input.WorldPosition.xyz + CameraPosAdjust[eyeIndex].xyz, wetnessEffectsSettings.Time, worldSpaceNormal); + raindropInfo = WetnessEffects::GetRainDrops(input.WorldPosition.xyz + CameraPosAdjust[eyeIndex].xyz, wetnessEffectsSettings.Time, worldSpaceNormal); # else - raindropInfo = WetnessEffects::GetRainDrops(!FrameParams.y ? input.ModelPosition.xyz : input.WorldPosition.xyz + CameraPosAdjust[eyeIndex].xyz, wetnessEffectsSettings.Time, worldSpaceNormal); + raindropInfo = WetnessEffects::GetRainDrops(!FrameParams.y ? input.ModelPosition.xyz : input.WorldPosition.xyz + CameraPosAdjust[eyeIndex].xyz, wetnessEffectsSettings.Time, worldSpaceNormal); # endif + } } float rainWetness = wetnessEffectsSettings.Wetness * minWetnessAngle * wetnessEffectsSettings.MaxRainWetness; diff --git a/package/Shaders/Particle.hlsl b/package/Shaders/Particle.hlsl index 43830083a..90ef7c930 100644 --- a/package/Shaders/Particle.hlsl +++ b/package/Shaders/Particle.hlsl @@ -248,11 +248,11 @@ PS_OUTPUT main(PS_INPUT input) # endif // !VR # if defined(ENVCUBE) - float2 precipitationOcclusionUv = (input.PrecipitationOcclusionTexCoord.xy * 0.5 + 0.5) * TextureSize.x; + float2 precipitationOcclusionUV = (input.PrecipitationOcclusionTexCoord.xy * 0.5 + 0.5) * TextureSize.x; # ifdef VR - precipitationOcclusionUv *= DynamicResolutionParams1.x; // only difference in VR + precipitationOcclusionUV *= DynamicResolutionParams1.x; // only difference in VR # endif - float precipitationOcclusion = -input.PrecipitationOcclusionTexCoord.z + TexPrecipitationOcclusionTexture.SampleLevel(SampSourceTexture, precipitationOcclusionUv, 0).x; + float precipitationOcclusion = -input.PrecipitationOcclusionTexCoord.z + TexPrecipitationOcclusionTexture.Load(float3(precipitationOcclusionUV, 0)).x; float2 underwaterMaskUv = TextureSize.yz * input.Position.xy; float underwaterMask = TexUnderwaterMask.Sample(SampUnderwaterMask, underwaterMaskUv).x; if (precipitationOcclusion - underwaterMask < 0) { diff --git a/src/Features/WetnessEffects.cpp b/src/Features/WetnessEffects.cpp index ab03e4f0f..57b6ad581 100644 --- a/src/Features/WetnessEffects.cpp +++ b/src/Features/WetnessEffects.cpp @@ -2,29 +2,6 @@ #include "Util.h" -const float MIN_START_PERCENTAGE = 0.05f; -const float DEFAULT_TRANSITION_PERCENTAGE = 1.0f; -const float TRANSITION_CURVE_MULTIPLIER = 2.0f; -const float TRANSITION_DENOMINATOR = 256.0f; -const float DRY_WETNESS = 0.0f; -const float RAIN_DELTA_PER_SECOND = 2.0f / 3600.0f; -const float SNOWY_DAY_DELTA_PER_SECOND = -0.489f / 3600.0f; // Only doing evaporation until snow wetness feature is added -const float CLOUDY_DAY_DELTA_PER_SECOND = -0.735f / 3600.0f; -const float CLEAR_DAY_DELTA_PER_SECOND = -1.518f / 3600.0f; -const float WETNESS_SCALE = 2.0; // Speed at which wetness builds up and drys. -const float PUDDLE_SCALE = 1.0; // Speed at which puddles build up and dry -const float MAX_PUDDLE_DEPTH = 3.0f; -const float MAX_WETNESS_DEPTH = 2.0f; -const float MAX_PUDDLE_WETNESS = 1.0f; -const float MAX_WETNESS = 1.0f; -const float SECONDS_IN_A_DAY = 86400; -const float MAX_TIME_DELTA = SECONDS_IN_A_DAY - 30; -const float MIN_WEATHER_TRANSITION_SPEED = 0.0f; -const float MAX_WEATHER_TRANSITION_SPEED = 500.0f; -const float AVERAGE_RAIN_VOLUME = 4000.0f; -const float MIN_RAINDROP_CHANCE_MULTIPLIER = 0.1f; -const float MAX_RAINDROP_CHANCE_MULTIPLIER = 2.0f; - NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( WetnessEffects::Settings, EnableWetnessEffects, @@ -41,8 +18,6 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( EnableRaindropFx, EnableSplashes, EnableRipples, - EnableChaoticRipples, - RaindropFxRange, RaindropGridSize, RaindropInterval, RaindropChance, @@ -53,10 +28,7 @@ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT( RippleStrength, RippleRadius, RippleBreadth, - RippleLifetime, - ChaoticRippleStrength, - ChaoticRippleScale, - ChaoticRippleSpeed) + RippleLifetime) void WetnessEffects::DrawSettings() { @@ -86,17 +58,11 @@ void WetnessEffects::DrawSettings() ImGui::Checkbox("Enable Ripples", (bool*)&settings.EnableRipples); if (auto _tt = Util::HoverTooltipWrapper()) ImGui::Text("Enables circular ripples on puddles, and to a less extent other wet surfaces"); - ImGui::Checkbox("Enable Chaotic Ripples", (bool*)&settings.EnableChaoticRipples); - if (auto _tt = Util::HoverTooltipWrapper()) - ImGui::Text("Enables an additional layer of disturbance to wet surfaces."); - - ImGui::SliderFloat("Effect Range", &settings.RaindropFxRange, 1e2f, 2e3f, "%.0f game unit(s)"); if (ImGui::TreeNodeEx("Raindrops")) { ImGui::BulletText( "At every interval, a raindrop is placed within each grid cell.\n" - "Only a set portion of raindrops will actually trigger splashes and ripples.\n" - "Chaotic ripples are not affected by raindrop settings."); + "Only a set portion of raindrops will actually trigger splashes and ripples.\n"); ImGui::SliderFloat("Grid Size", &settings.RaindropGridSize, 1.f, 10.f, "%.1f game unit(s)"); ImGui::SliderFloat("Interval", &settings.RaindropInterval, 0.1f, 2.f, "%.1f sec"); @@ -128,13 +94,6 @@ void WetnessEffects::DrawSettings() ImGui::TreePop(); } - if (ImGui::TreeNodeEx("Chaotic Ripples")) { - ImGui::SliderFloat("Strength", &settings.ChaoticRippleStrength, 0.f, .5f, "%.2f"); - ImGui::SliderFloat("Scale", &settings.ChaoticRippleScale, 0.1f, 5.f, "%.2f", ImGuiSliderFlags_AlwaysClamp); - ImGui::SliderFloat("Speed", &settings.ChaoticRippleSpeed, 0.f, 50.f, "%.1f"); - ImGui::TreePop(); - } - ImGui::EndDisabled(); ImGui::TreePop(); @@ -192,161 +151,154 @@ void WetnessEffects::DrawSettings() ImGui::Spacing(); ImGui::Spacing(); - - if (ImGui::TreeNodeEx("Statistics", ImGuiTreeNodeFlags_DefaultOpen)) { - ImGui::Text(std::format("Wetness depth : {:.2f}", wetnessDepth / WETNESS_SCALE).c_str()); - ImGui::Text(std::format("Puddle depth : {:.2f}", puddleDepth / PUDDLE_SCALE).c_str()); - ImGui::Spacing(); - ImGui::Spacing(); - ImGui::Text(std::format("Current weather : {0:X}", currentWeatherID).c_str()); - ImGui::Text(std::format("Previous weather : {0:X}", lastWeatherID).c_str()); - ImGui::TreePop(); - } } -float WetnessEffects::CalculateWeatherTransitionPercentage(float skyCurrentWeatherPct, float beginFade, bool fadeIn) +class BGSShaderParticleGeometryDataVR : public RE::TESForm { - float weatherTransitionPercentage = DEFAULT_TRANSITION_PERCENTAGE; - // Correct if beginFade is zero or negative - beginFade = beginFade > 0 ? beginFade : beginFade + TRANSITION_DENOMINATOR; - // Wait to start transition until precipitation begins/ends - float startPercentage = 1 - ((TRANSITION_DENOMINATOR - beginFade) * (1.0f / TRANSITION_DENOMINATOR)); - - if (fadeIn) { - float currentPercentage = (skyCurrentWeatherPct - startPercentage) / (1 - startPercentage); - weatherTransitionPercentage = std::clamp(currentPercentage, 0.0f, 1.0f); - } else { - float currentPercentage = (startPercentage - skyCurrentWeatherPct) / (startPercentage); - weatherTransitionPercentage = 1 - std::clamp(currentPercentage, 0.0f, 1.0f); - } - return weatherTransitionPercentage; -} +public: + struct SETTING_VALUE + { + RE::SETTING_VALUE value; + float pad0; + }; -void WetnessEffects::CalculateWetness(RE::TESWeather* weather, RE::Sky* sky, float seconds, float& weatherWetnessDepth, float& weatherPuddleDepth) -{ - float wetnessDepthDelta = CLEAR_DAY_DELTA_PER_SECOND * WETNESS_SCALE * seconds; - float puddleDepthDelta = CLEAR_DAY_DELTA_PER_SECOND * PUDDLE_SCALE * seconds; - if (weather && sky) { - // Figure out the weather type and set the wetness - if (weather->precipitationData && weather->data.flags.any(RE::TESWeather::WeatherDataFlag::kRainy)) { - // Raining - wetnessDepthDelta = RAIN_DELTA_PER_SECOND * WETNESS_SCALE * seconds; - puddleDepthDelta = RAIN_DELTA_PER_SECOND * PUDDLE_SCALE * seconds; - } else if (weather->precipitationData && weather->data.flags.any(RE::TESWeather::WeatherDataFlag::kSnow)) { - wetnessDepthDelta = SNOWY_DAY_DELTA_PER_SECOND * WETNESS_SCALE * seconds; - puddleDepthDelta = SNOWY_DAY_DELTA_PER_SECOND * PUDDLE_SCALE * seconds; - } else if (weather->data.flags.any(RE::TESWeather::WeatherDataFlag::kCloudy)) { - wetnessDepthDelta = CLOUDY_DAY_DELTA_PER_SECOND * WETNESS_SCALE * seconds; - puddleDepthDelta = CLOUDY_DAY_DELTA_PER_SECOND * PUDDLE_SCALE * seconds; - } - } - - weatherWetnessDepth = wetnessDepthDelta > 0 ? std::min(weatherWetnessDepth + wetnessDepthDelta, MAX_WETNESS_DEPTH) : std::max(weatherWetnessDepth + wetnessDepthDelta, 0.0f); - weatherPuddleDepth = puddleDepthDelta > 0 ? std::min(weatherPuddleDepth + puddleDepthDelta, MAX_PUDDLE_DEPTH) : std::max(weatherPuddleDepth + puddleDepthDelta, 0.0f); -} + RE::BSTArray data; + RE::TESTexture particleTexture; +}; WetnessEffects::PerFrame WetnessEffects::GetCommonBufferData() { PerFrame data{}; - data.Wetness = DRY_WETNESS; - data.PuddleWetness = DRY_WETNESS; - currentWeatherID = 0; - uint32_t previousLastWeatherID = lastWeatherID; - lastWeatherID = 0; - float currentWeatherRaining = 0.0f; - float lastWeatherRaining = 0.0f; - float weatherTransitionPercentage = previousWeatherTransitionPercentage; + + data.Raining = 0.0f; + data.Wetness = 0.0f; + data.PuddleWetness = 0.0f; if (settings.EnableWetnessEffects) { if (auto sky = RE::Sky::GetSingleton()) { if (sky->mode.get() == RE::Sky::Mode::kFull) { - if (auto currentWeather = sky->currentWeather) { - if (currentWeather->precipitationData && currentWeather->data.flags.any(RE::TESWeather::WeatherDataFlag::kRainy)) { - float rainDensity = currentWeather->precipitationData->GetSettingValue(RE::BGSShaderParticleGeometryData::DataID::kParticleDensity).f; - float rainGravity = currentWeather->precipitationData->GetSettingValue(RE::BGSShaderParticleGeometryData::DataID::kGravityVelocity).f; - currentWeatherRaining = std::clamp(((rainDensity * rainGravity) / AVERAGE_RAIN_VOLUME), MIN_RAINDROP_CHANCE_MULTIPLIER, MAX_RAINDROP_CHANCE_MULTIPLIER); - } - currentWeatherID = currentWeather->GetFormID(); - if (auto calendar = RE::Calendar::GetSingleton()) { - float currentWeatherWetnessDepth = wetnessDepth; - float currentWeatherPuddleDepth = puddleDepth; - float currentGameTime = calendar->GetCurrentGameTime() * SECONDS_IN_A_DAY; - lastGameTimeValue = lastGameTimeValue == 0 ? currentGameTime : lastGameTimeValue; - float seconds = currentGameTime - lastGameTimeValue; - lastGameTimeValue = currentGameTime; - - if (seconds >= MAX_TIME_DELTA || seconds < 0) { - // If too much time has passed, snap wetness depths to the current weather. - seconds = 0.0f; - currentWeatherWetnessDepth = 0.0f; - currentWeatherPuddleDepth = 0.0f; - weatherTransitionPercentage = DEFAULT_TRANSITION_PERCENTAGE; - CalculateWetness(currentWeather, sky, 1.0f, currentWeatherWetnessDepth, currentWeatherPuddleDepth); - wetnessDepth = currentWeatherWetnessDepth > 0 ? MAX_WETNESS_DEPTH : 0.0f; - puddleDepth = currentWeatherPuddleDepth > 0 ? MAX_PUDDLE_DEPTH : 0.0f; + if (auto precip = sky->precip) { + float currentRaining = 0.0f; + float lastRaining = 0.0f; + + { + auto precipObject = precip->currentPrecip; + if (!precipObject) { + precipObject = precip->lastPrecip; + } + if (precipObject) { + auto& effect = precipObject->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kEffect]; + auto shaderProp = netimmerse_cast(effect.get()); + auto particleShaderProperty = netimmerse_cast(shaderProp); + auto rain = (RE::BSParticleShaderRainEmitter*)(particleShaderProperty->particleEmitter); + data.OcclusionViewProj = rain->occlusionProjection; } + } - if (seconds > 0) { - weatherTransitionPercentage = DEFAULT_TRANSITION_PERCENTAGE; - float lastWeatherWetnessDepth = wetnessDepth; - float lastWeatherPuddleDepth = puddleDepth; - seconds *= std::clamp(settings.WeatherTransitionSpeed, MIN_WEATHER_TRANSITION_SPEED, MAX_WEATHER_TRANSITION_SPEED); - CalculateWetness(currentWeather, sky, seconds, currentWeatherWetnessDepth, currentWeatherPuddleDepth); - // If there is a lastWeather, figure out what type it is and set the wetness - if (auto lastWeather = sky->lastWeather) { - lastWeatherID = lastWeather->GetFormID(); - CalculateWetness(lastWeather, sky, seconds, lastWeatherWetnessDepth, lastWeatherPuddleDepth); - // If it was raining, wait to transition until precipitation ends, otherwise use the current weather's fade in - if (lastWeather->precipitationData && lastWeather->data.flags.any(RE::TESWeather::WeatherDataFlag::kRainy)) { - float rainDensity = lastWeather->precipitationData->GetSettingValue(RE::BGSShaderParticleGeometryData::DataID::kParticleDensity).f; - float rainGravity = lastWeather->precipitationData->GetSettingValue(RE::BGSShaderParticleGeometryData::DataID::kGravityVelocity).f; - lastWeatherRaining = std::clamp(((rainDensity * rainGravity) / AVERAGE_RAIN_VOLUME), MIN_RAINDROP_CHANCE_MULTIPLIER, MAX_RAINDROP_CHANCE_MULTIPLIER); - weatherTransitionPercentage = CalculateWeatherTransitionPercentage(sky->currentWeatherPct, lastWeather->data.precipitationEndFadeOut, false); - } else { - weatherTransitionPercentage = CalculateWeatherTransitionPercentage(sky->currentWeatherPct, currentWeather->data.precipitationBeginFadeIn, true); - } + if (precip->currentPrecip && sky->currentWeather && sky->currentWeather->precipitationData) { + auto& precipObject = precip->currentPrecip; + auto weather = sky->currentWeather; + + auto& effect = precipObject->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kEffect]; + auto shaderProp = netimmerse_cast(effect.get()); + auto particleShaderProperty = netimmerse_cast(shaderProp); + + auto rain = (RE::BSParticleShaderRainEmitter*)(particleShaderProperty->particleEmitter); + if (rain->emitterType.any(RE::BSParticleShaderEmitter::EMITTER_TYPE::kRain)) { + if (REL::Module::IsVR()) { + auto precipitionData = (BGSShaderParticleGeometryDataVR*)weather->precipitationData; + auto maxDensity = precipitionData->data[(uint)RE::BGSShaderParticleGeometryData::DataID::kParticleDensity].value.f; + if (maxDensity > 0.0f) + currentRaining = rain->density / maxDensity; + } else { + auto maxDensity = weather->precipitationData->data[(uint)RE::BGSShaderParticleGeometryData::DataID::kParticleDensity].f; + if (maxDensity > 0.0f) + currentRaining = rain->density / maxDensity; } - - // Transition between CurrentWeather and LastWeather depth values - wetnessDepth = std::lerp(lastWeatherWetnessDepth, currentWeatherWetnessDepth, weatherTransitionPercentage); - puddleDepth = std::lerp(lastWeatherPuddleDepth, currentWeatherPuddleDepth, weatherTransitionPercentage); - } else { - lastWeatherID = previousLastWeatherID; } + } - // Calculate the wetness value from the water depth - data.Wetness = std::min(wetnessDepth, MAX_WETNESS); - data.PuddleWetness = std::min(puddleDepth, MAX_PUDDLE_WETNESS); - data.Raining = std::lerp(lastWeatherRaining, currentWeatherRaining, weatherTransitionPercentage); - previousWeatherTransitionPercentage = weatherTransitionPercentage; + if (precip->lastPrecip && sky->lastWeather && sky->lastWeather->precipitationData) { + auto& precipObject = precip->lastPrecip; + auto weather = sky->lastWeather; + + auto& effect = precipObject->GetGeometryRuntimeData().properties[RE::BSGeometry::States::kEffect]; + auto shaderProp = netimmerse_cast(effect.get()); + auto particleShaderProperty = netimmerse_cast(shaderProp); + auto rain = (RE::BSParticleShaderRainEmitter*)(particleShaderProperty->particleEmitter); + if (rain->emitterType.any(RE::BSParticleShaderEmitter::EMITTER_TYPE::kRain)) { + if (REL::Module::IsVR()) { + auto precipitionData = (BGSShaderParticleGeometryDataVR*)weather->precipitationData; + auto maxDensity = precipitionData->data[(uint)RE::BGSShaderParticleGeometryData::DataID::kParticleDensity].value.f; + if (maxDensity > 0.0f) + lastRaining = rain->density / maxDensity; + } else { + auto maxDensity = weather->precipitationData->data[(uint)RE::BGSShaderParticleGeometryData::DataID::kParticleDensity].f; + if (maxDensity > 0.0f) + lastRaining = rain->density / maxDensity; + } + } } + + data.Raining = std::min(1.0f, currentRaining + lastRaining); + } + + auto linearstep = [](float edge0, float edge1, float x) { + return std::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f); + }; + + float wetnessCurrentWeather = 0.0f; + float puddleCurrentWeather = 0.0f; + + if (sky->currentWeather && sky->currentWeather->precipitationData && sky->currentWeather->data.flags.any(RE::TESWeather::WeatherDataFlag::kRainy)) { + wetnessCurrentWeather = linearstep(255.0f + (float)sky->currentWeather->data.precipitationBeginFadeIn, 255, sky->currentWeatherPct * 255); + puddleCurrentWeather = pow(wetnessCurrentWeather, 2.0f); } + + float wetnessLastWeather = 0.0f; + float puddleLastWeather = 0.0f; + + if (sky->lastWeather && sky->lastWeather->precipitationData && sky->lastWeather->data.flags.any(RE::TESWeather::WeatherDataFlag::kRainy)) { + wetnessLastWeather = 1.0f - linearstep((float)sky->lastWeather->data.precipitationEndFadeOut, 255, sky->currentWeatherPct * 255); + puddleLastWeather = pow(std::max(wetnessLastWeather, 1.0f - sky->currentWeatherPct), 0.25f); + } + + float wetness = std::min(1.0f, wetnessCurrentWeather + wetnessLastWeather); + float puddleWetness = std::min(1.0f, puddleCurrentWeather + puddleLastWeather); + + data.Wetness = wetness; + data.PuddleWetness = puddleWetness; } } } - static size_t rainTimer = 0; // size_t for precision - if (!RE::UI::GetSingleton()->GameIsPaused()) // from lightlimitfix + static size_t rainTimer = 0; // size_t for precision + if (!RE::UI::GetSingleton()->GameIsPaused()) rainTimer += (size_t)(RE::GetSecondsSinceLastFrame() * 1000); // BSTimer::delta is always 0 for some reason data.Time = rainTimer / 1000.f; data.settings = settings; // Disable Shore Wetness if Wetness Effects are Disabled data.settings.MaxShoreWetness = settings.EnableWetnessEffects ? settings.MaxShoreWetness : 0.0f; - // calculating some parameters on cpu - data.settings.RaindropChance *= data.Raining; - data.settings.RaindropGridSize = 1.f / settings.RaindropGridSize; - data.settings.RaindropInterval = 1.f / settings.RaindropInterval; + + // Calculating some parameters on cpu + data.settings.RaindropChance *= data.Raining * data.Raining; + data.settings.RaindropGridSize = 1.0f / settings.RaindropGridSize; + data.settings.RaindropInterval = 1.0f / settings.RaindropInterval; data.settings.RippleLifetime = settings.RaindropInterval / settings.RippleLifetime; - data.settings.ChaoticRippleStrength *= std::clamp(data.Raining, 0.f, 1.f); - data.settings.ChaoticRippleScale = 1.f / settings.ChaoticRippleScale; return data; } -void WetnessEffects::Reset() +void WetnessEffects::Prepass() { - requiresUpdate = true; + static auto renderer = RE::BSGraphics::Renderer::GetSingleton(); + static auto& precipOcclusionTexture = renderer->GetDepthStencilData().depthStencils[RE::RENDER_TARGETS_DEPTHSTENCIL::kPRECIPITATION_OCCLUSION_MAP]; + + auto state = State::GetSingleton(); + auto& context = state->context; + + context->PSSetShaderResources(31, 1, &precipOcclusionTexture.depthSRV); } void WetnessEffects::LoadSettings(json& o_json) diff --git a/src/Features/WetnessEffects.h b/src/Features/WetnessEffects.h index 51eccc0a8..34a5b2572 100644 --- a/src/Features/WetnessEffects.h +++ b/src/Features/WetnessEffects.h @@ -23,7 +23,7 @@ struct WetnessEffects : Feature { uint EnableWetnessEffects = true; float MaxRainWetness = 1.0f; - float MaxPuddleWetness = 2.667f; + float MaxPuddleWetness = 2.5f; float MaxShoreWetness = 0.5f; uint ShoreRange = 32; float PuddleRadius = 1.0f; @@ -37,8 +37,6 @@ struct WetnessEffects : Feature uint EnableRaindropFx = true; uint EnableSplashes = true; uint EnableRipples = true; - uint EnableChaoticRipples = true; - float RaindropFxRange = 1000.f; float RaindropGridSize = 4.f; float RaindropInterval = .5f; float RaindropChance = .3f; @@ -50,34 +48,24 @@ struct WetnessEffects : Feature float RippleRadius = 1.f; float RippleBreadth = .5f; float RippleLifetime = .15f; - float ChaoticRippleStrength = .1f; - float ChaoticRippleScale = 1.f; - float ChaoticRippleSpeed = 20.f; }; struct alignas(16) PerFrame { + REX::W32::XMFLOAT4X4 OcclusionViewProj; float Time; float Raining; float Wetness; float PuddleWetness; Settings settings; - uint pad0[2]; + uint pad0[3]; }; Settings settings; PerFrame GetCommonBufferData(); - bool requiresUpdate = true; - float wetnessDepth = 0.0f; - float puddleDepth = 0.0f; - float lastGameTimeValue = 0.0f; - uint32_t currentWeatherID = 0; - uint32_t lastWeatherID = 0; - float previousWeatherTransitionPercentage = 0.0f; - - virtual void Reset() override; + virtual void Prepass() override; virtual void DrawSettings() override; @@ -85,8 +73,6 @@ struct WetnessEffects : Feature virtual void SaveSettings(json& o_json) override; virtual void RestoreDefaultSettings() override; - float CalculateWeatherTransitionPercentage(float skyCurrentWeatherPct, float beginFade, bool fadeIn); - void CalculateWetness(RE::TESWeather* weather, RE::Sky* sky, float seconds, float& wetness, float& puddleWetness); virtual bool SupportsVR() override { return true; }; };