From 54f0ee693ff9668a5a79a245a31bcb8d10099e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Sat, 21 Oct 2023 15:47:41 +0200 Subject: [PATCH] Rain (#766) --- .../ScriptingAPI-Documentation.md | 22 +- Editor/WeatherWindow.cpp | 65 +++++- Editor/WeatherWindow.h | 5 + .../shaders/ShaderInterop_EmittedParticle.h | 1 + WickedEngine/shaders/ShaderInterop_Renderer.h | 8 + WickedEngine/shaders/ShaderInterop_Weather.h | 10 + .../shaders/emittedparticlePS_soft.hlsl | 16 +- .../shaders/emittedparticle_emitCS.hlsl | 8 + .../shaders/emittedparticle_simulateCS.hlsl | 27 +++ WickedEngine/shaders/objectHF.hlsli | 6 +- .../shaders/objectHF_tessellation.hlsli | 4 +- WickedEngine/shaders/shadowHF.hlsli | 50 +++++ WickedEngine/wiEmittedParticle.cpp | 4 + WickedEngine/wiEmittedParticle.h | 1 + WickedEngine/wiEnums.h | 1 + WickedEngine/wiGraphics.h | 28 +-- WickedEngine/wiRenderer.cpp | 198 ++++++++++++++---- WickedEngine/wiScene.cpp | 148 ++++++++++++- WickedEngine/wiScene.h | 9 +- WickedEngine/wiScene_BindLua.cpp | 5 + WickedEngine/wiScene_BindLua.h | 15 ++ WickedEngine/wiScene_Components.h | 16 +- WickedEngine/wiScene_Serializers.cpp | 18 ++ WickedEngine/wiTerrain.cpp | 2 +- WickedEngine/wiVersion.cpp | 2 +- 25 files changed, 591 insertions(+), 78 deletions(-) diff --git a/Content/Documentation/ScriptingAPI-Documentation.md b/Content/Documentation/ScriptingAPI-Documentation.md index 28b8547de..cc41a821d 100644 --- a/Content/Documentation/ScriptingAPI-Documentation.md +++ b/Content/Documentation/ScriptingAPI-Documentation.md @@ -1093,7 +1093,27 @@ Describes a Weather - VolumetricCloudParameters : VolumetricCloudParameters -- Returns a table to modify volumetric cloud parameters - SkyMapName : string -- Resource name for sky texture - ColorGradingMapName : string -- Resource name for color grading map -- Gravity : Vector +- sunColor : Vector +- sunDirection : Vector +- skyExposure : float +- horizon : Vector +- zenith : Vector +- ambient : Vector +- fogStart : float +- fog Density : float +- fogHeightStart : float +- fogHeightEnd : float +- windDirection : Vector +- windRandomness : float +- windWaveSize : float +- windSpeed : float +- stars : float +- rainAmount : float +- rainLenght : float +- rainSpeed : float +- rainScale : float +- rainColor : Vector +- gravity : Vector
diff --git a/Editor/WeatherWindow.cpp b/Editor/WeatherWindow.cpp index eade34d00..4aee580d9 100644 --- a/Editor/WeatherWindow.cpp +++ b/Editor/WeatherWindow.cpp @@ -9,7 +9,7 @@ void WeatherWindow::Create(EditorComponent* _editor) { editor = _editor; wi::gui::Window::Create(ICON_WEATHER " Weather", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); - SetSize(XMFLOAT2(660, 2000)); + SetSize(XMFLOAT2(660, 2140)); closeButton.SetTooltip("Delete WeatherComponent"); OnClose([=](wi::gui::EventArgs args) { @@ -61,7 +61,9 @@ void WeatherWindow::Create(EditorComponent* _editor) colorComboBox.AddItem("Cloud color 2"); colorComboBox.AddItem("Cloud extinction 1"); colorComboBox.AddItem("Cloud extinction 2"); + colorComboBox.AddItem("Rain color"); colorComboBox.SetTooltip("Choose the destination data of the color picker."); + colorComboBox.SetMaxVisibleItemCount(100); AddWidget(&colorComboBox); colorPicker.Create("Color", wi::gui::Window::WindowControls::NONE); @@ -97,6 +99,9 @@ void WeatherWindow::Create(EditorComponent* _editor) case 7: weather.volumetricCloudParameters.layerSecond.extinctionCoefficient = args.color.toFloat3(); break; + case 8: + weather.rain_color = args.color.toFloat4(); + break; } }); AddWidget(&colorPicker); @@ -233,6 +238,51 @@ void WeatherWindow::Create(EditorComponent* _editor) }); AddWidget(&skyRotationSlider); + rainAmountSlider.Create(0, 1, 0, 10000, "Rain Amount: "); + rainAmountSlider.SetTooltip("Set the amount of rain effect. 0 = disabled, 1 = heavy rain"); + rainAmountSlider.SetSize(XMFLOAT2(wid, hei)); + rainAmountSlider.SetPos(XMFLOAT2(x, y += step)); + rainAmountSlider.OnSlide([&](wi::gui::EventArgs args) { + GetWeather().rain_amount = args.fValue; + }); + AddWidget(&rainAmountSlider); + + rainLengthSlider.Create(0, 0.1f, 0, 10000, "Rain Length: "); + rainLengthSlider.SetTooltip("The elongation of rain particles in the direction of their motion."); + rainLengthSlider.SetSize(XMFLOAT2(wid, hei)); + rainLengthSlider.SetPos(XMFLOAT2(x, y += step)); + rainLengthSlider.OnSlide([&](wi::gui::EventArgs args) { + GetWeather().rain_length = args.fValue; + }); + AddWidget(&rainLengthSlider); + + rainSpeedSlider.Create(0, 2, 0, 10000, "Rain Speed: "); + rainSpeedSlider.SetTooltip("The downward speed of rain particles. The final speed will be modulated by the wind direction and speed as well."); + rainSpeedSlider.SetSize(XMFLOAT2(wid, hei)); + rainSpeedSlider.SetPos(XMFLOAT2(x, y += step)); + rainSpeedSlider.OnSlide([&](wi::gui::EventArgs args) { + GetWeather().rain_speed = args.fValue; + }); + AddWidget(&rainSpeedSlider); + + rainScaleSlider.Create(0.005f, 0.1f, 0, 10000, "Rain Scale: "); + rainScaleSlider.SetTooltip("The overall size of rain particles."); + rainScaleSlider.SetSize(XMFLOAT2(wid, hei)); + rainScaleSlider.SetPos(XMFLOAT2(x, y += step)); + rainScaleSlider.OnSlide([&](wi::gui::EventArgs args) { + GetWeather().rain_scale = args.fValue; + }); + AddWidget(&rainScaleSlider); + + rainSplashScaleSlider.Create(0, 1, 0, 10000, "Rain Splash Scale: "); + rainSplashScaleSlider.SetTooltip("The size of rain particles when they hit the ground."); + rainSplashScaleSlider.SetSize(XMFLOAT2(wid, hei)); + rainSplashScaleSlider.SetPos(XMFLOAT2(x, y += step)); + rainSplashScaleSlider.OnSlide([&](wi::gui::EventArgs args) { + GetWeather().rain_splash_scale = args.fValue; + }); + AddWidget(&rainSplashScaleSlider); + realisticskyCheckBox.Create("Realistic sky: "); realisticskyCheckBox.SetTooltip("Physically based sky rendering model.\nNote that realistic sky requires a sun (directional light) to be visible."); realisticskyCheckBox.SetSize(XMFLOAT2(hei, hei)); @@ -1020,6 +1070,11 @@ void WeatherWindow::Update() skyExposureSlider.SetValue(weather.skyExposure); starsSlider.SetValue(weather.stars); skyRotationSlider.SetValue(wi::math::RadiansToDegrees(weather.sky_rotation)); + rainAmountSlider.SetValue(weather.rain_amount); + rainLengthSlider.SetValue(weather.rain_length); + rainSpeedSlider.SetValue(weather.rain_speed); + rainScaleSlider.SetValue(weather.rain_scale); + rainSplashScaleSlider.SetValue(weather.rain_splash_scale); windMagnitudeSlider.SetValue(XMVectorGetX(XMVector3Length(XMLoadFloat3(&weather.windDirection)))); switch (colorComboBox.GetSelected()) @@ -1049,6 +1104,9 @@ void WeatherWindow::Update() case 7: colorPicker.SetPickColor(wi::Color::fromFloat3(weather.volumetricCloudParameters.layerSecond.extinctionCoefficient)); break; + case 8: + colorPicker.SetPickColor(wi::Color::fromFloat4(weather.rain_color)); + break; } realisticskyCheckBox.SetCheck(weather.IsRealisticSky()); @@ -1257,6 +1315,11 @@ void WeatherWindow::ResizeLayout() add(skyExposureSlider); add(starsSlider); add(skyRotationSlider); + add(rainAmountSlider); + add(rainLengthSlider); + add(rainSpeedSlider); + add(rainScaleSlider); + add(rainSplashScaleSlider); y += jump; diff --git a/Editor/WeatherWindow.h b/Editor/WeatherWindow.h index 50b8835f3..a5b6b3952 100644 --- a/Editor/WeatherWindow.h +++ b/Editor/WeatherWindow.h @@ -35,6 +35,11 @@ public: wi::gui::Slider skyExposureSlider; wi::gui::Slider starsSlider; wi::gui::Slider skyRotationSlider; + wi::gui::Slider rainAmountSlider; + wi::gui::Slider rainLengthSlider; + wi::gui::Slider rainSpeedSlider; + wi::gui::Slider rainScaleSlider; + wi::gui::Slider rainSplashScaleSlider; wi::gui::CheckBox realisticskyCheckBox; wi::gui::CheckBox aerialperspectiveCheckBox; wi::gui::CheckBox realisticskyHighQualityCheckBox; diff --git a/WickedEngine/shaders/ShaderInterop_EmittedParticle.h b/WickedEngine/shaders/ShaderInterop_EmittedParticle.h index 07db5cfb6..a3169e20f 100644 --- a/WickedEngine/shaders/ShaderInterop_EmittedParticle.h +++ b/WickedEngine/shaders/ShaderInterop_EmittedParticle.h @@ -37,6 +37,7 @@ static const uint EMITTER_OPTION_BIT_FRAME_BLENDING_ENABLED = 1 << 0; static const uint EMITTER_OPTION_BIT_SPH_ENABLED = 1 << 1; static const uint EMITTER_OPTION_BIT_MESH_SHADER_ENABLED = 1 << 2; static const uint EMITTER_OPTION_BIT_COLLIDERS_DISABLED = 1 << 3; +static const uint EMITTER_OPTION_BIT_USE_RAIN_BLOCKER = 1 << 4; CBUFFER(EmittedParticleCB, CBSLOT_OTHER_EMITTEDPARTICLE) { diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index 5d343f80a..d8bf7ea41 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -942,6 +942,14 @@ struct FrameCB int buffer_entity_index; float gi_boost; + float4 rain_blocker_mad; + float4x4 rain_blocker_matrix; + float4x4 rain_blocker_matrix_inverse; + + float4 rain_blocker_mad_prev; + float4x4 rain_blocker_matrix_prev; + float4x4 rain_blocker_matrix_inverse_prev; + ShaderScene scene; VXGI vxgi; diff --git a/WickedEngine/shaders/ShaderInterop_Weather.h b/WickedEngine/shaders/ShaderInterop_Weather.h index 68b5cbfda..080e1bef9 100644 --- a/WickedEngine/shaders/ShaderInterop_Weather.h +++ b/WickedEngine/shaders/ShaderInterop_Weather.h @@ -366,6 +366,16 @@ struct ShaderWeather float4x4 stars_rotation; + float rain_amount; + float rain_length; + float rain_speed; + float rain_scale; + + float3 padding_rain; + float rain_splash_scale; + + float4 rain_color; + ShaderFog fog; ShaderWind wind; ShaderOcean ocean; diff --git a/WickedEngine/shaders/emittedparticlePS_soft.hlsl b/WickedEngine/shaders/emittedparticlePS_soft.hlsl index 695eb0ec8..c2925c314 100644 --- a/WickedEngine/shaders/emittedparticlePS_soft.hlsl +++ b/WickedEngine/shaders/emittedparticlePS_soft.hlsl @@ -13,6 +13,13 @@ static const uint SLOT = BASECOLORMAP; [earlydepthstencil] float4 main(VertextoPixel input) : SV_TARGET { + // Blocker shadow map check: + [branch] + if ((xEmitterOptions & EMITTER_OPTION_BIT_USE_RAIN_BLOCKER) && rain_blocker_check(input.P)) + { + return 0; + } + ShaderMaterial material = EmitterGetMaterial(); float4 color = 1; @@ -64,13 +71,16 @@ float4 main(VertextoPixel input) : SV_TARGET [branch] if (color.a > 0) { - float3 N; N.x = -cos(PI * input.unrotated_uv.x); N.y = cos(PI * input.unrotated_uv.y); N.z = -sin(PI * length(input.unrotated_uv)); N = mul((float3x3)GetCamera().inverse_view, N); N = normalize(N); + + float3 V = GetCamera().position - input.P; + float dist = length(V); + V /= dist; Lighting lighting; lighting.create(0, 0, GetAmbient(N), 0); @@ -80,7 +90,7 @@ float4 main(VertextoPixel input) : SV_TARGET surface.create(material, color, surfacemap_simple); surface.P = input.P; surface.N = N; - surface.V = 0; + surface.V = V; surface.pixel = pixel; surface.sss = material.subsurfaceScattering; surface.sss_inv = material.subsurfaceScattering_inv; @@ -93,6 +103,8 @@ float4 main(VertextoPixel input) : SV_TARGET //color.rgb = float3(unrotated_uv, 0); //color.rgb = float3(input.tex, 0); + ApplyFog(dist, V, color); + color = max(0, color); } diff --git a/WickedEngine/shaders/emittedparticle_emitCS.hlsl b/WickedEngine/shaders/emittedparticle_emitCS.hlsl index 63c459bc1..28d397a16 100644 --- a/WickedEngine/shaders/emittedparticle_emitCS.hlsl +++ b/WickedEngine/shaders/emittedparticle_emitCS.hlsl @@ -1,6 +1,7 @@ #include "globals.hlsli" #include "emittedparticleHF.hlsli" #include "ShaderInterop_EmittedParticle.h" +#include "shadowHF.hlsli" RWStructuredBuffer particleBuffer : register(u0); RWStructuredBuffer aliveBuffer_CURRENT : register(u1); @@ -77,6 +78,13 @@ void main(uint3 DTid : SV_DispatchThreadID) #endif // EMIT_FROM_MESH float3 pos = mul(worldMatrix, float4(emitPos, 1)).xyz; + + // Blocker shadow map check using previous frame: + [branch] + if ((xEmitterOptions & EMITTER_OPTION_BIT_USE_RAIN_BLOCKER) && rain_blocker_check_prev(pos)) + { + return; + } float particleStartingSize = xParticleSize + xParticleSize * (rng.next_float() - 0.5f) * xParticleRandomFactor; diff --git a/WickedEngine/shaders/emittedparticle_simulateCS.hlsl b/WickedEngine/shaders/emittedparticle_simulateCS.hlsl index f4b60192b..001bcd2b6 100644 --- a/WickedEngine/shaders/emittedparticle_simulateCS.hlsl +++ b/WickedEngine/shaders/emittedparticle_simulateCS.hlsl @@ -1,6 +1,7 @@ #include "globals.hlsli" #include "emittedparticleHF.hlsli" #include "ShaderInterop_EmittedParticle.h" +#include "shadowHF.hlsli" static const float3 BILLBOARD[] = { float3(-1, -1, 0), // 0 @@ -53,6 +54,32 @@ void main(uint3 DTid : SV_DispatchThreadID, uint Gid : SV_GroupIndex) // drag: particle.velocity *= xParticleDrag; + + // Blocker shadow map check using previous frame: + // This is extended with blocker position calculation for splashing + [branch] + if ((xEmitterOptions & EMITTER_OPTION_BIT_USE_RAIN_BLOCKER) && GetFrame().texture_shadowatlas_index >= 0 && any(GetFrame().rain_blocker_mad_prev)) + { + Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; + float3 shadow_pos = mul(GetFrame().rain_blocker_matrix_prev, float4(particle.position, 1)).xyz; + float3 shadow_uv = clipspace_to_uv(shadow_pos); + if (is_saturated(shadow_uv)) + { + shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad_prev.xy, GetFrame().rain_blocker_mad_prev.zw); + float shadow = texture_shadowatlas.SampleLevel(sampler_point_clamp, shadow_uv.xy, 0).r; + + if(shadow > shadow_pos.z) + { + // Under blocker, make a splash by placing above blocker and modulating some params: + float3 blockerPos = reconstruct_position(clipspace_to_uv(shadow_pos.xy), shadow, GetFrame().rain_blocker_matrix_inverse_prev); + particle.velocity = 0; + float splashSize = GetWeather().rain_splash_scale; + particle.position = blockerPos + float3(0, splashSize * 0.5, 0); + particle.sizeBeginEnd = splashSize; + particle.life = 0.15; + } + } + } if (particle.life > 0) { diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index 7a8dce2bd..7a912966f 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -203,12 +203,16 @@ struct VertexSurface { color *= input.GetVertexColor(); } - + normal = mul((min16float3x3)input.GetInstance().transformInverseTranspose.GetMatrix(), normal); tangent = input.GetTangent(); tangent.xyz = mul((min16float3x3)input.GetInstance().transformInverseTranspose.GetMatrix(), tangent.xyz); + // Note: normalization must happen when normal is exported as half precision for interpolator! + normal = any(normal) ? normalize(normal) : 0; + tangent = any(tangent) ? normalize(tangent) : 0; + uvsets = input.GetUVSets(); atlas = input.GetAtlasUV(); diff --git a/WickedEngine/shaders/objectHF_tessellation.hlsli b/WickedEngine/shaders/objectHF_tessellation.hlsli index 337360d27..c45dbe525 100644 --- a/WickedEngine/shaders/objectHF_tessellation.hlsli +++ b/WickedEngine/shaders/objectHF_tessellation.hlsli @@ -131,11 +131,11 @@ PixelInput main(ConstantOutput input, float3 uvw : SV_DomainLocation, const Outp #endif // OBJECTSHADER_USE_ATLAS #ifdef OBJECTSHADER_USE_NORMAL - output.nor = min16float3(w * patch[0].nor + u * patch[1].nor + v * patch[2].nor); + output.nor = min16float3(normalize(w * patch[0].nor + u * patch[1].nor + v * patch[2].nor)); #endif // OBJECTSHADER_USE_NORMAL #ifdef OBJECTSHADER_USE_TANGENT - output.tan = min16float4(w * patch[0].tan + u * patch[1].tan + v * patch[2].tan); + output.tan = min16float4(normalize(w * patch[0].tan + u * patch[1].tan + v * patch[2].tan)); #endif // OBJECTSHADER_USE_TANGENT #ifdef OBJECTSHADER_USE_POSITION3D diff --git a/WickedEngine/shaders/shadowHF.hlsli b/WickedEngine/shaders/shadowHF.hlsli index 40b9b42a1..1a1038713 100644 --- a/WickedEngine/shaders/shadowHF.hlsli +++ b/WickedEngine/shaders/shadowHF.hlsli @@ -121,4 +121,54 @@ inline bool furthest_cascade_volumetrics(inout ShaderEntity light, inout uint fu return false; } +// Checks whether position is below or above rain blocker +// true: below +// false: above +inline bool rain_blocker_check(in float3 P) +{ + [branch] + if (GetFrame().texture_shadowatlas_index < 0 || !any(GetFrame().rain_blocker_mad)) + return false; + + Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; + float3 shadow_pos = mul(GetFrame().rain_blocker_matrix, float4(P, 1)).xyz; + float3 shadow_uv = clipspace_to_uv(shadow_pos); + if (is_saturated(shadow_uv)) + { + shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad.xy, GetFrame().rain_blocker_mad.zw); + float shadow = texture_shadowatlas.SampleLevel(sampler_point_clamp, shadow_uv.xy, 0).r; + + if(shadow > shadow_pos.z) + { + return true; + } + + } + return false; +} + +// Same as above but using previous frame's values +inline bool rain_blocker_check_prev(in float3 P) +{ + [branch] + if (GetFrame().texture_shadowatlas_index < 0 || !any(GetFrame().rain_blocker_mad_prev)) + return false; + + Texture2D texture_shadowatlas = bindless_textures[GetFrame().texture_shadowatlas_index]; + float3 shadow_pos = mul(GetFrame().rain_blocker_matrix_prev, float4(P, 1)).xyz; + float3 shadow_uv = clipspace_to_uv(shadow_pos); + if (is_saturated(shadow_uv)) + { + shadow_uv.xy = mad(shadow_uv.xy, GetFrame().rain_blocker_mad_prev.xy, GetFrame().rain_blocker_mad_prev.zw); + float shadow = texture_shadowatlas.SampleLevel(sampler_point_clamp, shadow_uv.xy, 0).r; + + if(shadow > shadow_pos.z) + { + return true; + } + + } + return false; +} + #endif // WI_SHADOW_HF diff --git a/WickedEngine/wiEmittedParticle.cpp b/WickedEngine/wiEmittedParticle.cpp index 3102a9174..54ec9f768 100644 --- a/WickedEngine/wiEmittedParticle.cpp +++ b/WickedEngine/wiEmittedParticle.cpp @@ -409,6 +409,10 @@ namespace wi { cb.xEmitterOptions |= EMITTER_OPTION_BIT_COLLIDERS_DISABLED; } + if (_flags & FLAG_USE_RAIN_BLOCKER) + { + cb.xEmitterOptions |= EMITTER_OPTION_BIT_USE_RAIN_BLOCKER; + } // SPH: cb.xSPH_h = SPH_h; diff --git a/WickedEngine/wiEmittedParticle.h b/WickedEngine/wiEmittedParticle.h index b17e8ce7b..0b61b9cdd 100644 --- a/WickedEngine/wiEmittedParticle.h +++ b/WickedEngine/wiEmittedParticle.h @@ -86,6 +86,7 @@ namespace wi FLAG_HAS_VOLUME = 1 << 5, FLAG_FRAME_BLENDING = 1 << 6, FLAG_COLLIDERS_DISABLED = 1 << 7, + FLAG_USE_RAIN_BLOCKER = 1 << 8, }; uint32_t _flags = FLAG_EMPTY; diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index b6c6767ef..a60cefec8 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -49,6 +49,7 @@ namespace wi::enums RENDERPASS_ENVMAPCAPTURE, RENDERPASS_SHADOW, RENDERPASS_VOXELIZE, + RENDERPASS_RAINBLOCKER, RENDERPASS_COUNT }; diff --git a/WickedEngine/wiGraphics.h b/WickedEngine/wiGraphics.h index cf03e13cb..b46c53d8a 100644 --- a/WickedEngine/wiGraphics.h +++ b/WickedEngine/wiGraphics.h @@ -274,20 +274,20 @@ namespace wi::graphics // Formats that are not usable in render pass must be below because formats in render pass must be encodable as 6 bits: - BC1_UNORM, - BC1_UNORM_SRGB, - BC2_UNORM, - BC2_UNORM_SRGB, - BC3_UNORM, - BC3_UNORM_SRGB, - BC4_UNORM, - BC4_SNORM, - BC5_UNORM, - BC5_SNORM, - BC6H_UF16, - BC6H_SF16, - BC7_UNORM, - BC7_UNORM_SRGB, + BC1_UNORM, // Three color channels (5 bits:6 bits:5 bits), with 0 or 1 bit(s) of alpha + BC1_UNORM_SRGB, // Three color channels (5 bits:6 bits:5 bits), with 0 or 1 bit(s) of alpha + BC2_UNORM, // Three color channels (5 bits:6 bits:5 bits), with 4 bits of alpha + BC2_UNORM_SRGB, // Three color channels (5 bits:6 bits:5 bits), with 4 bits of alpha + BC3_UNORM, // Three color channels (5 bits:6 bits:5 bits) with 8 bits of alpha + BC3_UNORM_SRGB, // Three color channels (5 bits:6 bits:5 bits) with 8 bits of alpha + BC4_UNORM, // One color channel (8 bits) + BC4_SNORM, // One color channel (8 bits) + BC5_UNORM, // Two color channels (8 bits:8 bits) + BC5_SNORM, // Two color channels (8 bits:8 bits) + BC6H_UF16, // Three color channels (16 bits:16 bits:16 bits) in "half" floating point + BC6H_SF16, // Three color channels (16 bits:16 bits:16 bits) in "half" floating point + BC7_UNORM, // Three color channels (4 to 7 bits per channel) with 0 to 8 bits of alpha + BC7_UNORM_SRGB, // Three color channels (4 to 7 bits per channel) with 0 to 8 bits of alpha NV12, // video YUV420; SRV Luminance aspect: R8_UNORM, SRV Chrominance aspect: R8G8_UNORM }; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index c072f149d..6ee98e053 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -425,6 +425,9 @@ SHADERTYPE GetVSTYPE(RENDERPASS renderPass, bool tessellation, bool alphatest, b case RENDERPASS_VOXELIZE: realVS = VSTYPE_VOXELIZER; break; + case RENDERPASS_RAINBLOCKER: + realVS = VSTYPE_SHADOW; + break; } return realVS; @@ -1666,6 +1669,8 @@ void LoadShaders() { for (uint32_t tessellation = 0; tessellation <= 1; ++tessellation) { + if (tessellation && renderPass > RENDERPASS_PREPASS) + continue; for (uint32_t alphatest = 0; alphatest <= 1; ++alphatest) { const bool transparency = blendMode != BLENDMODE_OPAQUE; @@ -1715,6 +1720,9 @@ void LoadShaders() case RENDERPASS_SHADOW: desc.bs = &blendStates[transparency ? BSTYPE_TRANSPARENTSHADOW : BSTYPE_COLORWRITEDISABLE]; break; + case RENDERPASS_RAINBLOCKER: + desc.bs = &blendStates[BSTYPE_COLORWRITEDISABLE]; + break; default: break; } @@ -1740,6 +1748,9 @@ void LoadShaders() case RENDERPASS_VOXELIZE: desc.dss = &depthStencils[DSSTYPE_DEPTHDISABLED]; break; + case RENDERPASS_RAINBLOCKER: + desc.dss = &depthStencils[DSSTYPE_DEFAULT]; + break; default: if (blendMode == BLENDMODE_ADDITIVE) { @@ -1840,6 +1851,15 @@ void LoadShaders() } break; + case RENDERPASS_RAINBLOCKER: + { + RenderPassInfo renderpass_info; + renderpass_info.rt_count = 0; + renderpass_info.ds_format = format_depthbuffer_shadowmap; + device->CreatePipelineState(&desc, GetObjectPSO(variant), &renderpass_info); + } + break; + default: device->CreatePipelineState(&desc, GetObjectPSO(variant)); break; @@ -1956,7 +1976,7 @@ void SetUpStates() rs.front_counter_clockwise = true; rs.depth_bias = -1; rs.depth_bias_clamp = 0; - rs.slope_scaled_depth_bias = -4.0f; + rs.slope_scaled_depth_bias = -2.0f; rs.depth_clip_enable = true; rs.multisample_enable = false; rs.antialiased_line_enable = false; @@ -2441,7 +2461,6 @@ void ClearWorld(Scene& scene) struct SHCAM { XMMATRIX view_projection; - XMMATRIX inverse_view_projection; Frustum frustum; // This frustum can be used for intersection test with wiPrimitive primitives BoundingFrustum boundingfrustum; // This boundingfrustum can be used for frustum vs frustum intersection test @@ -2455,7 +2474,6 @@ struct SHCAM const XMMATRIX V = XMMatrixLookToLH(E, to, up); const XMMATRIX P = XMMatrixPerspectiveFovLH(fov, 1, farPlane, nearPlane); view_projection = XMMatrixMultiply(V, P); - inverse_view_projection = XMMatrixInverse(nullptr, view_projection); frustum.Create(view_projection); BoundingFrustum::CreateFromMatrix(boundingfrustum, P); @@ -3275,7 +3293,7 @@ void UpdatePerFrameData( } // Shadow atlas packing: - if (!vis.visibleLights.empty()) + if (!vis.visibleLights.empty() || vis.scene->weather.rain_amount > 0) { auto range = wi::profiler::BeginRangeCPU("Shadowmap packing"); static thread_local wi::rectpacker::State packer; @@ -3284,6 +3302,14 @@ void UpdatePerFrameData( while (iterative_scaling > 0.03f) { packer.clear(); + if(vis.scene->weather.rain_amount > 0) + { + // Rain blocker: + wi::rectpacker::Rect rect = {}; + rect.id = -1; + rect.w = rect.h = 128; + packer.add_rect(rect); + } for (uint32_t lightIndex : vis.visibleLights) { LightComponent& light = scene.lights[lightIndex]; @@ -3347,6 +3373,19 @@ void UpdatePerFrameData( { for (auto& rect : packer.rects) { + if (rect.id == -1) + { + // Rain blocker: + if (rect.was_packed) + { + scene.rain_blocker_dummy_light.shadow_rect = rect; + } + else + { + scene.rain_blocker_dummy_light.shadow_rect = {}; + } + continue; + } uint32_t lightIndex = uint32_t(rect.id); LightComponent& light = scene.lights[lightIndex]; if (rect.was_packed) @@ -3548,6 +3587,20 @@ void UpdatePerFrameData( frameCB.gi_boost = GetGIBoost(); + frameCB.rain_blocker_mad_prev = frameCB.rain_blocker_mad; + frameCB.rain_blocker_matrix_prev = frameCB.rain_blocker_matrix; + frameCB.rain_blocker_matrix_inverse_prev = frameCB.rain_blocker_matrix_inverse; + frameCB.rain_blocker_mad = XMFLOAT4( + float(scene.rain_blocker_dummy_light.shadow_rect.w) / float(shadowMapAtlas.desc.width), + float(scene.rain_blocker_dummy_light.shadow_rect.h) / float(shadowMapAtlas.desc.height), + float(scene.rain_blocker_dummy_light.shadow_rect.x) / float(shadowMapAtlas.desc.width), + float(scene.rain_blocker_dummy_light.shadow_rect.y) / float(shadowMapAtlas.desc.height) + ); + SHCAM shcam; + CreateDirLightShadowCams(vis.scene->rain_blocker_dummy_light, *vis.camera, &shcam, 1); + XMStoreFloat4x4(&frameCB.rain_blocker_matrix, shcam.view_projection); + XMStoreFloat4x4(&frameCB.rain_blocker_matrix_inverse, XMMatrixInverse(nullptr, shcam.view_projection)); + frameCB.temporalaa_samplerotation = 0; if (GetTemporalAAEnabled()) { @@ -4538,7 +4591,7 @@ void UpdateRenderDataAsync( } // GPU Particle systems simulation/sorting/culling: - if (!vis.visibleEmitters.empty()) + if (!vis.visibleEmitters.empty() || vis.scene->weather.rain_amount > 0) { auto range = wi::profiler::BeginRangeGPU("EmittedParticles - Simulate", cmd); for (uint32_t emitterIndex : vis.visibleEmitters) @@ -4551,6 +4604,10 @@ void UpdateRenderDataAsync( emitter.UpdateGPU(instanceIndex, mesh, cmd); } + if (vis.scene->weather.rain_amount > 0) + { + vis.scene->rainEmitter.UpdateGPU(vis.scene->rainInstanceOffset, nullptr, cmd); + } wi::profiler::EndRange(range); } @@ -4639,6 +4696,11 @@ void UpdateRaytracingAccelerationStructures(const Scene& scene, CommandList cmd) } } + if (scene.weather.rain_amount > 0 && scene.rainEmitter.BLAS.IsValid()) + { + device->BuildRaytracingAccelerationStructure(&scene.rainEmitter.BLAS, cmd, nullptr); + } + { GPUBarrier barriers[] = { GPUBarrier::Buffer(&scene.TLAS.desc.top_level.instance_buffer, ResourceState::COPY_DST, ResourceState::SHADER_RESOURCE_COMPUTE), @@ -4871,47 +4933,51 @@ void DrawSoftParticles( CommandList cmd ) { - size_t emitterCount = vis.visibleEmitters.size(); - if (emitterCount == 0) - { - return; - } auto range = distortion ? wi::profiler::BeginRangeGPU("EmittedParticles - Render (Distortion)", cmd) : wi::profiler::BeginRangeGPU("EmittedParticles - Render", cmd); BindCommonResources(cmd); - // Sort emitters based on distance: - assert(emitterCount < 0x0000FFFF); // watch out for sorting hash truncation! - static thread_local wi::vector emitterSortingHashes; - emitterSortingHashes.resize(emitterCount); - for (size_t i = 0; i < emitterCount; ++i) + size_t emitterCount = vis.visibleEmitters.size(); + if (emitterCount > 0) { - const uint32_t emitterIndex = vis.visibleEmitters[i]; - const wi::EmittedParticleSystem& emitter = vis.scene->emitters[emitterIndex]; - float distance = wi::math::DistanceEstimated(emitter.center, vis.camera->Eye); - emitterSortingHashes[i] = 0; - emitterSortingHashes[i] |= (uint32_t)i & 0x0000FFFF; - emitterSortingHashes[i] |= (uint32_t)XMConvertFloatToHalf(distance) << 16u; + // Sort emitters based on distance: + assert(emitterCount < 0x0000FFFF); // watch out for sorting hash truncation! + static thread_local wi::vector emitterSortingHashes; + emitterSortingHashes.resize(emitterCount); + for (size_t i = 0; i < emitterCount; ++i) + { + const uint32_t emitterIndex = vis.visibleEmitters[i]; + const wi::EmittedParticleSystem& emitter = vis.scene->emitters[emitterIndex]; + float distance = wi::math::DistanceEstimated(emitter.center, vis.camera->Eye); + emitterSortingHashes[i] = 0; + emitterSortingHashes[i] |= (uint32_t)i & 0x0000FFFF; + emitterSortingHashes[i] |= (uint32_t)XMConvertFloatToHalf(distance) << 16u; + } + std::sort(emitterSortingHashes.begin(), emitterSortingHashes.end(), std::greater()); + + for (size_t i = 0; i < emitterCount; ++i) + { + const uint32_t emitterIndex = vis.visibleEmitters[emitterSortingHashes[i] & 0x0000FFFF]; + const wi::EmittedParticleSystem& emitter = vis.scene->emitters[emitterIndex]; + const Entity entity = vis.scene->emitters.GetEntity(emitterIndex); + const MaterialComponent& material = *vis.scene->materials.GetComponent(entity); + + if (distortion && emitter.shaderType == wi::EmittedParticleSystem::SOFT_DISTORTION) + { + emitter.Draw(material, cmd); + } + else if (!distortion && (emitter.shaderType == wi::EmittedParticleSystem::SOFT || emitter.shaderType == wi::EmittedParticleSystem::SOFT_LIGHTING || emitter.shaderType == wi::EmittedParticleSystem::SIMPLE || IsWireRender())) + { + emitter.Draw(material, cmd); + } + } } - std::sort(emitterSortingHashes.begin(), emitterSortingHashes.end(), std::greater()); - for (size_t i = 0; i < emitterCount; ++i) + if (!distortion && vis.scene->weather.rain_amount > 0) { - const uint32_t emitterIndex = vis.visibleEmitters[emitterSortingHashes[i] & 0x0000FFFF]; - const wi::EmittedParticleSystem& emitter = vis.scene->emitters[emitterIndex]; - const Entity entity = vis.scene->emitters.GetEntity(emitterIndex); - const MaterialComponent& material = *vis.scene->materials.GetComponent(entity); - - if (distortion && emitter.shaderType == wi::EmittedParticleSystem::SOFT_DISTORTION) - { - emitter.Draw(material, cmd); - } - else if (!distortion && (emitter.shaderType == wi::EmittedParticleSystem::SOFT || emitter.shaderType == wi::EmittedParticleSystem::SOFT_LIGHTING || emitter.shaderType == wi::EmittedParticleSystem::SIMPLE || IsWireRender())) - { - emitter.Draw(material, cmd); - } + vis.scene->rainEmitter.Draw(vis.scene->rainMaterial, cmd); } device->BindShadingRate(ShadingRate::RATE_1X1, cmd); @@ -4919,10 +4985,10 @@ void DrawSoftParticles( wi::profiler::EndRange(range); } void DrawSpritesAndFonts( - const wi::scene::Scene& scene, - const wi::scene::CameraComponent& camera, + const Scene& scene, + const CameraComponent& camera, bool distortion, - wi::graphics::CommandList cmd + CommandList cmd ) { if (scene.sprites.GetCount() == 0 && scene.fonts.GetCount() == 0) @@ -5454,7 +5520,7 @@ void DrawShadowmaps( if (IsWireRender()) return; - if (!vis.visibleLights.empty() && shadowMapAtlas.IsValid()) + if ((!vis.visibleLights.empty() || vis.scene->weather.rain_amount > 0) && shadowMapAtlas.IsValid()) { device->EventBegin("DrawShadowmaps", cmd); auto range_cpu = wi::profiler::BeginRangeCPU("Shadowmap Rendering"); @@ -5847,6 +5913,58 @@ void DrawShadowmaps( } // terminate switch } + // Rain blocker: + if(vis.scene->weather.rain_amount > 0) + { + SHCAM shcam; + CreateDirLightShadowCams(vis.scene->rain_blocker_dummy_light, *vis.camera, &shcam, 1); + + renderQueue.init(); + for (size_t i = 0; i < vis.scene->aabb_objects.size(); ++i) + { + const AABB& aabb = vis.scene->aabb_objects[i]; + if (aabb.layerMask & vis.layerMask) + { + const ObjectComponent& object = vis.scene->objects[i]; + if (object.IsRenderable()) + { + uint16_t camera_mask = 0; + if (shcam.frustum.CheckBoxFast(aabb)) + { + camera_mask |= 1 << 0; + } + if (camera_mask == 0) + continue; + + renderQueue.add(object.mesh_index, uint32_t(i), 0, object.sort_bits, camera_mask); + } + } + } + + if (!renderQueue.empty()) + { + device->EventBegin("Rain Blocker", cmd); + const uint cascade = 0; + XMStoreFloat4x4(&cb.cameras[cascade].view_projection, shcam.view_projection); + cb.cameras[cascade].output_index = cascade; + + Viewport vp; + vp.top_left_x = float(vis.scene->rain_blocker_dummy_light.shadow_rect.x + cascade * vis.scene->rain_blocker_dummy_light.shadow_rect.w); + vp.top_left_y = float(vis.scene->rain_blocker_dummy_light.shadow_rect.y); + vp.width = float(vis.scene->rain_blocker_dummy_light.shadow_rect.w); + vp.height = float(vis.scene->rain_blocker_dummy_light.shadow_rect.h); + vp.min_depth = 0.0f; + vp.max_depth = 1.0f; + + device->BindDynamicConstantBuffer(cb, CBSLOT_RENDERER_CAMERA, cmd); + device->BindViewports(1, &vp, cmd); + + renderQueue.sort_opaque(); + RenderMeshes(vis, renderQueue, RENDERPASS_RAINBLOCKER, FILTER_OBJECT_ALL, cmd, 0, 1); + device->EventEnd(cmd); + } + } + device->RenderPassEnd(cmd); wi::profiler::EndRange(range_gpu); diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index e1f37ff10..f75f92372 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -60,6 +60,11 @@ namespace wi::scene impostorInstanceOffset = uint32_t(instanceArraySize); instanceArraySize += 1; } + if (weathers.GetCount() > 0 && weathers[0].rain_amount > 0) + { + rainInstanceOffset = uint32_t(instanceArraySize); + instanceArraySize += 1; + } if (instanceUploadBuffer[0].desc.size < (instanceArraySize * sizeof(ShaderMeshInstance))) { GPUBufferDesc desc; @@ -93,6 +98,11 @@ namespace wi::scene impostorMaterialOffset = uint32_t(materialArraySize); materialArraySize += 1; } + if (weathers.GetCount() > 0 && weathers[0].rain_amount > 0) + { + rainMaterialOffset = uint32_t(materialArraySize); + materialArraySize += 1; + } if (materialUploadBuffer[0].desc.size < (materialArraySize * sizeof(ShaderMaterial))) { GPUBufferDesc desc; @@ -247,6 +257,11 @@ namespace wi::scene impostorGeometryOffset = uint32_t(geometryArraySize); geometryArraySize += 1; } + if (weathers.GetCount() > 0 && weathers[0].rain_amount > 0) + { + rainGeometryOffset = uint32_t(geometryArraySize); + geometryArraySize += 1; + } if (geometryUploadBuffer[0].desc.size < (geometryArraySize * sizeof(ShaderGeometry))) { GPUBufferDesc desc; @@ -815,6 +830,12 @@ namespace wi::scene shaderscene.weather.ocean.texture_gradientmap = device->GetDescriptorIndex(ocean.getGradientMap(), SubresourceType::SRV); shaderscene.weather.stars = weather.stars; XMStoreFloat4x4(&shaderscene.weather.stars_rotation, XMMatrixRotationQuaternion(XMLoadFloat4(&weather.stars_rotation_quaternion))); + shaderscene.weather.rain_amount = weather.rain_amount; + shaderscene.weather.rain_length = weather.rain_length; + shaderscene.weather.rain_speed = weather.rain_speed; + shaderscene.weather.rain_scale = weather.rain_scale; + shaderscene.weather.rain_splash_scale = weather.rain_splash_scale; + shaderscene.weather.rain_color = weather.rain_color; shaderscene.ddgi.grid_dimensions = ddgi.grid_dimensions; shaderscene.ddgi.probe_count = ddgi.grid_dimensions.x * ddgi.grid_dimensions.y * ddgi.grid_dimensions.z; @@ -4355,11 +4376,6 @@ namespace wi::scene GraphicsDevice* device = wi::graphics::GetDevice(); - uint32_t indexCount = emitter.GetMaxParticleCount() * 6; - uint32_t triangleCount = indexCount / 3u; - uint32_t meshletCount = triangle_count_to_meshlet_count(triangleCount); - uint32_t meshletOffset = meshletAllocator.fetch_add(meshletCount); - ShaderGeometry geometry; geometry.init(); geometry.indexOffset = 0; @@ -4369,8 +4385,6 @@ namespace wi::scene geometry.vb_uvs = emitter.vb_uvs.descriptor_srv; geometry.vb_col = emitter.vb_col.descriptor_srv; geometry.flags = SHADERMESH_FLAG_DOUBLE_SIDED | SHADERMESH_FLAG_EMITTEDPARTICLE; - geometry.meshletOffset = 0; - geometry.meshletCount = meshletCount; size_t geometryAllocation = geometryAllocator.fetch_add(1); std::memcpy(geometryArrayMapped + geometryAllocation, &geometry, sizeof(geometry)); @@ -4385,7 +4399,6 @@ namespace wi::scene inst.geometryCount = 1; inst.baseGeometryOffset = inst.geometryOffset; inst.baseGeometryCount = inst.geometryCount; - inst.meshletOffset = meshletOffset; const size_t instanceIndex = objects.GetCount() + hairs.GetCount() + args.jobIndex; std::memcpy(instanceArrayMapped + instanceIndex, &inst, sizeof(inst)); @@ -4450,6 +4463,125 @@ namespace wi::scene } ocean.occlusionQueries[queryheap_idx] = -1; // invalidate query } + + rain_blocker_dummy_light.shadow_rect = {}; + if (weather.rain_amount > 0) + { + GraphicsDevice* device = wi::graphics::GetDevice(); + rainEmitter._flags |= wi::EmittedParticleSystem::FLAG_USE_RAIN_BLOCKER; + rainEmitter.shaderType = wi::EmittedParticleSystem::PARTICLESHADERTYPE::SOFT_LIGHTING; + rainEmitter.SetCollidersDisabled(true); + rainEmitter.SetVolumeEnabled(true); + constexpr uint32_t target_max_particle_count = 1000000; + if (rainEmitter.GetMaxParticleCount() != target_max_particle_count) + { + rainEmitter.SetMaxParticleCount(target_max_particle_count); + } + rainEmitter.count = wi::math::Lerp(0, (float)target_max_particle_count, weather.rain_amount); + rainEmitter.life = 1; + rainEmitter.size = weather.rain_scale; + rainEmitter.random_factor = weather.windRandomness; + rainEmitter.random_life = 1; + rainEmitter.motionBlurAmount = weather.rain_length; + rainEmitter.velocity = XMFLOAT3( + weather.windDirection.x * weather.windSpeed, + -weather.rain_speed, + weather.windDirection.z * weather.windSpeed + ); + rainMaterial.SetUseVertexColors(true); + rainMaterial.shaderType = MaterialComponent::SHADERTYPE_PBR; + rainMaterial.subsurfaceScattering = XMFLOAT4(1, 1, 1, 2); + rainMaterial.userBlendMode = BLENDMODE_ALPHA; + rainMaterial.baseColor = weather.rain_color; + if (!rainMaterial.textures[MaterialComponent::BASECOLORMAP].resource.IsValid()) + { + Texture gradientTex = wi::texturehelper::CreateGradientTexture( + wi::texturehelper::GradientType::Circular, + 32, 32, + XMFLOAT2(0.5f, 0.5f), XMFLOAT2(0.5f, 0), + wi::texturehelper::GradientFlags::Smoothstep | wi::texturehelper::GradientFlags::Inverse + ); + Texture gradientTexBC; + TextureDesc desc = gradientTex.GetDesc(); + desc.format = Format::BC4_UNORM; + desc.swizzle = { wi::graphics::ComponentSwizzle::ONE,wi::graphics::ComponentSwizzle::ONE,wi::graphics::ComponentSwizzle::ONE,wi::graphics::ComponentSwizzle::R }; + bool success = device->CreateTexture(&desc, nullptr, &gradientTexBC); + assert(success); + wi::renderer::AddDeferredBlockCompression(gradientTex, gradientTexBC); + rainMaterial.textures[MaterialComponent::BASECOLORMAP].resource.SetTexture(gradientTexBC); + } + rainMaterial.shadingRate = ShadingRate::RATE_4X4; + TransformComponent transform; + transform.scale_local = XMFLOAT3(30, 30, 30); + transform.translation_local.x = camera.Eye.x + camera.At.x * 10; + transform.translation_local.y = camera.Eye.y + camera.At.y * 10 + transform.scale_local.y * 0.5f; + transform.translation_local.z = camera.Eye.z + camera.At.z * 10; + transform.UpdateTransform(); + rainEmitter.UpdateCPU(transform, dt); + rain_blocker_dummy_light.cascade_distances[0] = transform.scale_local.x; + + ShaderMaterial material; + material.init(); + rainMaterial.WriteShaderMaterial(&material); + std::memcpy(materialArrayMapped + rainMaterialOffset, &material, sizeof(material)); + + ShaderGeometry geometry; + geometry.init(); + geometry.indexOffset = 0; + geometry.materialIndex = rainMaterialOffset; + geometry.ib = device->GetDescriptorIndex(&rainEmitter.primitiveBuffer, SubresourceType::SRV); + geometry.vb_pos_nor_wind = rainEmitter.vb_pos.descriptor_srv; + geometry.vb_uvs = rainEmitter.vb_uvs.descriptor_srv; + geometry.vb_col = rainEmitter.vb_col.descriptor_srv; + geometry.flags = SHADERMESH_FLAG_DOUBLE_SIDED | SHADERMESH_FLAG_EMITTEDPARTICLE; + + std::memcpy(geometryArrayMapped + rainGeometryOffset, &geometry, sizeof(geometry)); + + ShaderMeshInstance inst; + inst.init(); + inst.uid = 0; + inst.layerMask = ~0u; + inst.emissive = wi::math::Pack_R11G11B10_FLOAT(XMFLOAT3(1, 1, 1)); + inst.color = wi::math::CompressColor(XMFLOAT4(1, 1, 1, 1)); + inst.geometryOffset = (uint)rainGeometryOffset; + inst.geometryCount = 1; + inst.baseGeometryOffset = inst.geometryOffset; + inst.baseGeometryCount = inst.geometryCount; + + const size_t instanceIndex = rainInstanceOffset; + std::memcpy(instanceArrayMapped + instanceIndex, &inst, sizeof(inst)); + + if (TLAS_instancesMapped != nullptr) + { + if (!rainEmitter.BLAS.IsValid()) + { + rainEmitter.CreateRaytracingRenderData(); + } + + // TLAS instance data: + RaytracingAccelerationStructureDesc::TopLevel::Instance instance; + for (int i = 0; i < arraysize(instance.transform); ++i) + { + for (int j = 0; j < arraysize(instance.transform[i]); ++j) + { + instance.transform[i][j] = wi::math::IDENTITY_MATRIX.m[j][i]; + } + } + instance.instance_id = (uint32_t)instanceIndex; + instance.instance_mask = rainEmitter.layerMask == 0 ? 0 : 0xFF; + instance.bottom_level = &rainEmitter.BLAS; + instance.instance_contribution_to_hit_group_index = 0; + instance.flags = RaytracingAccelerationStructureDesc::TopLevel::Instance::FLAG_TRIANGLE_CULL_DISABLE; + + void* dest = (void*)((size_t)TLAS_instancesMapped + instanceIndex * device->GetTopLevelAccelerationStructureInstanceSize()); + device->WriteTopLevelAccelerationStructureInstance(&instance, dest); + } + } + else + { + rainMaterial = {}; + rainEmitter = {}; + } } void Scene::RunSoundUpdateSystem(wi::jobsystem::context& ctx) { diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index b13bceb49..f2686d0fa 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -46,7 +46,7 @@ namespace wi::scene wi::ecs::ComponentManager& animation_datas = componentLibrary.Register("wi::scene::Scene::animation_datas"); wi::ecs::ComponentManager& emitters = componentLibrary.Register("wi::scene::Scene::emitters"); wi::ecs::ComponentManager& hairs = componentLibrary.Register("wi::scene::Scene::hairs"); - wi::ecs::ComponentManager& weathers = componentLibrary.Register("wi::scene::Scene::weathers", 4); // version = 4 + wi::ecs::ComponentManager& weathers = componentLibrary.Register("wi::scene::Scene::weathers", 5); // version = 5 wi::ecs::ComponentManager& sounds = componentLibrary.Register("wi::scene::Scene::sounds", 1); // version = 1 wi::ecs::ComponentManager& videos = componentLibrary.Register("wi::scene::Scene::videos"); wi::ecs::ComponentManager& inverse_kinematics = componentLibrary.Register("wi::scene::Scene::inverse_kinematics"); @@ -236,6 +236,13 @@ namespace wi::scene uint32_t impostorGeometryOffset = ~0u; uint32_t impostorMaterialOffset = ~0u; + wi::EmittedParticleSystem rainEmitter; + MaterialComponent rainMaterial; + uint32_t rainInstanceOffset = ~0u; + uint32_t rainGeometryOffset = ~0u; + uint32_t rainMaterialOffset = ~0u; + LightComponent rain_blocker_dummy_light; + std::atomic lightmap_request_allocator{ 0 }; wi::vector lightmap_requests; wi::vector transforms_temp; diff --git a/WickedEngine/wiScene_BindLua.cpp b/WickedEngine/wiScene_BindLua.cpp index e4d936b1b..168c55b53 100644 --- a/WickedEngine/wiScene_BindLua.cpp +++ b/WickedEngine/wiScene_BindLua.cpp @@ -5551,6 +5551,11 @@ Luna::PropertyType WeatherComponent_BindLua::propertie lunaproperty(WeatherComponent_BindLua, windWaveSize), lunaproperty(WeatherComponent_BindLua, windSpeed), lunaproperty(WeatherComponent_BindLua, stars), + lunaproperty(WeatherComponent_BindLua, rainAmount), + lunaproperty(WeatherComponent_BindLua, rainLength), + lunaproperty(WeatherComponent_BindLua, rainSpeed), + lunaproperty(WeatherComponent_BindLua, rainScale), + lunaproperty(WeatherComponent_BindLua, rainColor), lunaproperty(WeatherComponent_BindLua, OceanParameters), lunaproperty(WeatherComponent_BindLua, AtmosphereParameters), diff --git a/WickedEngine/wiScene_BindLua.h b/WickedEngine/wiScene_BindLua.h index 435b1ca04..a0d0b1a11 100644 --- a/WickedEngine/wiScene_BindLua.h +++ b/WickedEngine/wiScene_BindLua.h @@ -1444,6 +1444,11 @@ namespace wi::lua::scene windWaveSize = FloatProperty(&component->windWaveSize); windSpeed = FloatProperty(&component->windSpeed); stars = FloatProperty(&component->stars); + rainAmount = FloatProperty(&component->rain_amount); + rainLength = FloatProperty(&component->rain_length); + rainSpeed = FloatProperty(&component->rain_speed); + rainScale = FloatProperty(&component->rain_scale); + rainColor = VectorProperty(&component->rain_color); gravity = VectorProperty(&component->gravity); OceanParameters = Weather_OceanParams_Property(&component->oceanParameters); @@ -1488,6 +1493,11 @@ namespace wi::lua::scene FloatProperty windWaveSize; FloatProperty windSpeed; FloatProperty stars; + FloatProperty rainAmount; + FloatProperty rainLength; + FloatProperty rainSpeed; + FloatProperty rainScale; + VectorProperty rainColor; PropertyFunction(sunColor) PropertyFunction(sunDirection) @@ -1512,6 +1522,11 @@ namespace wi::lua::scene PropertyFunction(windWaveSize) PropertyFunction(windSpeed) PropertyFunction(stars) + PropertyFunction(rainAmount) + PropertyFunction(rainLength) + PropertyFunction(rainSpeed) + PropertyFunction(rainScale) + PropertyFunction(rainColor) Weather_OceanParams_Property OceanParameters; Weather_AtmosphereParams_Property AtmosphereParameters; diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 52ca8e294..13719cb06 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -894,12 +894,10 @@ namespace wi::scene int forced_shadow_resolution = -1; // -1: disabled, greater: fixed shadow map resolution // Non-serialized attributes: - XMFLOAT3 position; - XMFLOAT3 direction; - XMFLOAT4 rotation; - XMFLOAT3 scale; - XMFLOAT3 front; - XMFLOAT3 right; + XMFLOAT3 position = XMFLOAT3(0, 0, 0); + XMFLOAT3 direction = XMFLOAT3(0, 1, 0); + XMFLOAT4 rotation = XMFLOAT4(0, 0, 0, 1); + XMFLOAT3 scale = XMFLOAT3(1, 1, 1); mutable int occlusionquery = -1; wi::rectpacker::Rect shadow_rect = {}; @@ -1342,6 +1340,12 @@ namespace wi::scene float stars = 0.5f; XMFLOAT3 gravity = XMFLOAT3(0, -10, 0); float sky_rotation = 0; // horizontal rotation for skyMap texture (in radians) + float rain_amount = 0; + float rain_length = 0.04f; + float rain_speed = 1; + float rain_scale = 0.005f; + float rain_splash_scale = 0.1f; + XMFLOAT4 rain_color = XMFLOAT4(0.6f, 0.8f, 1, 0.5f); wi::Ocean::OceanParameters oceanParameters; AtmosphereParameters atmosphereParameters; diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index 8614c21d9..acf000a24 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -1436,6 +1436,15 @@ namespace wi::scene { archive >> sky_rotation; } + if (seri.GetVersion() >= 5) + { + archive >> rain_amount; + archive >> rain_length; + archive >> rain_speed; + archive >> rain_scale; + archive >> rain_splash_scale; + archive >> rain_color; + } } else { @@ -1647,6 +1656,15 @@ namespace wi::scene { archive << sky_rotation; } + if (seri.GetVersion() >= 5) + { + archive << rain_amount; + archive << rain_length; + archive << rain_speed; + archive << rain_scale; + archive << rain_splash_scale; + archive << rain_color; + } } } void SoundComponent::Serialize(wi::Archive& archive, EntitySerializer& seri) diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 6c394cc62..e8616af06 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -848,7 +848,7 @@ namespace wi::terrain }); wi::jobsystem::Wait(ctx); // wait until chunk's vertex buffer is fully generated - material.SetCastShadow(slope_cast_shadow.load()); + object.SetCastShadow(slope_cast_shadow.load()); mesh.SetDoubleSidedShadow(slope_cast_shadow.load()); wi::jobsystem::Execute(ctx, [&](wi::jobsystem::JobArgs args) { diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 38d9b1e5a..da7bf4fd1 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 319; + const int revision = 320; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);