Volumetric cloud updates (#544)

- Reprojection update
- Cloud model changes
- Weather map import
- Local lights
- Environment capture
- Volumetric cloud shadow
- Aerial perspective for clouds

Co-authored-by: Silas Oler <silasmartins@outlook.dk>
This commit is contained in:
Turánszki János
2022-08-30 16:37:51 +02:00
committed by GitHub
parent 6a2173f699
commit 73ee94d114
56 changed files with 1673 additions and 1144 deletions
@@ -846,7 +846,7 @@ Describes a Force Field effector.
- Range : float
#### WeatherComponent
Describes a Rigid Body Physics object.
Describes a Weather
- OceanParameters : OceanParameters -- Returns a table to modify ocean parameters (if ocean is enabled)
- AtmosphereParameters : AtmosphereParameters -- Returns a table to modify atmosphere parameters
- VolumetricCloudParameters : VolumetricCloudParameters -- Returns a table to modify volumetric cloud parameters
Binary file not shown.
Binary file not shown.
+9
View File
@@ -69,6 +69,7 @@ void ComponentsWindow::Create(EditorComponent* _editor)
newComponentCombo.AddItem("Soft Body " ICON_SOFTBODY, 17);
newComponentCombo.AddItem("Collider " ICON_COLLIDER, 18);
newComponentCombo.AddItem("Camera " ICON_CAMERA, 20);
newComponentCombo.AddItem("Object " ICON_OBJECT, 21);
newComponentCombo.OnSelect([=](wi::gui::EventArgs args) {
newComponentCombo.SetSelectedWithoutCallback(-1);
if (editor->translator.selected.empty())
@@ -168,6 +169,10 @@ void ComponentsWindow::Create(EditorComponent* _editor)
if (scene.cameras.Contains(entity))
return;
break;
case 21:
if (scene.objects.Contains(entity))
return;
break;
default:
return;
}
@@ -264,6 +269,10 @@ void ComponentsWindow::Create(EditorComponent* _editor)
case 20:
scene.cameras.Create(entity);
break;
case 21:
scene.objects.Create(entity);
scene.aabb_objects.Create(entity);
break;
default:
break;
}
+1 -1
View File
@@ -1001,7 +1001,7 @@ void EditorComponent::Update(float dt)
}
ForceFieldComponent& force = scene.forces.Create(grass_interaction_entity);
TransformComponent& transform = scene.transforms.Create(grass_interaction_entity);
force.type = ENTITY_TYPE_FORCEFIELD_POINT;
force.type = ForceFieldComponent::Type::Point;
force.gravity = -80;
force.range = 3;
transform.Translate(P);
+5 -5
View File
@@ -42,10 +42,10 @@ void ForceFieldWindow::Create(EditorComponent* _editor)
switch (args.iValue)
{
case 0:
force->type = ENTITY_TYPE_FORCEFIELD_POINT;
force->type = ForceFieldComponent::Type::Point;
break;
case 1:
force->type = ENTITY_TYPE_FORCEFIELD_PLANE;
force->type = ForceFieldComponent::Type::Plane;
break;
default:
assert(0); // error
@@ -53,8 +53,8 @@ void ForceFieldWindow::Create(EditorComponent* _editor)
}
}
});
typeComboBox.AddItem("Point");
typeComboBox.AddItem("Plane");
typeComboBox.AddItem("Point", (uint64_t)ForceFieldComponent::Type::Point);
typeComboBox.AddItem("Plane", (uint64_t)ForceFieldComponent::Type::Plane);
typeComboBox.SetEnabled(false);
typeComboBox.SetTooltip("Choose the force field type.");
AddWidget(&typeComboBox);
@@ -105,7 +105,7 @@ void ForceFieldWindow::SetEntity(Entity entity)
if (force != nullptr)
{
typeComboBox.SetSelected(force->type == ENTITY_TYPE_FORCEFIELD_POINT ? 0 : 1);
typeComboBox.SetSelectedByUserdataWithoutCallback((uint64_t)force->type);
gravitySlider.SetValue(force->gravity);
rangeSlider.SetValue(force->range);
+19 -1
View File
@@ -13,7 +13,7 @@ void LightWindow::Create(EditorComponent* _editor)
{
editor = _editor;
wi::gui::Window::Create(ICON_POINTLIGHT " Light", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE);
SetSize(XMFLOAT2(650, 740));
SetSize(XMFLOAT2(650, 760));
closeButton.SetTooltip("Delete LightComponent");
OnClose([=](wi::gui::EventArgs args) {
@@ -167,6 +167,20 @@ void LightWindow::Create(EditorComponent* _editor)
staticCheckBox.SetTooltip("Static lights will only be used for baking into lightmaps.");
AddWidget(&staticCheckBox);
volumetricCloudsCheckBox.Create("Volumetric Clouds: ");
volumetricCloudsCheckBox.SetSize(XMFLOAT2(hei, hei));
volumetricCloudsCheckBox.SetPos(XMFLOAT2(x, y += step));
volumetricCloudsCheckBox.OnClick([&](wi::gui::EventArgs args) {
LightComponent* light = editor->GetCurrentScene().lights.GetComponent(entity);
if (light != nullptr)
{
light->SetVolumetricCloudsEnabled(args.bValue);
}
});
volumetricCloudsCheckBox.SetEnabled(false);
volumetricCloudsCheckBox.SetTooltip("When enabled light emission will affect volumetric clouds.");
AddWidget(&volumetricCloudsCheckBox);
typeSelectorComboBox.Create("Type: ");
typeSelectorComboBox.SetSize(XMFLOAT2(wid, hei));
typeSelectorComboBox.SetPos(XMFLOAT2(x, y += step));
@@ -282,6 +296,8 @@ void LightWindow::SetEntity(Entity entity)
volumetricsCheckBox.SetCheck(light->IsVolumetricsEnabled());
staticCheckBox.SetEnabled(true);
staticCheckBox.SetCheck(light->IsStatic());
volumetricCloudsCheckBox.SetEnabled(true);
volumetricCloudsCheckBox.SetCheck(light->IsVolumetricCloudsEnabled());
colorPicker.SetEnabled(true);
colorPicker.SetPickColor(wi::Color::fromFloat3(light->color));
typeSelectorComboBox.SetSelected((int)light->GetType());
@@ -312,6 +328,7 @@ void LightWindow::SetEntity(Entity entity)
haloCheckBox.SetEnabled(false);
volumetricsCheckBox.SetEnabled(false);
staticCheckBox.SetEnabled(false);
volumetricCloudsCheckBox.SetEnabled(false);
intensitySlider.SetEnabled(false);
colorPicker.SetEnabled(false);
shadowResolutionComboBox.SetEnabled(false);
@@ -394,6 +411,7 @@ void LightWindow::ResizeLayout()
add_right(haloCheckBox);
add_right(volumetricsCheckBox);
add_right(staticCheckBox);
add_right(volumetricCloudsCheckBox);
add(shadowResolutionComboBox);
y += jump;
+1
View File
@@ -22,6 +22,7 @@ public:
wi::gui::CheckBox haloCheckBox;
wi::gui::CheckBox volumetricsCheckBox;
wi::gui::CheckBox staticCheckBox;
wi::gui::CheckBox volumetricCloudsCheckBox;
wi::gui::ColorPicker colorPicker;
wi::gui::ComboBox typeSelectorComboBox;
wi::gui::ComboBox shadowResolutionComboBox;
+2 -5
View File
@@ -794,8 +794,8 @@ void TerrainGenerator::Generation_Restart()
weather.ambient = XMFLOAT3(0.2f, 0.2f, 0.2f);
weather.SetRealisticSky(true);
weather.SetVolumetricClouds(true);
weather.volumetricCloudParameters.CoverageAmount = 0.4f;
weather.volumetricCloudParameters.CoverageMinimum = 1.35f;
weather.volumetricCloudParameters.CoverageAmount = 0.65f;
weather.volumetricCloudParameters.CoverageMinimum = 0.15f;
if (presetCombo.GetItemUserData(presetCombo.GetSelected()) == PRESET_ISLANDS)
{
weather.SetOceanEnabled(true);
@@ -813,9 +813,6 @@ void TerrainGenerator::Generation_Restart()
weather.fogHeightEnd = 100;
weather.windDirection = XMFLOAT3(0.05f, 0.05f, 0.05f);
weather.windSpeed = 4;
weather.cloud_shadow_amount = 0.4f;
weather.cloud_shadow_scale = 0.003f;
weather.cloud_shadow_speed = 0.25f;
weather.stars = 0.6f;
}
if (scene->lights.GetCount() == 0)
+58 -110
View File
@@ -10,7 +10,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, 1400));
SetSize(XMFLOAT2(660, 1300));
closeButton.SetTooltip("Delete WeatherComponent");
OnClose([=](wi::gui::EventArgs args) {
@@ -58,7 +58,7 @@ void WeatherWindow::Create(EditorComponent* _editor)
colorComboBox.AddItem("Horizon color");
colorComboBox.AddItem("Zenith color");
colorComboBox.AddItem("Ocean color");
colorComboBox.AddItem("V. Cloud color");
colorComboBox.AddItem("Cloud color");
colorComboBox.SetTooltip("Choose the destination data of the color picker.");
AddWidget(&colorComboBox);
@@ -137,62 +137,6 @@ void WeatherWindow::Create(EditorComponent* _editor)
});
AddWidget(&fogHeightEndSlider);
fogHeightSkySlider.Create(0, 1, 0, 10000, "Fog Height Sky: ");
fogHeightSkySlider.SetSize(XMFLOAT2(wid, hei));
fogHeightSkySlider.SetPos(XMFLOAT2(x, y += step));
fogHeightSkySlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().fogHeightSky = args.fValue;
});
AddWidget(&fogHeightSkySlider);
cloudinessSlider.Create(0, 1, 0.0f, 10000, "Cloudiness: ");
cloudinessSlider.SetSize(XMFLOAT2(wid, hei));
cloudinessSlider.SetPos(XMFLOAT2(x, y += step));
cloudinessSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().cloudiness = args.fValue;
});
AddWidget(&cloudinessSlider);
cloudScaleSlider.Create(0.00005f, 0.001f, 0.0005f, 10000, "Cloud Scale: ");
cloudScaleSlider.SetSize(XMFLOAT2(wid, hei));
cloudScaleSlider.SetPos(XMFLOAT2(x, y += step));
cloudScaleSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().cloudScale = args.fValue;
});
AddWidget(&cloudScaleSlider);
cloudSpeedSlider.Create(0.001f, 0.2f, 0.1f, 10000, "Cloud Speed: ");
cloudSpeedSlider.SetSize(XMFLOAT2(wid, hei));
cloudSpeedSlider.SetPos(XMFLOAT2(x, y += step));
cloudSpeedSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().cloudSpeed = args.fValue;
});
AddWidget(&cloudSpeedSlider);
cloudShadowAmountSlider.Create(0, 1, 0, 10000, "Cloud Shadow: ");
cloudShadowAmountSlider.SetSize(XMFLOAT2(wid, hei));
cloudShadowAmountSlider.SetPos(XMFLOAT2(x, y += step));
cloudShadowAmountSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().cloud_shadow_amount = args.fValue;
});
AddWidget(&cloudShadowAmountSlider);
cloudShadowSpeedSlider.Create(0, 1, 0.2f, 10000, "Cloud Shadow Speed: ");
cloudShadowSpeedSlider.SetSize(XMFLOAT2(wid, hei));
cloudShadowSpeedSlider.SetPos(XMFLOAT2(x, y += step));
cloudShadowSpeedSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().cloud_shadow_speed = args.fValue;
});
AddWidget(&cloudShadowSpeedSlider);
cloudShadowScaleSlider.Create(0.0001f, 0.02f, 0.005f, 10000, "Cloud Shadow Scale: ");
cloudShadowScaleSlider.SetSize(XMFLOAT2(wid, hei));
cloudShadowScaleSlider.SetPos(XMFLOAT2(x, y += step));
cloudShadowScaleSlider.OnSlide([&](wi::gui::EventArgs args) {
GetWeather().cloud_shadow_scale = args.fValue;
});
AddWidget(&cloudShadowScaleSlider);
windSpeedSlider.Create(0.0f, 4.0f, 1.0f, 10000, "Wind Speed: ");
windSpeedSlider.SetSize(XMFLOAT2(wid, hei));
windSpeedSlider.SetPos(XMFLOAT2(x, y += step));
@@ -250,31 +194,13 @@ void WeatherWindow::Create(EditorComponent* _editor)
});
AddWidget(&starsSlider);
simpleskyCheckBox.Create("Simple sky: ");
simpleskyCheckBox.SetTooltip("Simple sky will simply blend horizon and zenith color from bottom to top.");
simpleskyCheckBox.SetSize(XMFLOAT2(hei, hei));
simpleskyCheckBox.SetPos(XMFLOAT2(x, y += step));
simpleskyCheckBox.OnClick([&](wi::gui::EventArgs args) {
auto& weather = GetWeather();
weather.SetSimpleSky(args.bValue);
if (args.bValue)
{
weather.SetRealisticSky(false);
}
});
AddWidget(&simpleskyCheckBox);
realisticskyCheckBox.Create("Realistic sky: ");
realisticskyCheckBox.SetTooltip("Physically based sky rendering model.");
realisticskyCheckBox.SetTooltip("Physically based sky rendering model.\nNote that realistic sky requires a sun (directional light) to be visible.");
realisticskyCheckBox.SetSize(XMFLOAT2(hei, hei));
realisticskyCheckBox.SetPos(XMFLOAT2(x, y += step));
realisticskyCheckBox.OnClick([&](wi::gui::EventArgs args) {
auto& weather = GetWeather();
weather.SetRealisticSky(args.bValue);
if (args.bValue)
{
weather.SetSimpleSky(false);
}
});
AddWidget(&realisticskyCheckBox);
@@ -289,7 +215,17 @@ void WeatherWindow::Create(EditorComponent* _editor)
});
AddWidget(&volumetricCloudsCheckBox);
coverageAmountSlider.Create(0, 10, 0, 1000, "Coverage amount: ");
volumetricCloudsShadowsCheckBox.Create("Volumetric clouds shadows: ");
volumetricCloudsShadowsCheckBox.SetTooltip("Compute shadows for volumetric clouds that will be used for geometry and lighting.");
volumetricCloudsShadowsCheckBox.SetSize(XMFLOAT2(hei, hei));
volumetricCloudsShadowsCheckBox.SetPos(XMFLOAT2(x, y += step));
volumetricCloudsShadowsCheckBox.OnClick([&](wi::gui::EventArgs args) {
auto& weather = GetWeather();
weather.SetVolumetricCloudsShadows(args.bValue);
});
AddWidget(&volumetricCloudsShadowsCheckBox);
coverageAmountSlider.Create(0, 10, 1, 1000, "Coverage amount: ");
coverageAmountSlider.SetSize(XMFLOAT2(wid, hei));
coverageAmountSlider.SetPos(XMFLOAT2(x, y += step));
coverageAmountSlider.OnSlide([&](wi::gui::EventArgs args) {
@@ -298,7 +234,7 @@ void WeatherWindow::Create(EditorComponent* _editor)
});
AddWidget(&coverageAmountSlider);
coverageMinimumSlider.Create(1, 2, 1, 1000, "Coverage minimmum: ");
coverageMinimumSlider.Create(0, 1, 0, 1000, "Coverage minimmum: ");
coverageMinimumSlider.SetSize(XMFLOAT2(wid, hei));
coverageMinimumSlider.SetPos(XMFLOAT2(x, y += step));
coverageMinimumSlider.OnSlide([&](wi::gui::EventArgs args) {
@@ -374,6 +310,38 @@ void WeatherWindow::Create(EditorComponent* _editor)
});
AddWidget(&colorgradingButton);
volumetricCloudsWeatherMapButton.Create("Load Volumetric Clouds Weather Map");
volumetricCloudsWeatherMapButton.SetTooltip("Load a weather map for volumetric clouds. Red channel is coverage, green is type and blue is water density (rain).");
volumetricCloudsWeatherMapButton.SetSize(XMFLOAT2(mod_wid, hei));
volumetricCloudsWeatherMapButton.SetPos(XMFLOAT2(mod_x, y += step));
volumetricCloudsWeatherMapButton.OnClick([=](wi::gui::EventArgs args) {
auto& weather = GetWeather();
if (!weather.volumetricCloudsWeatherMap.IsValid())
{
wi::helper::FileDialogParams params;
params.type = wi::helper::FileDialogParams::OPEN;
params.description = "Texture";
params.extensions = wi::resourcemanager::GetSupportedImageExtensions();
wi::helper::FileDialog(params, [=](std::string fileName) {
wi::eventhandler::Subscribe_Once(wi::eventhandler::EVENT_THREAD_SAFE_POINT, [=](uint64_t userdata) {
auto& weather = GetWeather();
weather.volumetricCloudsWeatherMapName = fileName;
weather.volumetricCloudsWeatherMap = wi::resourcemanager::Load(fileName, wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA);
volumetricCloudsWeatherMapButton.SetText(wi::helper::GetFileNameFromPath(fileName));
});
});
}
else
{
weather.volumetricCloudsWeatherMap = {};
weather.volumetricCloudsWeatherMapName.clear();
volumetricCloudsWeatherMapButton.SetText("Load Volumetric Clouds Weather Map");
}
});
AddWidget(&volumetricCloudsWeatherMapButton);
// Ocean params:
@@ -519,10 +487,8 @@ void WeatherWindow::Create(EditorComponent* _editor)
weather.ambient = XMFLOAT3(33.0f / 255.0f, 47.0f / 255.0f, 127.0f / 255.0f);
weather.horizon = XMFLOAT3(101.0f / 255.0f, 101.0f / 255.0f, 227.0f / 255.0f);
weather.zenith = XMFLOAT3(99.0f / 255.0f, 133.0f / 255.0f, 255.0f / 255.0f);
weather.cloudiness = 0.4f;
weather.fogStart = 100;
weather.fogEnd = 1000;
weather.fogHeightSky = 0;
InvalidateProbes();
@@ -538,11 +504,9 @@ void WeatherWindow::Create(EditorComponent* _editor)
auto& weather = GetWeather();
weather.ambient = XMFLOAT3(86.0f / 255.0f, 29.0f / 255.0f, 29.0f / 255.0f);
weather.horizon = XMFLOAT3(121.0f / 255.0f, 28.0f / 255.0f, 22.0f / 255.0f);
weather.zenith = XMFLOAT3(146.0f / 255.0f, 51.0f / 255.0f, 51.0f / 255.0f);
weather.cloudiness = 0.36f;
weather.zenith = XMFLOAT3(80.0f / 255.0f, 10.0f / 255.0f, 10.0f / 255.0f);
weather.fogStart = 50;
weather.fogEnd = 600;
weather.fogHeightSky = 0;
InvalidateProbes();
@@ -559,10 +523,8 @@ void WeatherWindow::Create(EditorComponent* _editor)
weather.ambient = XMFLOAT3(0.1f, 0.1f, 0.1f);
weather.horizon = XMFLOAT3(0.38f, 0.38f, 0.38f);
weather.zenith = XMFLOAT3(0.42f, 0.42f, 0.42f);
weather.cloudiness = 0.75f;
weather.fogStart = 0;
weather.fogEnd = 500;
weather.fogHeightSky = 0;
InvalidateProbes();
@@ -577,12 +539,10 @@ void WeatherWindow::Create(EditorComponent* _editor)
auto& weather = GetWeather();
weather.ambient = XMFLOAT3(12.0f / 255.0f, 21.0f / 255.0f, 77.0f / 255.0f);
weather.horizon = XMFLOAT3(10.0f / 255.0f, 33.0f / 255.0f, 70.0f / 255.0f);
weather.zenith = XMFLOAT3(4.0f / 255.0f, 20.0f / 255.0f, 51.0f / 255.0f);
weather.cloudiness = 0.28f;
weather.horizon = XMFLOAT3(2.0f / 255.0f, 10.0f / 255.0f, 20.0f / 255.0f);
weather.zenith = XMFLOAT3(0, 0, 0);
weather.fogStart = 10;
weather.fogEnd = 400;
weather.fogHeightSky = 0;
InvalidateProbes();
@@ -599,11 +559,8 @@ void WeatherWindow::Create(EditorComponent* _editor)
weather.ambient = XMFLOAT3(0, 0, 0);
weather.horizon = XMFLOAT3(1, 1, 1);
weather.zenith = XMFLOAT3(1, 1, 1);
weather.SetSimpleSky(true);
weather.cloudiness = 0;
weather.fogStart = 1000000;
weather.fogEnd = 1000000;
weather.fogHeightSky = 0;
InvalidateProbes();
@@ -712,18 +669,16 @@ void WeatherWindow::Update()
colorgradingButton.SetText(wi::helper::GetFileNameFromPath(weather.colorGradingMapName));
}
if (!weather.volumetricCloudsWeatherMapName.empty())
{
volumetricCloudsWeatherMapButton.SetText(wi::helper::GetFileNameFromPath(weather.volumetricCloudsWeatherMapName));
}
heightFogCheckBox.SetCheck(weather.IsHeightFog());
fogStartSlider.SetValue(weather.fogStart);
fogEndSlider.SetValue(weather.fogEnd);
fogHeightStartSlider.SetValue(weather.fogHeightStart);
fogHeightEndSlider.SetValue(weather.fogHeightEnd);
fogHeightSkySlider.SetValue(weather.fogHeightSky);
cloudinessSlider.SetValue(weather.cloudiness);
cloudScaleSlider.SetValue(weather.cloudScale);
cloudSpeedSlider.SetValue(weather.cloudSpeed);
cloudShadowAmountSlider.SetValue(weather.cloud_shadow_amount);
cloudShadowScaleSlider.SetValue(weather.cloud_shadow_scale);
cloudShadowSpeedSlider.SetValue(weather.cloud_shadow_speed);
windSpeedSlider.SetValue(weather.windSpeed);
windWaveSizeSlider.SetValue(weather.windWaveSize);
windRandomnessSlider.SetValue(weather.windRandomness);
@@ -751,7 +706,6 @@ void WeatherWindow::Update()
break;
}
simpleskyCheckBox.SetCheck(weather.IsSimpleSky());
realisticskyCheckBox.SetCheck(weather.IsRealisticSky());
ocean_enabledCheckBox.SetCheck(weather.IsOceanEnabled());
@@ -765,13 +719,13 @@ void WeatherWindow::Update()
ocean_toleranceSlider.SetValue(weather.oceanParameters.surfaceDisplacementTolerance);
volumetricCloudsCheckBox.SetCheck(weather.IsVolumetricClouds());
volumetricCloudsShadowsCheckBox.SetCheck(weather.IsVolumetricCloudsShadows());
coverageAmountSlider.SetValue(weather.volumetricCloudParameters.CoverageAmount);
coverageMinimumSlider.SetValue(weather.volumetricCloudParameters.CoverageMinimum);
}
else
{
scene.weather = {};
scene.weather.SetSimpleSky(true);
scene.weather.ambient = XMFLOAT3(0.5f, 0.5f, 0.5f);
scene.weather.zenith = default_sky_zenith;
scene.weather.horizon = default_sky_horizon;
@@ -846,7 +800,6 @@ void WeatherWindow::ResizeLayout()
};
add_fullwidth(primaryButton);
add_right(simpleskyCheckBox);
add_right(realisticskyCheckBox);
add(colorComboBox);
add_fullwidth(colorPicker);
@@ -857,13 +810,6 @@ void WeatherWindow::ResizeLayout()
add(fogEndSlider);
add(fogHeightStartSlider);
add(fogHeightEndSlider);
add(fogHeightSkySlider);
add(cloudinessSlider);
add(cloudScaleSlider);
add(cloudSpeedSlider);
add(cloudShadowAmountSlider);
add(cloudShadowScaleSlider);
add(cloudShadowSpeedSlider);
add(windSpeedSlider);
add(windMagnitudeSlider);
add(windDirectionSlider);
@@ -875,8 +821,10 @@ void WeatherWindow::ResizeLayout()
y += jump;
add_right(volumetricCloudsCheckBox);
add_right(volumetricCloudsShadowsCheckBox);
add(coverageAmountSlider);
add(coverageMinimumSlider);
add_fullwidth(volumetricCloudsWeatherMapButton);
y += jump;
+2 -8
View File
@@ -27,13 +27,6 @@ public:
wi::gui::Slider fogEndSlider;
wi::gui::Slider fogHeightStartSlider;
wi::gui::Slider fogHeightEndSlider;
wi::gui::Slider fogHeightSkySlider;
wi::gui::Slider cloudinessSlider;
wi::gui::Slider cloudScaleSlider;
wi::gui::Slider cloudSpeedSlider;
wi::gui::Slider cloudShadowAmountSlider;
wi::gui::Slider cloudShadowScaleSlider;
wi::gui::Slider cloudShadowSpeedSlider;
wi::gui::Slider windSpeedSlider;
wi::gui::Slider windMagnitudeSlider;
wi::gui::Slider windDirectionSlider;
@@ -41,7 +34,6 @@ public:
wi::gui::Slider windRandomnessSlider;
wi::gui::Slider skyExposureSlider;
wi::gui::Slider starsSlider;
wi::gui::CheckBox simpleskyCheckBox;
wi::gui::CheckBox realisticskyCheckBox;
wi::gui::Button skyButton;
wi::gui::Button colorgradingButton;
@@ -63,8 +55,10 @@ public:
// volumetric clouds:
wi::gui::CheckBox volumetricCloudsCheckBox;
wi::gui::CheckBox volumetricCloudsShadowsCheckBox;
wi::gui::Slider coverageAmountSlider;
wi::gui::Slider coverageMinimumSlider;
wi::gui::Button volumetricCloudsWeatherMapButton;
wi::gui::Button preset0Button;
wi::gui::Button preset1Button;
-1
View File
@@ -384,7 +384,6 @@ void TestsRenderer::Load()
weather.ambient = XMFLOAT3(0.2f, 0.2f, 0.2f);
weather.horizon = XMFLOAT3(0.38f, 0.38f, 0.38f);
weather.zenith = XMFLOAT3(0.42f, 0.42f, 0.42f);
weather.cloudiness = 0.75f;
wi::scene::GetScene().Merge(scene); // add lodaded scene to global scene
}
+1 -1
View File
@@ -12,7 +12,7 @@ dofile("../Content/scripts/camera_animation_repeat.lua");
ToggleCameraAnimation();
-- Load an image:
local sprite = Sprite("../logo_small.png");
local sprite = Sprite("../Content/logo_small.png");
sprite.SetParams(ImageParams(100,100,128,128));
-- Set this image as renderable to the active component:
local component = main.GetActivePath();
+1
View File
@@ -1,5 +1,6 @@
This file contains changelog of wi::Archive versions
86: serialized volumetric clouds weather map, removed unused values and remapped values from VolumetricCloudParameters
85: DDGI serialization
84: component library serialization
83: physical light units
+7 -4
View File
@@ -150,13 +150,16 @@ wi::vector<ShaderEntry> shaders = {
{"blur_bilateral_unorm1CS", wi::graphics::ShaderStage::CS },
{"voxelSceneCopyClearCS_TemporalSmoothing", wi::graphics::ShaderStage::CS },
{"normalsfromdepthCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_shapenoiseCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_detailnoiseCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_curlnoiseCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_weathermapCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_detailnoiseCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_renderCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_renderCS_capture", wi::graphics::ShaderStage::CS },
{"volumetricCloud_renderCS_capture_MSAA", wi::graphics::ShaderStage::CS },
{"volumetricCloud_reprojectCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_temporalCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_shadow_filterCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_shadow_renderCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_shapenoiseCS", wi::graphics::ShaderStage::CS },
{"volumetricCloud_weathermapCS", wi::graphics::ShaderStage::CS },
{"shadingRateClassificationCS", wi::graphics::ShaderStage::CS },
{"shadingRateClassificationCS_DEBUG", wi::graphics::ShaderStage::CS },
{"skyAtmosphere_transmittanceLutCS", wi::graphics::ShaderStage::CS },
+26 -1
View File
@@ -632,6 +632,7 @@ enum SHADER_ENTITY_TYPE
};
static const uint ENTITY_FLAG_LIGHT_STATIC = 1 << 0;
static const uint ENTITY_FLAG_LIGHT_VOLUMETRICCLOUDS = 1 << 1;
static const uint SHADER_ENTITY_COUNT = 256;
static const uint SHADER_ENTITY_TILE_BUCKET_COUNT = SHADER_ENTITY_COUNT / 32;
@@ -653,7 +654,6 @@ static const uint OPTION_BIT_TRANSPARENTSHADOWS_ENABLED = 1 << 1;
static const uint OPTION_BIT_VOXELGI_ENABLED = 1 << 2;
static const uint OPTION_BIT_VOXELGI_REFLECTIONS_ENABLED = 1 << 3;
static const uint OPTION_BIT_VOXELGI_RETARGETTED = 1 << 4;
static const uint OPTION_BIT_SIMPLE_SKY = 1 << 5;
static const uint OPTION_BIT_REALISTIC_SKY = 1 << 6;
static const uint OPTION_BIT_HEIGHT_FOG = 1 << 7;
static const uint OPTION_BIT_RAYTRACED_SHADOWS = 1 << 8;
@@ -662,6 +662,7 @@ static const uint OPTION_BIT_SURFELGI_ENABLED = 1 << 10;
static const uint OPTION_BIT_DISABLE_ALBEDO_MAPS = 1 << 11;
static const uint OPTION_BIT_FORCE_DIFFUSE_LIGHTING = 1 << 12;
static const uint OPTION_BIT_STATIC_SKY_HDR = 1 << 13;
static const uint OPTION_BIT_VOLUMETRICCLOUDS_SHADOWS = 1 << 14;
// ---------- Common Constant buffers: -----------------
@@ -680,6 +681,13 @@ struct FrameCB
uint2 shadow_atlas_resolution;
float2 shadow_atlas_resolution_rcp;
float4x4 cloudShadowLightSpaceMatrix;
float4x4 cloudShadowLightSpaceMatrixInverse;
float cloudShadowFarPlaneKm;
int texture_volumetricclouds_shadow_index;
float2 padding0;
float3 voxelradiance_center; // center of the voxel grid in world space units
float voxelradiance_max_distance; // maximum raymarch distance for voxel GI in world-space
@@ -840,6 +848,7 @@ struct LensFlarePush
struct CubemapRenderCam
{
float4x4 view_projection;
float4x4 inverse_view_projection;
uint4 properties;
};
CBUFFER(CubemapRenderCB, CBSLOT_RENDERER_CUBEMAPRENDER)
@@ -928,5 +937,21 @@ struct SkinningPushConstants
int so_tan;
};
struct VolumetricCloudCapturePushConstants
{
uint2 resolution;
float2 resolution_rcp;
uint arrayIndex;
int texture_input;
int texture_output;
int MaxStepCount;
float LODMin;
float ShadowSampleCount;
float GroundContributionSampleCount;
float padding;
};
#endif // WI_SHADERINTEROP_RENDERER_H
+23 -44
View File
@@ -95,7 +95,7 @@ struct VolumetricCloudParameters
float3 Albedo; // Cloud albedo is normally very close to 1
float CloudAmbientGroundMultiplier; // [0; 1] Amount of ambient light to reach the bottom of clouds
float3 ExtinctionCoefficient; // * 0.05 looks good too
float3 ExtinctionCoefficient;
float BeerPowder;
float BeerPowderPower;
@@ -120,12 +120,8 @@ struct VolumetricCloudParameters
float WeatherScale;
float CurlScale;
float ShapeNoiseHeightGradientAmount;
float ShapeNoiseMultiplier;
float2 ShapeNoiseMinMax;
float ShapeNoisePower;
float DetailNoiseModifier;
float padding0;
float DetailNoiseHeightFraction;
float CurlNoiseModifier;
@@ -133,7 +129,7 @@ struct VolumetricCloudParameters
float CoverageMinimum;
float TypeAmount;
float TypeOverall;
float TypeMinimum;
float AnvilAmount; // Anvil clouds disabled by default.
float AnvilOverhangHeight;
@@ -143,7 +139,7 @@ struct VolumetricCloudParameters
float WindAngle;
float WindUpAmount;
float2 padding0;
float2 padding1;
float CoverageWindSpeed;
float CoverageWindAngle;
@@ -161,21 +157,19 @@ struct VolumetricCloudParameters
float LODDistance; // After a certain distance, noises will get higher LOD
float LODMin; //
float BigStepMarch; // How long inital rays should be until they hit something. Lower values may ives a better image but may be slower.
float BigStepMarch; // How long inital rays should be until they hit something. Lower values may give a better image but may be slower.
float TransmittanceThreshold; // Default: 0.005. If the clouds transmittance has reached it's desired opacity, there's no need to keep raymarching for performance.
float2 padding1;
float2 padding2;
float ShadowSampleCount;
float GroundContributionSampleCount;
void init()
{
// Lighting
Albedo = float3(0.9f, 0.9f, 0.9f);
CloudAmbientGroundMultiplier = 0.75f;
ExtinctionCoefficient = float3(0.71f * 0.1f, 0.86f * 0.1f, 1.0f * 0.1f);
ExtinctionCoefficient = float3(0.71f * 0.05f, 0.86f * 0.05f, 1.0f * 0.05f);
BeerPowder = 20.0f;
BeerPowderPower = 0.5f;
PhaseG = 0.5f; // [-0.999; 0.999]
@@ -185,7 +179,7 @@ struct VolumetricCloudParameters
MultiScatteringExtinction = 0.1f;
MultiScatteringEccentricity = 0.2f;
ShadowStepLength = 3000.0f;
HorizonBlendAmount = 1.25f;
HorizonBlendAmount = 0.0000125f;
HorizonBlendPower = 2.0f;
WeatherDensityAmount = 0.0f;
@@ -194,24 +188,19 @@ struct VolumetricCloudParameters
CloudThickness = 4000.0f;
SkewAlongWindDirection = 700.0f;
TotalNoiseScale = 1.0f;
DetailScale = 5.0f;
WeatherScale = 0.0625f;
CurlScale = 7.5f;
ShapeNoiseHeightGradientAmount = 0.2f;
ShapeNoiseMultiplier = 0.8f;
ShapeNoisePower = 6.0f;
ShapeNoiseMinMax = float2(0.25f, 1.1f);
TotalNoiseScale = 0.0006f;
DetailScale = 2.0f;
WeatherScale = 0.000025f;
CurlScale = 0.3f;
DetailNoiseModifier = 0.2f;
DetailNoiseHeightFraction = 10.0f;
CurlNoiseModifier = 550.0f;
CurlNoiseModifier = 500.0f;
CoverageAmount = 2.0f;
CoverageMinimum = 1.05f;
CoverageAmount = 1.0f;
CoverageMinimum = 0.0f;
TypeAmount = 1.0f;
TypeOverall = 0.0f;
TypeMinimum = 0.0f;
AnvilAmount = 0.0f;
AnvilOverhangHeight = 3.0f;
@@ -225,21 +214,21 @@ struct VolumetricCloudParameters
// Cloud types
// 4 positions of a black, white, white, black gradient
CloudGradientSmall = float4(0.02f, 0.07f, 0.12f, 0.28f);
CloudGradientMedium = float4(0.02f, 0.07f, 0.39f, 0.59f);
CloudGradientSmall = float4(0.02f, 0.1f, 0.12f, 0.28f);
CloudGradientMedium = float4(0.02f, 0.1f, 0.39f, 0.59f);
CloudGradientLarge = float4(0.02f, 0.07f, 0.88f, 1.0f);
// Performance
MaxStepCount = 128;
MaxStepCount = 96;
MaxMarchingDistance = 30000.0f;
InverseDistanceStepCount = 15000.0f;
RenderDistance = 70000.0f;
LODDistance = 25000.0f;
LODMin = 0.0f;
BigStepMarch = 3.0f;
BigStepMarch = 1.0f;
TransmittanceThreshold = 0.005f;
ShadowSampleCount = 5.0f;
GroundContributionSampleCount = 2.0f;
GroundContributionSampleCount = 3.0f;
}
#ifdef __cplusplus
@@ -254,11 +243,6 @@ struct ShaderFog
float end;
float height_start;
float height_end;
float height_sky;
float padding0;
float padding1;
float padding2;
};
struct ShaderWind
@@ -293,15 +277,10 @@ struct ShaderWeather
float sky_exposure;
float3 zenith;
float cloudiness;
float padding0;
float3 ambient;
float cloud_scale;
float cloud_speed;
float cloud_shadow_amount;
float cloud_shadow_scale;
float cloud_shadow_speed;
float padding1;
float4x4 stars_rotation;
+16 -1
View File
@@ -1125,7 +1125,22 @@
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)visibility_velocityCS.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_temporalCS.hlsl" />
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_renderCS_capture.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_renderCS_capture_MSAA.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_shadow_filterCS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_shadow_renderCS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compute</ShaderType>
<ShaderModel Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">4.0</ShaderModel>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetriclight_directionalVS.hlsl">
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Vertex</ShaderType>
<ShaderType Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Vertex</ShaderType>
@@ -947,9 +947,6 @@
<FxCompile Include="$(MSBuildThisFileDirectory)fsr_sharpenCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_temporalCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)surfel_coverageCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
@@ -1055,6 +1052,18 @@
<FxCompile Include="$(MSBuildThisFileDirectory)impostor_prepareCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_renderCS_capture.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_shadow_renderCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_shadow_filterCS.hlsl">
<Filter>CS</Filter>
</FxCompile>
<FxCompile Include="$(MSBuildThisFileDirectory)volumetricCloud_renderCS_capture_MSAA.hlsl">
<Filter>CS</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)ShaderInterop.h">
@@ -9,6 +9,5 @@ float4 main(PixelInput input) : SV_TARGET
{
float3 normal = normalize(input.nor);
float3 sky = DEGAMMA(texture_sky.SampleLevel(sampler_linear_clamp, normal, 0).rgb);
CalculateClouds(sky, normal, false);
return float4(sky, 1);
}
+11
View File
@@ -210,6 +210,9 @@ struct PrimitiveID
#define sqr(a) ((a)*(a))
#define pow5(x) pow(x, 5)
#define M_TO_SKY_UNIT 0.001f // Engine units are in meters
#define SKY_UNIT_TO_M (1.0 / M_TO_SKY_UNIT)
// attribute computation with barycentric interpolation
// a0 : attribute at triangle corner 0
// a1 : attribute at triangle corner 1
@@ -571,6 +574,14 @@ inline float compute_lineardepth(in float z)
return compute_lineardepth(z, GetCamera().z_near, GetCamera().z_far);
}
// Computes post-projection depth from linear depth
inline float compute_inverse_lineardepth(in float lin, in float near, in float far)
{
float z_n = ((lin - 2 * far) * near + far * lin) / (lin * near - far * lin);
float z = (z_n + 1) / 2;
return z;
}
inline float3x3 get_tangentspace(in float3 normal)
{
// Choose a helper vector for the cross product
+3 -5
View File
@@ -131,13 +131,11 @@ inline void light_directional(in ShaderEntity light, in Surface surface, inout L
[branch]
if (light.IsCastingShadow() && surface.IsReceiveShadow())
{
if (GetWeather().cloud_shadow_amount > 0)
if (GetFrame().options & OPTION_BIT_VOLUMETRICCLOUDS_SHADOWS)
{
// Fake cloud shadows:
float cloud_shadow = noise_simplex_2D(surface.P.xz * GetWeather().cloud_shadow_scale + GetTime() * GetWeather().cloud_shadow_speed) * 0.5 + 0.5;
shadow *= saturate(cloud_shadow + 1 - GetWeather().cloud_shadow_amount * 2);
shadow *= shadow_2D_volumetricclouds(surface.P);
}
#ifdef SHADOW_MASK_ENABLED
[branch]
if ((GetFrame().options & OPTION_BIT_RAYTRACED_SHADOWS) == 0 || GetCamera().texture_rtshadow_index < 0)
+8 -1
View File
@@ -2,6 +2,7 @@
#define DISABLE_VOXELGI
#include "objectHF.hlsli"
#include "voxelHF.hlsli"
#include "volumetricCloudsHF.hlsli"
// Note: the voxelizer uses an overall simplified material and lighting model (no normal maps, only diffuse light and emissive)
@@ -102,10 +103,16 @@ void main(PSInput input)
float3 ShPos = mul(load_entitymatrix(light.GetMatrixIndex() + cascade), float4(P, 1)).xyz; // ortho matrix, no divide by .w
float3 ShTex = ShPos.xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f;
[branch] if ((saturate(ShTex.x) == ShTex.x) && (saturate(ShTex.y) == ShTex.y) && (saturate(ShTex.z) == ShTex.z))
[branch]
if ((saturate(ShTex.x) == ShTex.x) && (saturate(ShTex.y) == ShTex.y) && (saturate(ShTex.z) == ShTex.z))
{
lightColor *= shadow_2D(light, ShPos, ShTex.xy, cascade);
}
if (GetFrame().options & OPTION_BIT_VOLUMETRICCLOUDS_SHADOWS)
{
lightColor *= shadow_2D_volumetricclouds(P);
}
}
lighting.direct.diffuse += lightColor;
+22 -26
View File
@@ -1,6 +1,7 @@
#ifndef WI_SKYATMOSPHERE_HF
#define WI_SKYATMOSPHERE_HF
#include "globals.hlsli"
#include "volumetricCloudsHF.hlsli"
/*
*
@@ -14,13 +15,11 @@
static const float2 transmittanceLUTRes = float2(256, 64);
static const float2 multiScatteringLUTRes = float2(32, 32);
static const float2 skyViewLUTRes = float2(192.0, 104);
static const float2 skyViewLUTRes = float2(192, 104);
static const float2 skyLuminanceLUTRes = float2(1, 1);
#define USE_CornetteShanks
#define M_TO_SKY_UNIT 0.001f // Engine units are in meters
#define SKY_UNIT_TO_M (1.0 / M_TO_SKY_UNIT)
#define PLANET_RADIUS_OFFSET 0.001f // Float accuracy offset in Sky unit (km, so this is 1m)
////////////////////////////////////////////////////////////
@@ -470,12 +469,12 @@ struct SamplingParameters
float sampleCountIni; // Used when variableSampleCount is false
float2 rayMarchMinMaxSPP;
float distanceSPPMaxInv;
//bool perPixelNoise;
bool perPixelNoise;
};
SingleScatteringResult IntegrateScatteredLuminance(
in AtmosphereParameters atmosphere, in float2 pixPos, in float3 worldPosition, in float3 worldDirection, in float3 sunDirection, in float3 sunIlluminance,
in SamplingParameters sampling, in bool ground, in float3 depthBufferWorldPos, in bool opaque, in bool mieRayPhase, in bool multiScatteringApprox,
in AtmosphereParameters atmosphere, in float2 pixelPosition, in float3 worldPosition, in float3 worldDirection, in float3 sunDirection, in float3 sunIlluminance,
in SamplingParameters sampling, in float tDepth, in bool opaque, in bool ground, in bool mieRayPhase, in bool multiScatteringApprox, in bool volumetricCloudShadow,
in Texture2D<float4> transmittanceLutTexture, in Texture2D<float4> multiScatteringLUTTexture, in float tMaxMax = 9000000.0f)
{
SingleScatteringResult result = (SingleScatteringResult) 0;
@@ -512,19 +511,10 @@ SingleScatteringResult IntegrateScatteredLuminance(
{
if (opaque)
{
float3 depthBufferWorldPosKm = depthBufferWorldPos * M_TO_SKY_UNIT;
float3 traceStartWorldPosKm = worldPosition + atmosphere.planetCenter; // Planet center is in km
float3 traceStartToSurfaceWorldKm = depthBufferWorldPosKm - traceStartWorldPosKm;
float tDepth = length(traceStartToSurfaceWorldKm); // Apply earth offset to go back to origin as top of earth mode.
if (tDepth < tMax)
{
tMax = tDepth;
}
//if (dot(worldDirection, traceStartToSurfaceWorldKm) < 0.0)
//{
// return result;
//}
}
tMax = min(tMax, tMaxMax);
@@ -579,16 +569,16 @@ SingleScatteringResult IntegrateScatteredLuminance(
t1 = tMaxFloor * t1;
}
//if (Sampling.PerPixelNoise)
//{
// t = t0 + (t1 - t0) * InterleavedGradientNoise(pixPos, GetFrame().frame_count % 16);
//}
//else
//{
// t = t0 + (t1 - t0) * SampleSegmentT;
//}
t = t0 + (t1 - t0) * sampleSegmentT;
// Reduce sample count with noise and Temporal AA:
if (sampling.perPixelNoise)
{
t = t0 + (t1 - t0) * InterleavedGradientNoise(pixelPosition, GetFrame().frame_count);
}
else
{
t = t0 + (t1 - t0) * sampleSegmentT;
}
dt = t1 - t0;
}
else
@@ -625,6 +615,12 @@ SingleScatteringResult IntegrateScatteredLuminance(
float tEarth = RaySphereIntersectNearest(P, sunDirection, earthO + PLANET_RADIUS_OFFSET * UpVector, atmosphere.bottomRadius);
float earthShadow = tEarth >= 0.0f ? 0.0f : 1.0f;
// Volumetric cloud shadow
if (volumetricCloudShadow && GetFrame().options & OPTION_BIT_VOLUMETRICCLOUDS_SHADOWS)
{
earthShadow *= shadow_2D_volumetricclouds(P * SKY_UNIT_TO_M + atmosphere.planetCenter * SKY_UNIT_TO_M);
}
// Dual scattering for multi scattering
float3 multiScatteredLuminance = 0.0f;
@@ -16,7 +16,6 @@ void main(uint3 DTid : SV_DispatchThreadID)
{
float2 pixelPosition = float2(DTid.xy) + 0.5;
float2 uv = pixelPosition * rcp(multiScatteringLUTRes);
uv = float2(FromSubUvsToUnit(uv.x, multiScatteringLUTRes.x), FromSubUvsToUnit(uv.y, multiScatteringLUTRes.y));
@@ -39,11 +38,12 @@ void main(uint3 DTid : SV_DispatchThreadID)
sampling.variableSampleCount = false;
sampling.sampleCountIni = 20; // a minimum set of step is required for accuracy unfortunately
}
const bool ground = true;
const float depthBufferWorldPos = 0.0;
const float tDepth = 0.0;
const bool opaque = false;
const bool ground = true;
const bool mieRayPhase = false;
const bool multiScatteringApprox = false;
const bool volumetricCloudShadow = false;
const float sphereSolidAngle = 4.0 * PI;
const float isotropicPhase = 1.0 / sphereSolidAngle;
@@ -68,7 +68,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
worldDirection.z = cosPhi;
SingleScatteringResult result = IntegrateScatteredLuminance(
atmosphere, pixelPosition, worldPosition, worldDirection, sunDirection, sunIlluminance,
sampling, ground, depthBufferWorldPos, opaque, mieRayPhase, multiScatteringApprox, transmittanceLUT, multiScatteringLUT);
sampling, tDepth, opaque, ground, mieRayPhase, multiScatteringApprox, volumetricCloudShadow, transmittanceLUT, multiScatteringLUT);
MultiScatAs1SharedMem[DTid.z] = result.multiScatAs1 * sphereSolidAngle / (sqrtSample * sqrtSample);
LSharedMem[DTid.z] = result.L * sphereSolidAngle / (sqrtSample * sqrtSample);
@@ -14,8 +14,7 @@ groupshared float3 SkyLuminanceSharedMem[64];
void main(uint3 DTid : SV_DispatchThreadID)
{
float2 pixelPosition = float2(DTid.xy) + 0.5;
float2 uv = pixelPosition * rcp(multiScatteringLUTRes);
float2 uv = pixelPosition * rcp(skyLuminanceLUTRes);
AtmosphereParameters atmosphere = GetWeather().atmosphere;
@@ -32,11 +31,12 @@ void main(uint3 DTid : SV_DispatchThreadID)
sampling.variableSampleCount = false;
sampling.sampleCountIni = 10; // Should be enough since we're taking an approximation of luminance around a point
}
const bool ground = false;
const float depthBufferWorldPos = 0.0;
const float tDepth = 0.0;
const bool opaque = false;
const bool ground = false;
const bool mieRayPhase = false; // Perhabs?
const bool multiScatteringApprox = true;
const bool volumetricCloudShadow = false;
const float sphereSolidAngle = 4.0 * PI;
const float isotropicPhase = 1.0 / sphereSolidAngle;
@@ -61,7 +61,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
worldDirection.z = cosPhi;
SingleScatteringResult result = IntegrateScatteredLuminance(
atmosphere, pixelPosition, worldPosition, worldDirection, sunDirection, sunIlluminance,
sampling, ground, depthBufferWorldPos, opaque, mieRayPhase, multiScatteringApprox, transmittanceLUT, multiScatteringLUT);
sampling, tDepth, opaque, ground, mieRayPhase, multiScatteringApprox, volumetricCloudShadow, transmittanceLUT, multiScatteringLUT);
SkyLuminanceSharedMem[DTid.z] = result.L * sphereSolidAngle / (sqrtSample * sqrtSample);
}
@@ -57,15 +57,17 @@ void main(uint3 DTid : SV_DispatchThreadID)
sampling.sampleCountIni = 30;
sampling.rayMarchMinMaxSPP = float2(4, 14);
sampling.distanceSPPMaxInv = 0.01;
sampling.perPixelNoise = false;
}
const float tDepth = 0.0;
const bool ground = false;
const float depthBufferWorldPos = 0.0;
const bool opaque = false;
const bool mieRayPhase = true;
const bool multiScatteringApprox = true;
const bool volumetricCloudShadow = false;
SingleScatteringResult ss = IntegrateScatteredLuminance(
atmosphere, pixelPosition, worldPosition, worldDirection, sunDirection, sunIlluminance,
sampling, ground, depthBufferWorldPos, opaque, mieRayPhase, multiScatteringApprox, transmittanceLUT, multiScatteringLUT);
sampling, tDepth, opaque, ground, mieRayPhase, multiScatteringApprox, volumetricCloudShadow, transmittanceLUT, multiScatteringLUT);
float3 L = ss.L;
@@ -29,14 +29,15 @@ void main(uint3 DTid : SV_DispatchThreadID)
sampling.variableSampleCount = false;
sampling.sampleCountIni = 40.0f; // Can go a low as 10 sample but energy lost starts to be visible.
}
const bool ground = false;
const float depthBufferWorldPos = 0.0;
const float tDepth = 0.0;
const bool opaque = false;
const bool ground = false;
const bool mieRayPhase = false;
const bool multiScatteringApprox = false;
const bool volumetricCloudShadow = false;
SingleScatteringResult ss = IntegrateScatteredLuminance(
atmosphere, pixelPosition, worldPosition, worldDirection, sunDirection, sunIlluminance,
sampling, ground, depthBufferWorldPos, opaque, mieRayPhase, multiScatteringApprox, transmittanceLUT, multiScatteringLUT);
sampling, tDepth, opaque, ground, mieRayPhase, multiScatteringApprox, volumetricCloudShadow, transmittanceLUT, multiScatteringLUT);
float3 transmittance = exp(-ss.opticalDepth);
+12 -177
View File
@@ -56,16 +56,18 @@ float3 AccurateAtmosphericScattering(Texture2D<float4> skyViewLutTexture, Textur
sampling.sampleCountIni = 0.0f;
sampling.rayMarchMinMaxSPP = float2(4, 14);
sampling.distanceSPPMaxInv = 0.01;
}
const bool ground = false;
const float depthBufferWorldPos = 0.0;
sampling.perPixelNoise = false;
}
const float2 pixelPosition = float2(0.0, 0.0);
const float tDepth = 0.0;
const bool opaque = false;
const bool ground = false;
const bool mieRayPhase = true;
const bool multiScatteringApprox = true;
const float2 pixPos = float2(0, 0);
const bool volumetricCloudShadow = false;
SingleScatteringResult ss = IntegrateScatteredLuminance(
atmosphere, pixPos, worldPosition, worldDirection, sunDirection, sunIlluminance,
sampling, ground, depthBufferWorldPos, opaque, mieRayPhase, multiScatteringApprox, transmittanceLUT, multiScatteringLUT);
atmosphere, pixelPosition, worldPosition, worldDirection, sunDirection, sunIlluminance,
sampling, tDepth, opaque, ground, mieRayPhase, multiScatteringApprox, volumetricCloudShadow, transmittanceLUT, multiScatteringLUT);
luminance = ss.L;
}
@@ -91,166 +93,11 @@ float3 AccurateAtmosphericScattering(Texture2D<float4> skyViewLutTexture, Textur
return totalColor;
}
float2 hash(float2 p)
{
p = float2(dot(p, float2(127.1, 311.7)), dot(p, float2(269.5, 183.3)));
return -1.0 + 2.0 * frac(sin(p) * 43758.5453123);
}
float noise(in float2 p)
{
const float K1 = 0.366025404; // (sqrt(3)-1)/2;
const float K2 = 0.211324865; // (3-sqrt(3))/6;
float2 i = floor(p + (p.x + p.y) * K1);
float2 a = p - i + (i.x + i.y) * K2;
float2 o = (a.x > a.y) ? float2(1.0, 0.0) : float2(0.0, 1.0); //float2 of = 0.5 + 0.5*float2(sign(a.x-a.y), sign(a.y-a.x));
float2 b = a - o + K2;
float2 c = a - 1.0 + 2.0 * K2;
float3 h = max(0.5 - float3(dot(a, a), dot(b, b), dot(c, c)), 0.0);
float3 n = h * h * h * h * float3(dot(a, hash(i + 0.0)), dot(b, hash(i + o)), dot(c, hash(i + 1.0)));
return dot(n, float3(70.0, 70.0, 70.0));
}
float3 CustomAtmosphericScattering(float3 V, float3 sunDirection, float3 sunColor, bool sun_enabled, bool dark_enabled)
{
const float3 skyColor = GetZenithColor();
const bool sunPresent = any(sunColor);
const bool sunDisc = sun_enabled && sunPresent;
const float zenith = V.y; // how much is above (0: horizon, 1: directly above)
const float sunScatter = saturate(sunDirection.y + 0.1f); // how much the sun is directly above. Even if sunis at horizon, we add a constant scattering amount so that light still scatters at horizon
const float atmosphereDensity = 0.5 + GetWeather().fog.height_sky; // constant of air density, or "fog height" as interpreted here (bigger is more obstruction of sun)
const float zenithDensity = atmosphereDensity / pow(max(0.000001f, zenith), 0.75f);
const float sunScatterDensity = atmosphereDensity / pow(max(0.000001f, sunScatter), 0.75f);
const float3 aberration = float3(0.39, 0.57, 1.0); // the chromatic aberration effect on the horizon-zenith fade line
const float3 skyAbsorption = saturate(exp2(aberration * -zenithDensity) * 2.0f); // gradient on horizon
const float3 sunAbsorption = sunPresent ? saturate(sunColor * exp2(aberration * -sunScatterDensity) * 2.0f) : 1; // gradient of sun when it's getting below horizon
const float sunAmount = distance(V, sunDirection); // sun falloff descreasing from mid point
const float rayleigh = sunPresent ? 1.0 + pow(1.0 - saturate(sunAmount), 2.0) * PI * 0.5 : 1;
const float mie_disk = saturate(1.0 - pow(sunAmount, 0.1));
const float3 mie = mie_disk * mie_disk * (3.0 - 2.0 * mie_disk) * 2.0 * PI * sunAbsorption;
float3 totalColor = lerp(GetHorizonColor(), GetZenithColor() * zenithDensity * rayleigh, skyAbsorption);
totalColor = lerp(totalColor * skyAbsorption, totalColor, sunScatter); // when sun goes below horizon, absorb sky color
if (sunDisc)
{
const float3 sun = smoothstep(0.03, 0.026, sunAmount) * sunColor * 50.0 * skyAbsorption; // sun disc
totalColor += sun;
totalColor += mie;
}
totalColor *= (sunAbsorption + length(sunAbsorption)) * 0.5f; // when sun goes below horizon, fade out whole sky
totalColor *= 0.25; // exposure level
if (dark_enabled)
{
totalColor = max(pow(saturate(dot(sunDirection, V)), 64) * sunColor, 0) * skyAbsorption;
}
return totalColor;
}
void CalculateClouds(inout float3 sky, float3 V, bool dark_enabled)
{
if (GetWeather().cloudiness <= 0)
{
return;
}
// Trace a cloud layer plane:
const float3 o = GetCamera().position;
const float3 d = V;
const float3 planeOrigin = float3(0, 1000, 0);
const float3 planeNormal = float3(0, -1, 0);
const float t = trace_plane(o, d, planeOrigin, planeNormal);
if (t < 0)
{
return;
}
const float3 cloudPos = o + d * t;
const float2 cloudUV = cloudPos.xz * GetWeather().cloud_scale;
const float cloudTime = GetFrame().time * GetWeather().cloud_speed;
const float2x2 m = float2x2(1.6, 1.2, -1.2, 1.6);
const uint quality = 8;
// rotate uvs like a flow effect:
float flow = 0;
{
float2 uv = cloudUV * 0.5f;
float amount = 0.1;
for (uint i = 0; i < quality; i++)
{
flow += noise(uv) * amount;
uv = mul(m, uv);
amount *= 0.4;
}
}
// Main shape:
float clouds = 0.0;
{
const float time = cloudTime * 0.2f;
float density = 1.1f;
float2 uv = cloudUV * 0.8f;
uv -= flow - time;
for (uint i = 0; i < quality; i++)
{
clouds += density * noise(uv);
uv = mul(m, uv) + time;
density *= 0.6f;
}
}
// Detail shape:
{
float detail_shape = 0.0;
const float time = cloudTime * 0.1f;
float density = 0.8f;
float2 uv = cloudUV;
uv -= flow - time;
for (uint i = 0; i < quality; i++)
{
detail_shape += abs(density * noise(uv));
uv = mul(m, uv) + time;
density *= 0.7f;
}
clouds *= detail_shape + clouds;
clouds *= detail_shape;
}
// lerp between "choppy clouds" and "uniform clouds". Lower cloudiness will produce choppy clouds, but very high cloudiness will switch to overcast unfiform clouds:
clouds = lerp(clouds * 9.0f * GetWeather().cloudiness + 0.3f, clouds * 0.5f + 0.5f, pow(saturate(GetWeather().cloudiness), 8));
clouds = saturate(clouds - (1 - GetWeather().cloudiness)); // modulate constant cloudiness
clouds *= pow(1 - saturate(length(abs(cloudPos.xz * 0.00001f))), 16); //fade close to horizon
if (dark_enabled)
{
sky *= pow(saturate(1 - clouds), 16.0f); // only sun and clouds. Boost clouds to have nicer sun shafts occlusion
}
else
{
sky = lerp(sky, 1, clouds); // sky and clouds on top
}
}
// Returns sky color modulated by the sun and clouds
// V : view direction
float3 GetDynamicSkyColor(in float3 V, bool sun_enabled = true, bool clouds_enabled = true, bool dark_enabled = false, bool realistic_sky_stationary = false)
{
if (GetFrame().options & OPTION_BIT_SIMPLE_SKY)
{
return lerp(GetHorizonColor(), GetZenithColor(), saturate(V.y * 0.5f + 0.5f)) * GetWeather().sky_exposure;
}
const float3 sunDirection = GetSunDirection();
const float3 sunColor = GetSunColor();
float3 sky = float3(0, 0, 0);
float3 sky = 0;
if (GetFrame().options & OPTION_BIT_REALISTIC_SKY)
{
@@ -261,8 +108,8 @@ float3 GetDynamicSkyColor(in float3 V, bool sun_enabled = true, bool clouds_enab
texture_multiscatteringlut,
GetCamera().position, // Ray origin
V, // Ray direction
sunDirection, // Position of the sun
sunColor, // Sun Color
GetSunDirection(), // Position of the sun
GetSunColor(), // Sun Color
sun_enabled, // Use sun and total
dark_enabled, // Enable dark mode for light shafts etc.
realistic_sky_stationary // Fixed position for ambient and environment capture.
@@ -270,23 +117,11 @@ float3 GetDynamicSkyColor(in float3 V, bool sun_enabled = true, bool clouds_enab
}
else
{
sky = CustomAtmosphericScattering
(
V, // normalized ray direction
sunDirection, // position of the sun
sunColor, // color of the sun, for disc
sun_enabled, // use sun and total
dark_enabled // enable dark mode for light shafts etc.
);
sky = lerp(GetHorizonColor(), GetZenithColor(), saturate(V.y * 0.5f + 0.5f));
}
sky *= GetWeather().sky_exposure;
if (clouds_enabled)
{
CalculateClouds(sky, V, dark_enabled);
}
return sky;
}
-1
View File
@@ -9,7 +9,6 @@ float4 main(float4 pos : SV_POSITION, float2 clipspace : TEXCOORD) : SV_TARGET
const float3 V = normalize(unprojected.xyz - GetCamera().position);
float4 color = float4(DEGAMMA_SKY(texture_globalenvmap.SampleLevel(sampler_linear_clamp, V, 0).rgb), 1);
CalculateClouds(color.rgb, V, false);
float4 pos2DPrev = mul(GetCamera().previous_view_projection, float4(unprojected.xyz, 1));
float2 velocity = ((pos2DPrev.xy / pos2DPrev.w - GetCamera().temporalaa_jitter_prev) - (clipspace - GetCamera().temporalaa_jitter)) * float2(0.5f, -0.5f);
+1 -9
View File
@@ -83,14 +83,6 @@ uint3 hash33(uint3 x)
return uint3(n, n * 16807u, n * 48271u); //see: http://random.mat.sbg.ac.at/results/karl/server/node4.html
}
// Computes post-projection depth from linear depth
float getInverseLinearDepth(float lin, float near, float far)
{
float z_n = ((lin - 2 * far) * near + far * lin) / (lin * near - far * lin);
float z = (z_n + 1) / 2;
return z;
}
[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
@@ -164,7 +156,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
// Convert to post-projection depth so we can construct dual source reprojection buffers later
const float lineardepth = texture_lineardepth[DTid.xy] * GetCamera().z_far;
float reprojectionDepth = getInverseLinearDepth(lineardepth + closestRayLength, GetCamera().z_near, GetCamera().z_far);
float reprojectionDepth = compute_inverse_lineardepth(lineardepth + closestRayLength, GetCamera().z_near, GetCamera().z_far);
texture_resolve[DTid.xy] = max(result, 0.00001f);
texture_resolve_variance[DTid.xy] = resolveVariance;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,2 @@
#define VOLUMETRICCLOUD_CAPTURE
#include "volumetricCloud_renderCS.hlsl"
@@ -0,0 +1,2 @@
#define MSAA
#include "volumetricCloud_renderCS_capture.hlsl"
@@ -1,4 +1,5 @@
#include "globals.hlsli"
#include "volumetricCloudsHF.hlsli"
#include "ShaderInterop_Postprocess.h"
PUSHCONSTANT(postprocess, PostProcess);
@@ -7,32 +8,29 @@ Texture2D<float4> cloud_current : register(t0);
Texture2D<float2> cloud_depth_current : register(t1);
Texture2D<float4> cloud_history : register(t2);
Texture2D<float2> cloud_depth_history : register(t3);
Texture2D<float> cloud_additional_history : register(t4);
RWTexture2D<float4> output : register(u0);
RWTexture2D<float2> output_depth : register(u1);
RWTexture2D<float> output_additional : register(u2);
RWTexture2D<unorm float4> output_cloudMask : register(u3);
// This function compute the checkerboard undersampling position
int ComputeCheckerBoardIndex(int2 renderCoord, int subPixelIndex)
{
const int localOffset = (renderCoord.x & 1 + renderCoord.y & 1) & 1;
const int checkerBoardLocation = (subPixelIndex + localOffset) & 0x3;
return checkerBoardLocation;
}
static const float2 temporalResponseMinMax = float2(0.5, 0.9);
// Computes post-projection depth from linear depth
float getInverseLinearDepth(float lin, float near, float far)
{
float z_n = ((lin - 2 * far) * near + far * lin) / (lin * near - far * lin);
float z = (z_n + 1) / 2;
return z;
}
// When moving fast reprojection cannot catch up. This value eliminates the ghosting but results in clipping artefacts
//#define ADDITIONAL_BOX_CLAMP
[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
uint2 renderCoord = DTid.xy / 2;
const float2 uv = (DTid.xy + 0.5f) * postprocess.resolution_rcp;
uint2 renderResolution = postprocess.resolution / 2;
uint2 renderCoord = DTid.xy / 2;
uint2 minRenderCoord = uint2(0, 0);
uint2 maxRenderCoord = renderResolution - 1;
#if 0
// Calculate screen dependant motion vector
@@ -55,7 +53,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
float2 screenPosition = float2(x, y);
float currentCloudLinearDepth = cloud_depth_current.SampleLevel(sampler_point_clamp, uv, 0).x;
float currentCloudDepth = getInverseLinearDepth(currentCloudLinearDepth, GetCamera().z_near, GetCamera().z_far);
float currentCloudDepth = compute_inverse_lineardepth(currentCloudLinearDepth, GetCamera().z_near, GetCamera().z_far);
float4 thisClip = float4(screenPosition, currentCloudDepth, 1.0);
@@ -83,6 +81,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
float4 result = 0.0;
float2 depthResult = 0.0;
float additionalResult = 0.0;
#if 0 // Simple reprojection version
@@ -98,31 +97,78 @@ void main(uint3 DTid : SV_DispatchThreadID)
}
output[DTid.xy] = result;
output_depth[DTid.xy] = depthResult;
output_additional[DTid.xy] = 0.0;
output_cloudMask[DTid.xy] = pow(saturate(1 - result.a), 64);
return;
#endif
if (validHistory)
{
float4 newResult = cloud_current[renderCoord];
float2 newDepthResult = cloud_depth_current[renderCoord];
float4 newResult = cloud_current[clamp(renderCoord, minRenderCoord, maxRenderCoord)];
float2 newDepthResult = cloud_depth_current[clamp(renderCoord, minRenderCoord, maxRenderCoord)];
float4 previousResult = cloud_history.SampleLevel(sampler_linear_clamp, prevUV, 0);
float2 previousDepthResult = cloud_depth_history.SampleLevel(sampler_linear_clamp, prevUV, 0);
float previousAdditionalResult = cloud_additional_history.SampleLevel(sampler_linear_clamp, prevUV, 0);
float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 1).r; // Half res
float3 depthWorldPosition = reconstruct_position(uv, depth);
float tToDepthBuffer = length(depthWorldPosition - GetCamera().position);
// Accommodate so when we compare tToDepthBuffer (float precision) with cloud_depth_current (half float precision) we don't overshoot and get incorrect testing
// No issues has been noticed so far
tToDepthBuffer = depth == 0.0 ? HALF_FLT_MAX : tToDepthBuffer;
if (shouldUpdatePixel)
{
result = newResult;
depthResult = newDepthResult;
if (abs(tToDepthBuffer - previousDepthResult.y) > tToDepthBuffer * 0.1)
{
result = newResult;
depthResult = newDepthResult;
additionalResult = temporalResponseMinMax.x;
}
else
{
// Based on Welford's online algorithm:
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
float4 m1 = 0.0;
float4 m2 = 0.0;
for (int x = -1; x <= 1; x++)
{
for (int y = -1; y <= 1; y++)
{
int2 offset = int2(x, y);
int2 neighborCoord = renderCoord + offset;
neighborCoord = clamp(neighborCoord, minRenderCoord, maxRenderCoord);
float4 neighborResult = cloud_current[neighborCoord];
m1 += neighborResult;
m2 += neighborResult * neighborResult;
}
}
float4 mean = m1 / 9.0;
float4 variance = (m2 / 9.0) - (mean * mean);
float4 stddev = sqrt(max(variance, 0.0f));
// Color box clamp
float4 colorMin = mean - stddev;
float4 colorMax = mean + stddev;
previousResult = clamp(previousResult, colorMin, colorMax);
result = lerp(newResult, previousResult, previousAdditionalResult);
depthResult = newDepthResult;
additionalResult = temporalResponseMinMax.y;
}
}
else
{
float4 previousResult = cloud_history.SampleLevel(sampler_linear_clamp, prevUV, 0);
float2 previousDepthResult = cloud_depth_history.SampleLevel(sampler_linear_clamp, prevUV, 0);
result = previousResult;
depthResult = previousDepthResult;
float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 1).r; // Half res
float3 depthWorldPosition = reconstruct_position(uv, depth);
float tToDepthBuffer = length(depthWorldPosition - GetCamera().position);
additionalResult = previousAdditionalResult;
if (abs(tToDepthBuffer - previousDepthResult.y) > tToDepthBuffer * 0.1)
{
@@ -135,31 +181,66 @@ void main(uint3 DTid : SV_DispatchThreadID)
if ((abs(x) + abs(y)) == 0)
continue;
int2 neighborCoord = renderCoord + int2(x, y);
int2 offset = int2(x, y);
int2 neighborCoord = renderCoord + offset;
neighborCoord = clamp(neighborCoord, minRenderCoord, maxRenderCoord);
float2 neighboorDepthResult = cloud_depth_current[neighborCoord];
float neighborClosestDepth = abs(tToDepthBuffer - neighboorDepthResult.y);
if (neighborClosestDepth < closestDepth)
{
closestDepth = neighborClosestDepth;
float4 neighborResult = cloud_current[neighborCoord];
result = neighborResult;
depthResult = neighboorDepthResult;
additionalResult = temporalResponseMinMax.x;
}
}
}
if (abs(tToDepthBuffer - newDepthResult.y) < closestDepth)
{
result = newResult;
depthResult = newDepthResult;
}
}
else
{
#ifdef ADDITIONAL_BOX_CLAMP
// Simple box clamping from neighbour pixels
float4 resultAABBMin = FLT_MAX;
float4 resultAABBMax = 0.0;
float2 depthResultAABBMin = FLT_MAX;
float2 depthResultAABBMax = 0.0;
for (int y = -1; y <= 1; y++)
{
for (int x = -1; x <= 1; x++)
{
// If it's middle then skip. We only evaluate neighbor samples
if ((abs(x) + abs(y)) == 0)
continue;
int2 offset = int2(x, y);
int2 neighborCoord = renderCoord + offset;
float4 neighborResult = cloud_current[neighborCoord];
float2 neighboorDepthResult = cloud_depth_current[neighborCoord];
resultAABBMin = min(resultAABBMin, neighborResult);
resultAABBMax = max(resultAABBMax, neighborResult);
depthResultAABBMin = min(depthResultAABBMin, neighboorDepthResult);
depthResultAABBMax = max(depthResultAABBMax, neighboorDepthResult);
}
}
resultAABBMin = min(resultAABBMin, newResult);
resultAABBMax = max(resultAABBMax, newResult);
depthResultAABBMin = min(depthResultAABBMin, newDepthResult);
depthResultAABBMax = max(depthResultAABBMax, newDepthResult);
result = clamp(result, resultAABBMin, resultAABBMax);
depthResult = clamp(depthResult, depthResultAABBMin, depthResultAABBMax);
#endif // ADDITIONAL_CLIPPING
}
}
}
@@ -167,8 +248,11 @@ void main(uint3 DTid : SV_DispatchThreadID)
{
result = cloud_current.SampleLevel(sampler_linear_clamp, uv, 0);
depthResult = cloud_depth_current.SampleLevel(sampler_linear_clamp, uv, 0);
additionalResult = temporalResponseMinMax.x;
}
output[DTid.xy] = result;
output_depth[DTid.xy] = depthResult;
output_additional[DTid.xy] = additionalResult;
output_cloudMask[DTid.xy] = pow(saturate(1 - result.a), 64);
}
@@ -0,0 +1,43 @@
#include "globals.hlsli"
#include "ShaderInterop_Postprocess.h"
PUSHCONSTANT(postprocess, PostProcess);
Texture2D<float3> input : register(t0);
RWTexture2D<float3> output : register(u0);
[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
const float2 uv = (DTid.xy + 0.5) * postprocess.resolution_rcp;
#if 0 // Debug
output[DTid.xy] = input[DTid.xy];
return;
#endif
// Filter
float3 filteredResult = 0.0;
float sum = 0.0;
const int radius = 1;
for (int x = -radius; x <= radius; x++)
{
for (int y = -radius; y <= radius; y++)
{
int2 offset = int2(x, y);
int2 neighborCoord = DTid.xy + offset;
if (all(neighborCoord >= int2(0, 0) && neighborCoord < (int2) postprocess.resolution))
{
float3 neighborResult = input[neighborCoord];
filteredResult += neighborResult;
sum += 1.0;
}
}
}
filteredResult /= sum;
output[DTid.xy] = filteredResult;
}
@@ -0,0 +1,144 @@
#include "globals.hlsli"
#include "volumetricCloudsHF.hlsli"
#include "skyAtmosphere.hlsli"
#include "ShaderInterop_Postprocess.h"
PUSHCONSTANT(postprocess, PostProcess);
Texture3D<float4> texture_shapeNoise : register(t0);
Texture3D<float4> texture_detailNoise : register(t1);
Texture2D<float4> texture_curlNoise : register(t2);
Texture2D<float4> texture_weatherMap : register(t3);
RWTexture2D<float3> texture_render : register(u0);
static const float2 sampleCountMinMax = float2(16.0, 32.0); // Based on sun angle, more angle more samples
void VolumetricShadowMap(out float3 result, in AtmosphereParameters atmosphere, float3 worldPosition, float3 sunDirection,
float tMin, float tMax, float3 windOffset, float3 windDirection, float2 coverageWindOffset)
{
float nearDepth = 0.0;
float3 extinctionAccumulation = 0.0f;
float extinctionAccumulationCount = 0.0f;
float3 maxOpticalDepth = 0.0f;
float3 planetSurfaceNormal = normalize(GetCamera().position - (atmosphere.planetCenter * SKY_UNIT_TO_M));
float NdotL = saturate(dot(planetSurfaceNormal, sunDirection));
float sampleCount = lerp(sampleCountMinMax.y, sampleCountMinMax.x, NdotL);
const float shadowLength = tMax - tMin;
const float delta = shadowLength / sampleCount; // Since our samples our linear this stays constant
for (float s = 0.0f; s < sampleCount; s += 1.0)
{
// Linear Distribution
float t = (s + 1.0f) / sampleCount;
float shadowSampleT = shadowLength * t;
float3 samplePoint = worldPosition + sunDirection * shadowSampleT; // Step futher towards the light
float heightFraction = GetHeightFractionForPoint(atmosphere, samplePoint);
if (heightFraction < 0.0 || heightFraction > 1.0)
{
break;
}
float3 weatherData = SampleWeather(texture_weatherMap, samplePoint, heightFraction, coverageWindOffset);
if (weatherData.r < 0.25)
{
continue;
}
float shadowCloudDensity = SampleCloudDensity(texture_shapeNoise, texture_detailNoise, texture_curlNoise, samplePoint, heightFraction, weatherData, windOffset, windDirection, 0.0f, true);
float3 shadowExtinction = GetWeather().volumetric_clouds.ExtinctionCoefficient * shadowCloudDensity;
if (any(shadowExtinction > 0.0f))
{
nearDepth = max(shadowSampleT, nearDepth); // If there exists extinction "push" the near depth futher
extinctionAccumulationCount += 1.0;
}
extinctionAccumulation += shadowExtinction;
maxOpticalDepth += shadowExtinction * delta;
}
const float averageGreyExtinction = dot(extinctionAccumulation / max(extinctionAccumulationCount, 1.0f), 1.0f / 3.0f);
const float maxGreyOpticalDepth = dot(maxOpticalDepth, 1.0f / 3.0f);
// Values can get to big for the assigned texture, so we pack this into kilometer type
const bool miss = nearDepth == 0.0;
const float frontDepth = miss ? tMax * M_TO_SKY_UNIT : (tMin + nearDepth) * M_TO_SKY_UNIT;
result = float3(frontDepth, averageGreyExtinction, maxGreyOpticalDepth);
}
[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)]
void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex)
{
const float2 uv = (DTid.xy + 0.5) * postprocess.resolution_rcp;
const float nearDepth = 1.0f;
float3 nearPlaneWorldPosition = reconstruct_position(uv, nearDepth, GetFrame().cloudShadowLightSpaceMatrixInverse);
// Setup for shadow capture:
float3 rayOrigin = nearPlaneWorldPosition;
float3 rayDirection = GetSunDirection();
float3 result = float3(GetFrame().cloudShadowFarPlaneKm, 0.0, 0.0);
AtmosphereParameters parameters = GetWeather().atmosphere;
float planetRadius = parameters.bottomRadius * SKY_UNIT_TO_M;
float3 planetCenterWorld = parameters.planetCenter * SKY_UNIT_TO_M;
const float cloudBottomRadius = planetRadius + GetWeather().volumetric_clouds.CloudStartHeight;
const float cloudTopRadius = planetRadius + GetWeather().volumetric_clouds.CloudStartHeight + GetWeather().volumetric_clouds.CloudThickness;
float2 tTopSolutions = RaySphereIntersect(rayOrigin, rayDirection, planetCenterWorld, cloudTopRadius);
if (tTopSolutions.x > 0.0 || tTopSolutions.y > 0.0) // Only calculate if any solutions are visible on screen!
{
float tMin = -FLT_MAX;
float tMax = -FLT_MAX;
float2 tBottomSolutions = RaySphereIntersect(rayOrigin, rayDirection, planetCenterWorld, cloudBottomRadius);
if (tBottomSolutions.x > 0.0 || tBottomSolutions.y > 0.0)
{
// If we see both intersections on the screen, keep the min closest, otherwise the max furthest
float tempTop = all(tTopSolutions > 0.0f) ? min(tTopSolutions.x, tTopSolutions.y) : max(tTopSolutions.x, tTopSolutions.y);
float tempBottom = all(tBottomSolutions > 0.0f) ? min(tBottomSolutions.x, tBottomSolutions.y) : max(tBottomSolutions.x, tBottomSolutions.y);
// But if we can see the bottom of the layer, make sure we use the camera view or the highest top layer intersection
if (all(tBottomSolutions > 0.0f))
{
tempTop = max(0.0f, min(tTopSolutions.x, tTopSolutions.y));
}
tMin = min(tempBottom, tempTop);
tMax = max(tempBottom, tempTop);
}
else
{
tMin = tTopSolutions.x;
tMax = tTopSolutions.y;
}
tMin = max(0.0, tMin);
tMax = max(0.0, tMax);
float3 worldPositionClosestToCloudLayer = rayOrigin + rayDirection * tMin; // Determined by tMin
// Wind animation offsets
float3 windDirection = float3(cos(GetWeather().volumetric_clouds.WindAngle), -GetWeather().volumetric_clouds.WindUpAmount, sin(GetWeather().volumetric_clouds.WindAngle));
float3 windOffset = GetWeather().volumetric_clouds.WindSpeed * GetWeather().volumetric_clouds.AnimationMultiplier * windDirection * GetFrame().time;
float2 coverageWindDirection = float2(cos(GetWeather().volumetric_clouds.CoverageWindAngle), sin(GetWeather().volumetric_clouds.CoverageWindAngle));
float2 coverageWindOffset = GetWeather().volumetric_clouds.CoverageWindSpeed * GetWeather().volumetric_clouds.AnimationMultiplier * coverageWindDirection * GetFrame().time;
// Render
VolumetricShadowMap(result, parameters, worldPositionClosestToCloudLayer, GetSunDirection(), tMin, tMax, windOffset, windDirection, coverageWindOffset);
}
// Output
texture_render[DTid.xy] = result;
}
@@ -1,205 +0,0 @@
#include "globals.hlsli"
#include "ShaderInterop_Postprocess.h"
PUSHCONSTANT(postprocess, PostProcess);
Texture2D<float4> cloud_reproject : register(t0);
Texture2D<float2> cloud_reproject_depth : register(t1);
Texture2D<float4> cloud_history : register(t2);
RWTexture2D<float4> output : register(u0);
RWTexture2D<unorm float4> output_cloudMask : register(u1);
// If the clouds are moving fast, the upsampling will most likely not be able to keep up. You can modify these values to relax the effect:
static const float temporalResponse = 0.05;
static const float temporalScale = 2.0;
static const float temporalExposure = 10.0;
// Different aabb clipping method from eg. SSR temporal, suitable for clouds in this case
float4 clip_aabb(float4 aabb_min, float4 aabb_max, float4 prev_sample)
{
float4 p_clip = 0.5 * (aabb_max + aabb_min);
float4 e_clip = 0.5 * (aabb_max - aabb_min) + 0.00000001f;
float4 v_clip = prev_sample - p_clip;
float4 v_unit = v_clip / e_clip;
float4 a_unit = abs(v_unit);
float ma_unit = max(max(a_unit.x, max(a_unit.y, a_unit.z)), a_unit.w);
if (ma_unit > 1.0)
return p_clip + v_clip / ma_unit;
else
return prev_sample; // point inside aabb
}
inline void ResolverAABB(Texture2D<float4> currentColor, SamplerState currentSampler, float sharpness, float exposureScale, float AABBScale, float2 uv, float2 texelSize, inout float4 currentMin, inout float4 currentMax, inout float4 currentAverage, inout float4 currentOutput)
{
const int2 SampleOffset[9] = { int2(-1.0, -1.0), int2(0.0, -1.0), int2(1.0, -1.0), int2(-1.0, 0.0), int2(0.0, 0.0), int2(1.0, 0.0), int2(-1.0, 1.0), int2(0.0, 1.0), int2(1.0, 1.0) };
// Modulate Luma HDR
float4 sampleColors[9];
[unroll]
for (uint i = 0; i < 9; i++)
{
sampleColors[i] = currentColor.SampleLevel(currentSampler, uv + (SampleOffset[i] / texelSize), 0.0f);
}
#if 0 // Exaggerates outline between clouds and geometry
float sampleWeights[9];
[unroll]
for (uint j = 0; j < 9; j++)
{
sampleWeights[j] = HdrWeight4(sampleColors[j].rgb, exposureScale);
}
float totalWeight = 0;
[unroll]
for (uint k = 0; k < 9; k++)
{
totalWeight += sampleWeights[k];
}
sampleColors[4] = (sampleColors[0] * sampleWeights[0] + sampleColors[1] * sampleWeights[1] + sampleColors[2] * sampleWeights[2] + sampleColors[3] * sampleWeights[3] + sampleColors[4] * sampleWeights[4] +
sampleColors[5] * sampleWeights[5] + sampleColors[6] * sampleWeights[6] + sampleColors[7] * sampleWeights[7] + sampleColors[8] * sampleWeights[8]) / totalWeight;
#endif
#if 0 // Standard clipping
// Variance Clipping (AABB)
float4 m1 = 0.0;
float4 m2 = 0.0;
[unroll]
for (uint x = 0; x < 9; x++)
{
m1 += sampleColors[x];
m2 += sampleColors[x] * sampleColors[x];
}
float4 mean = m1 / 9.0;
float4 stddev = sqrt((m2 / 9.0) - sqr(mean));
#else // Depth check
float depth = texture_depth.SampleLevel(sampler_point_clamp, uv, 1).r; // Half res
float3 depthWorldPosition = reconstruct_position(uv, depth);
float tToDepthBuffer = length(depthWorldPosition - GetCamera().position);
float validSampleCount = 1.0;
float4 m1 = 0.0;
float4 m2 = 0.0;
[unroll]
for (uint x = 0; x < 9; x++)
{
if (x == 4)
{
m1 += sampleColors[x];
m2 += sampleColors[x] * sampleColors[x];
}
else
{
float2 reprojectionDepthResults = cloud_reproject_depth.SampleLevel(sampler_point_clamp, uv + (SampleOffset[x] / texelSize), 1);
if (abs(tToDepthBuffer - reprojectionDepthResults.y) < tToDepthBuffer * 0.1)
{
m1 += sampleColors[x];
m2 += sampleColors[x] * sampleColors[x];
validSampleCount += 1.0;
}
}
}
float4 mean = m1 / validSampleCount;
float4 stddev = sqrt((m2 / validSampleCount) - sqr(mean));
#endif
currentMin = mean - AABBScale * stddev;
currentMax = mean + AABBScale * stddev;
currentOutput = sampleColors[4];
currentMin = min(currentMin, currentOutput);
currentMax = max(currentMax, currentOutput);
currentAverage = mean;
}
// Computes post-projection depth from linear depth
float getInverseLinearDepth(float lin, float near, float far)
{
float z_n = ((lin - 2 * far) * near + far * lin) / (lin * near - far * lin);
float z = (z_n + 1) / 2;
return z;
}
[numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
const float2 uv = (DTid.xy + 0.5f) * postprocess.resolution_rcp;
#if 0
// Calculate screen dependant motion vector
float4 prevPos = float4(uv * 2.0 - 1.0, 1.0, 1.0);
prevPos = mul(GetCamera().inverse_projection, prevPos);
prevPos = prevPos / prevPos.w;
prevPos.xyz = mul((float3x3)GetCamera().inverse_view, prevPos.xyz);
prevPos.xyz = mul((float3x3)GetCamera().previous_view, prevPos.xyz);
float4 reproj = mul(GetCamera().projection, prevPos);
reproj /= reproj.w;
float2 prevUV = reproj.xy * 0.5 + 0.5;
#else
// We must recalculate motion with new upscaled cloud depths:
float x = uv.x * 2 - 1;
float y = (1 - uv.y) * 2 - 1;
float2 screenPosition = float2(x, y);
float currentCloudLinearDepth = cloud_reproject_depth[DTid.xy].x;
float currentCloudDepth = getInverseLinearDepth(currentCloudLinearDepth, GetCamera().z_near, GetCamera().z_far);
float4 thisClip = float4(screenPosition, currentCloudDepth, 1.0);
float4 prevClip = mul(GetCamera().inverse_view_projection, thisClip);
prevClip = mul(GetCamera().previous_view_projection, prevClip);
//float4 prevClip = mul(GetCamera().previous_view_projection, worldPosition);
float2 prevScreen = prevClip.xy / prevClip.w;
float2 screenVelocity = screenPosition - prevScreen;
float2 prevScreenPosition = screenPosition - screenVelocity;
// Transform from screen position to uv
float2 prevUV = prevScreenPosition * float2(0.5, -0.5) + 0.5;
#endif
float4 previous = cloud_history.SampleLevel(sampler_linear_clamp, prevUV, 0);
float4 current = 0;
float4 currentMin, currentMax, currentAverage;
ResolverAABB(cloud_reproject, sampler_point_clamp, 0, temporalExposure, temporalScale, uv, postprocess.resolution, currentMin, currentMax, currentAverage, current);
//previous = clip_aabb(currentMin.xyz, currentMax.xyz, clamp(currentAverage, currentMin, currentMax), previous);
previous = clip_aabb(currentMin, currentMax, previous);
float4 result = lerp(previous, current, temporalResponse);
result = (is_saturated(prevUV) && volumetricclouds_frame > 0) ? result : current;
output[DTid.xy] = result;
[branch]
if (DTid.x % 2 == 0 && DTid.y % 2 == 0)
{
// the mask is half the resolution of the clouds
output_cloudMask[DTid.xy / 2] = pow(saturate(1 - result.a), 64);
}
}
@@ -17,7 +17,7 @@ void main(uint3 DTid : SV_DispatchThreadID)
const float depthOffset4 = 200.0;
const float totalSize = 3.0; // Adjust the overall size for all channels
const float coveragePerlinWorleyDifference = 0.7; // For more bigger and mean clouds, you can use something like 0.9 or 1.0
const float coveragePerlinWorleyDifference = 0.4; // For more bigger and mean clouds, you can use something like 0.9 or 1.0
const float worleySeed = 1.0; // Randomize the worley coverage noise with a seed.
const float totalRemapLow = 0.5;
@@ -53,6 +53,8 @@ void main(uint3 DTid : SV_DispatchThreadID)
perlinNoise1 -= perlinNoise4;
perlinNoise2 -= pow(perlinNoise4, 2.0);
perlinNoise1 = RemapClamped(perlinNoise1 * 2.0, 0.0, 1.0, 0.05, 1.0);
output[DTid.xy] = float4(perlinNoise1, perlinNoise2, perlinNoise3, 1.0);
}
+137 -1
View File
@@ -1,5 +1,8 @@
#ifndef WI_VOLUMETRICCLOUDS_HF
#define WI_VOLUMETRICCLOUDS_HF
#include "globals.hlsli"
#define HALF_FLT_MAX 65504.0
// Amazing noise and weather creation, modified from: https://github.com/greje656/clouds
@@ -351,4 +354,137 @@ float DilatePerlinWorley(float p, float w, float x)
}
}
#endif // WI_VOLUMETRICCLOUDS_HF
// Calculates checkerboard undersampling position
int ComputeCheckerBoardIndex(int2 renderCoord, int subPixelIndex)
{
const int localOffset = (renderCoord.x & 1 + renderCoord.y & 1) & 1;
const int checkerBoardLocation = (subPixelIndex + localOffset) & 0x3;
return checkerBoardLocation;
}
////////////////////////////////////// Cloud Model ////////////////////////////////////////////////
float GetHeightFractionForPoint(AtmosphereParameters atmosphere, float3 pos)
{
float planetRadius = atmosphere.bottomRadius * SKY_UNIT_TO_M;
float3 planetCenterWorld = atmosphere.planetCenter * SKY_UNIT_TO_M;
return saturate((distance(pos, planetCenterWorld) - (planetRadius + GetWeather().volumetric_clouds.CloudStartHeight)) / GetWeather().volumetric_clouds.CloudThickness);
}
float SampleGradient(float4 gradient, float heightFraction)
{
return smoothstep(gradient.x, gradient.y, heightFraction) - smoothstep(gradient.z, gradient.w, heightFraction);
}
float GetDensityHeightGradient(float heightFraction, float3 weatherData)
{
float cloudType = weatherData.g;
float smallType = 1.0f - saturate(cloudType * 2.0f);
float mediumType = 1.0f - abs(cloudType - 0.5f) * 2.0f;
float largeType = saturate(cloudType - 0.5f) * 2.0f;
float4 cloudGradient =
(GetWeather().volumetric_clouds.CloudGradientSmall * smallType) +
(GetWeather().volumetric_clouds.CloudGradientMedium * mediumType) +
(GetWeather().volumetric_clouds.CloudGradientLarge * largeType);
return SampleGradient(cloudGradient, heightFraction);
}
float3 SampleWeather(Texture2D<float4> texture_weatherMap, float3 pos, float heightFraction, float2 coverageWindOffset)
{
float4 weatherData = texture_weatherMap.SampleLevel(sampler_linear_wrap, (pos.xz + coverageWindOffset) * GetWeather().volumetric_clouds.WeatherScale, 0);
// Apply effects for coverage
weatherData.r = RemapClamped(weatherData.r * GetWeather().volumetric_clouds.CoverageAmount, 0.0, 1.0, GetWeather().volumetric_clouds.CoverageMinimum, 1.0);
weatherData.g = RemapClamped(weatherData.g * GetWeather().volumetric_clouds.TypeAmount, 0.0, 1.0, GetWeather().volumetric_clouds.TypeMinimum, 1.0);
// Apply anvil clouds to coverage
weatherData.r = pow(weatherData.r, max(Remap(pow(1.0 - heightFraction, GetWeather().volumetric_clouds.AnvilOverhangHeight), 0.7, 0.8, 1.0, GetWeather().volumetric_clouds.AnvilAmount + 1.0), 0.0));
return weatherData.rgb;
}
float WeatherDensity(float3 weatherData)
{
const float wetness = saturate(weatherData.b);
return lerp(1.0, 1.0 - GetWeather().volumetric_clouds.WeatherDensityAmount, wetness);
}
float SampleCloudDensity(Texture3D<float4> texture_shapeNoise, Texture3D<float4> texture_detailNoise, Texture2D<float4> texture_curlNoise, float3 p, float heightFraction, float3 weatherData, float3 windOffset, float3 windDirection, float lod, bool sampleDetail)
{
float3 pos = p + windOffset;
pos += heightFraction * windDirection * GetWeather().volumetric_clouds.SkewAlongWindDirection;
float4 lowFrequencyNoises = texture_shapeNoise.SampleLevel(sampler_linear_wrap, pos * GetWeather().volumetric_clouds.TotalNoiseScale, lod);
// Create an FBM out of the low-frequency Perlin-Worley Noises
float lowFrequencyFBM = (lowFrequencyNoises.g * 0.625) + (lowFrequencyNoises.b * 0.25) + (lowFrequencyNoises.a * 0.125);
lowFrequencyFBM = saturate(lowFrequencyFBM);
float cloudSample = Remap(lowFrequencyNoises.r, -(1.0 - lowFrequencyFBM), 1.0, 0.0, 1.0);
// Apply height gradients
float densityHeightGradient = GetDensityHeightGradient(heightFraction, weatherData);
cloudSample *= densityHeightGradient;
float cloudCoverage = weatherData.r;
// Apply Coverage to sample
cloudSample = Remap(cloudSample, 1.0 - cloudCoverage, 1.0, 0.0, 1.0);
cloudSample *= cloudCoverage;
// Erode with detail noise if cloud sample > 0
if (cloudSample > 0.0 && sampleDetail)
{
// Apply our curl noise to erode with tiny details.
float3 curlNoise = DecodeCurlNoise(texture_curlNoise.SampleLevel(sampler_linear_wrap, p.xz * GetWeather().volumetric_clouds.CurlScale * GetWeather().volumetric_clouds.TotalNoiseScale, 0).rgb);
pos += float3(curlNoise.r, curlNoise.b, curlNoise.g) * (1.0 - heightFraction) * GetWeather().volumetric_clouds.CurlNoiseModifier;
float3 highFrequencyNoises = texture_detailNoise.SampleLevel(sampler_linear_wrap, pos * GetWeather().volumetric_clouds.DetailScale * GetWeather().volumetric_clouds.TotalNoiseScale, lod).rgb;
// Create an FBM out of the high-frequency Worley Noises
float highFrequencyFBM = (highFrequencyNoises.r * 0.625) + (highFrequencyNoises.g * 0.25) + (highFrequencyNoises.b * 0.125);
highFrequencyFBM = saturate(highFrequencyFBM);
// Dilate detail noise based on height
float highFrequenceNoiseModifier = lerp(1.0 - highFrequencyFBM, highFrequencyFBM, saturate(heightFraction * GetWeather().volumetric_clouds.DetailNoiseHeightFraction));
// Erode with base of clouds
cloudSample = Remap(cloudSample, highFrequenceNoiseModifier * GetWeather().volumetric_clouds.DetailNoiseModifier, 1.0, 0.0, 1.0);
}
return max(cloudSample, 0.0);
}
////////////////////////////////////// Shadow ////////////////////////////////////////////////
inline float shadow_2D_volumetricclouds(float3 P)
{
// Project into shadow map space (no need to divide by .w because ortho projection!):
float3 shadow_pos = mul(GetFrame().cloudShadowLightSpaceMatrix, float4(P, 1)).xyz;
float3 shadow_uv = clipspace_to_uv(shadow_pos);
[branch]
if (is_saturated(shadow_uv))
{
float cloudShadowSampleZ = shadow_pos.z;
Texture2D texture_volumetricclouds_shadow = bindless_textures[GetFrame().texture_volumetricclouds_shadow_index];
float3 cloudShadowData = texture_volumetricclouds_shadow.SampleLevel(sampler_linear_clamp, shadow_uv.xy, 0.0f).rgb;
float sampleDepthKm = saturate(1.0 - cloudShadowSampleZ) * GetFrame().cloudShadowFarPlaneKm;
float opticalDepth = cloudShadowData.g * (max(0.0f, cloudShadowData.r - sampleDepthKm) * SKY_UNIT_TO_M);
opticalDepth = min(cloudShadowData.b, opticalDepth);
float transmittance = saturate(exp(-opticalDepth));
return transmittance;
}
return 1.0;
}
#endif // WI_VOLUMETRICCLOUDS_HF
@@ -1,6 +1,7 @@
#define DISABLE_SOFT_SHADOWMAP
#define TRANSPARENT_SHADOWMAP_SECONDARY_DEPTH_CHECK // fix the lack of depth testing
#include "volumetricLightHF.hlsli"
#include "volumetricCloudsHF.hlsli"
float4 main(VertexToPixel input) : SV_TARGET
{
@@ -38,7 +39,7 @@ float4 main(VertexToPixel input) : SV_TARGET
for (uint i = 0; i < sampleCount; ++i)
{
bool valid = false;
for (uint cascade = 0; cascade < GetFrame().shadow_cascade_count; ++cascade)
{
float3 shadow_pos = mul(load_entitymatrix(light.GetMatrixIndex() + cascade), float4(P, 1)).xyz; // ortho matrix, no divide by .w
@@ -49,6 +50,11 @@ float4 main(VertexToPixel input) : SV_TARGET
{
float3 attenuation = shadow_2D(light, shadow_pos, shadow_uv.xy, cascade);
if (GetFrame().options & OPTION_BIT_VOLUMETRICCLOUDS_SHADOWS)
{
attenuation *= shadow_2D_volumetricclouds(P);
}
// Evaluate sample height for height fog calculation, given 0 for V:
attenuation *= GetFogAmount(cameraDistance - marchedDistance, P, float3(0.0, 0.0, 0.0));
attenuation *= scattering;
+1 -1
View File
@@ -5,7 +5,7 @@ namespace wi
{
// this should always be only INCREMENTED and only if a new serialization is implemeted somewhere!
static constexpr uint64_t __archiveVersion = 85;
static constexpr uint64_t __archiveVersion = 86;
// this is the version number of which below the archive is not compatible with the current version
static constexpr uint64_t __archiveVersionBarrier = 22;
+5 -1
View File
@@ -78,6 +78,7 @@ namespace wi::enums
{
TEXTYPE_3D_VOXELRADIANCE,
TEXTYPE_3D_VOXELRADIANCE_HELPER,
TEXTYPE_2D_VOLUMETRICCLOUDS_SHADOW,
TEXTYPE_2D_SKYATMOSPHERE_TRANSMITTANCELUT,
TEXTYPE_2D_SKYATMOSPHERE_MULTISCATTEREDLUMINANCELUT,
TEXTYPE_2D_SKYATMOSPHERE_SKYVIEWLUT,
@@ -316,8 +317,11 @@ namespace wi::enums
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_CURLNOISE,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_WEATHERMAP,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_RENDER,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_RENDER_CAPTURE,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_RENDER_CAPTURE_MSAA,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_REPROJECT,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_TEMPORAL,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_SHADOW_RENDER,
CSTYPE_POSTPROCESS_VOLUMETRICCLOUDS_SHADOW_FILTER,
CSTYPE_POSTPROCESS_FXAA,
CSTYPE_POSTPROCESS_TEMPORALAA,
CSTYPE_POSTPROCESS_SHARPEN,
+25 -1
View File
@@ -631,7 +631,8 @@ namespace wi::graphics
{
RENDERTARGET,
DEPTH_STENCIL,
RESOLVE,
RESOLVE, // resolve render target (color)
RESOLVE_DEPTH,
SHADING_RATE_SOURCE
} type = Type::RENDERTARGET;
enum class LoadOp
@@ -650,6 +651,11 @@ namespace wi::graphics
ResourceState initial_layout = ResourceState::UNDEFINED; // layout before the render pass
ResourceState subpass_layout = ResourceState::UNDEFINED; // layout within the render pass
ResourceState final_layout = ResourceState::UNDEFINED; // layout after the render pass
enum class DepthResolveMode
{
Min,
Max,
} depth_resolve_mode = DepthResolveMode::Min;
static RenderPassAttachment RenderTarget(
const Texture* resource = nullptr,
@@ -711,6 +717,24 @@ namespace wi::graphics
return attachment;
}
static RenderPassAttachment ResolveDepth(
const Texture* resource = nullptr,
DepthResolveMode depth_resolve_mode = DepthResolveMode::Min,
ResourceState initial_layout = ResourceState::SHADER_RESOURCE,
ResourceState final_layout = ResourceState::SHADER_RESOURCE,
int subresource_SRV = -1
)
{
RenderPassAttachment attachment;
attachment.type = Type::RESOLVE_DEPTH;
attachment.texture = resource;
attachment.initial_layout = initial_layout;
attachment.final_layout = final_layout;
attachment.subresource = subresource_SRV;
attachment.depth_resolve_mode = depth_resolve_mode;
return attachment;
}
static RenderPassAttachment ShadingRateSource(
const Texture* resource = nullptr,
ResourceState initial_layout = ResourceState::SHADING_RATE_SOURCE,
+73 -7
View File
@@ -1486,6 +1486,7 @@ namespace dx12_internal
// Due to a API bug, this resolve_subresources array must be kept alive between BeginRenderpass() and EndRenderpass()!
wi::vector<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS> resolve_subresources[D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT] = {};
wi::vector<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS> resolve_subresources_dsv = {};
};
struct SwapChain_DX12
{
@@ -2024,6 +2025,7 @@ using namespace dx12_internal;
for (auto& attachment : commandlist.active_renderpass->desc.attachments)
{
if (attachment.type == RenderPassAttachment::Type::RESOLVE ||
attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH ||
attachment.type == RenderPassAttachment::Type::SHADING_RATE_SOURCE ||
attachment.texture == nullptr)
continue;
@@ -3835,11 +3837,10 @@ using namespace dx12_internal;
const SingleDescriptor& src_descriptor = src_subresource < 0 ? src_internal->rtv : src_internal->subresources_rtv[src_subresource];
D3D12_RENDER_PASS_RENDER_TARGET_DESC& src_RTV = internal_state->RTVs[resolve_src_counter];
src_RTV.EndingAccess.Resolve.PreserveResolveSource = src_RTV.EndingAccess.Type == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
src_RTV.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE;
src_RTV.EndingAccess.Resolve.Format = clear_value.Format;
src_RTV.EndingAccess.Resolve.PreserveResolveSource = src.storeop == RenderPassAttachment::StoreOp::STORE ? TRUE : FALSE;
src_RTV.EndingAccess.Resolve.Format = src_descriptor.rtv.Format;
src_RTV.EndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE;
src_RTV.EndingAccess.Resolve.PreserveResolveSource = src_RTV.EndingAccess.Type == D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD ? FALSE : TRUE;
src_RTV.EndingAccess.Resolve.pDstResource = texture_internal->resource.Get();
src_RTV.EndingAccess.Resolve.pSrcResource = src_internal->resource.Get();
@@ -3867,6 +3868,63 @@ using namespace dx12_internal;
}
resolve_dst_counter++;
}
else if (attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH)
{
if (texture != nullptr)
{
for (auto& src : renderpass->desc.attachments)
{
if (src.type == RenderPassAttachment::Type::DEPTH_STENCIL && src.texture != nullptr)
{
auto src_internal = to_internal(src.texture);
int src_subresource = src.subresource;
const SingleDescriptor& src_descriptor = src_subresource < 0 ? src_internal->dsv : src_internal->subresources_dsv[src_subresource];
D3D12_RENDER_PASS_DEPTH_STENCIL_DESC& src_DSV = internal_state->DSV;
src_DSV.DepthEndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE;
src_DSV.DepthEndingAccess.Resolve.PreserveResolveSource = src.storeop == RenderPassAttachment::StoreOp::STORE ? TRUE : FALSE;
src_DSV.DepthEndingAccess.Resolve.Format = src_descriptor.dsv.Format;
switch (attachment.depth_resolve_mode)
{
default:
case RenderPassAttachment::DepthResolveMode::Min:
src_DSV.DepthEndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_MIN;
break;
case RenderPassAttachment::DepthResolveMode::Max:
src_DSV.DepthEndingAccess.Resolve.ResolveMode = D3D12_RESOLVE_MODE_MAX;
break;
}
src_DSV.DepthEndingAccess.Resolve.pDstResource = texture_internal->resource.Get();
src_DSV.DepthEndingAccess.Resolve.pSrcResource = src_internal->resource.Get();
const SingleDescriptor& dst_descriptor = subresource < 0 ? texture_internal->srv : texture_internal->subresources_srv[subresource];
for (uint32_t mip = 0; mip < std::min(attachment.texture->desc.mip_levels, dst_descriptor.mipCount); ++mip)
{
for (uint32_t slice = 0; slice < std::min(attachment.texture->desc.array_size, dst_descriptor.sliceCount); ++slice)
{
D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS& params = internal_state->resolve_subresources_dsv.emplace_back();
params.SrcSubresource = D3D12CalcSubresource(src_descriptor.firstMip + mip, src_descriptor.firstSlice + slice, 0, src.texture->desc.mip_levels, src.texture->desc.array_size);
params.DstSubresource = D3D12CalcSubresource(dst_descriptor.firstMip + mip, dst_descriptor.firstSlice + slice, 0, texture->desc.mip_levels, texture->desc.array_size);
params.SrcRect.left = 0;
params.SrcRect.top = 0;
params.SrcRect.right = (LONG)texture->desc.width;
params.SrcRect.bottom = (LONG)texture->desc.height;
}
}
src_DSV.DepthEndingAccess.Resolve.SubresourceCount = (UINT)internal_state->resolve_subresources_dsv.size();
src_DSV.DepthEndingAccess.Resolve.pSubresourceParameters = internal_state->resolve_subresources_dsv.data();
if (IsFormatStencilSupport(attachment.texture->desc.format))
{
src_DSV.StencilBeginningAccess = src_DSV.DepthBeginningAccess;
src_DSV.StencilEndingAccess = src_DSV.DepthEndingAccess;
}
break;
}
}
}
}
else if (attachment.type == RenderPassAttachment::Type::SHADING_RATE_SOURCE)
{
internal_state->shading_rate_image = texture;
@@ -3881,7 +3939,11 @@ using namespace dx12_internal;
continue;
D3D12_RESOURCE_STATES before = _ParseResourceState(attachment.initial_layout);
D3D12_RESOURCE_STATES after = attachment.type == RenderPassAttachment::Type::RESOLVE ? D3D12_RESOURCE_STATE_RESOLVE_DEST : _ParseResourceState(attachment.subpass_layout);
D3D12_RESOURCE_STATES after = _ParseResourceState(attachment.subpass_layout);
if (attachment.type == RenderPassAttachment::Type::RESOLVE || attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH)
{
after = D3D12_RESOURCE_STATE_RESOLVE_DEST;
}
if (before == after)
continue;
@@ -3906,7 +3968,7 @@ using namespace dx12_internal;
{
descriptor = &texture_internal->subresources_dsv[attachment.subresource];
}
else if (attachment.type == RenderPassAttachment::Type::RESOLVE)
else if (attachment.type == RenderPassAttachment::Type::RESOLVE || attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH)
{
// Single barrier for whole resource:
// From debug layer it looks like the resolve operation requires entire resource to be in RESOLVE_DEST
@@ -3943,8 +4005,12 @@ using namespace dx12_internal;
if (attachment.texture == nullptr)
continue;
D3D12_RESOURCE_STATES before = attachment.type == RenderPassAttachment::Type::RESOLVE ? D3D12_RESOURCE_STATE_RESOLVE_DEST : _ParseResourceState(attachment.subpass_layout);
D3D12_RESOURCE_STATES before = _ParseResourceState(attachment.subpass_layout);
D3D12_RESOURCE_STATES after = _ParseResourceState(attachment.final_layout);
if (attachment.type == RenderPassAttachment::Type::RESOLVE || attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH)
{
before = D3D12_RESOURCE_STATE_RESOLVE_DEST;
}
if (before == after)
continue;
@@ -3969,7 +4035,7 @@ using namespace dx12_internal;
{
descriptor = &texture_internal->subresources_dsv[attachment.subresource];
}
else if (attachment.type == RenderPassAttachment::Type::RESOLVE)
else if (attachment.type == RenderPassAttachment::Type::RESOLVE || attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH)
{
// Single barrier for whole resource:
// From debug layer it looks like the resolve operation requires entire resource to be in RESOLVE_DEST
+63 -1
View File
@@ -2477,6 +2477,10 @@ using namespace vulkan_internal;
*properties_chain = &sampler_minmax_properties;
properties_chain = &sampler_minmax_properties.pNext;
depth_stencil_resolve_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
*properties_chain = &depth_stencil_resolve_properties;
properties_chain = &depth_stencil_resolve_properties.pNext;
enabled_deviceExtensions = required_deviceExtensions;
if (checkExtensionSupport(VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, available_deviceExtensions))
@@ -2577,6 +2581,8 @@ using namespace vulkan_internal;
}
assert(properties2.properties.limits.timestampComputeAndGraphics == VK_TRUE);
assert(depth_stencil_resolve_properties.supportedDepthResolveModes& VK_RESOLVE_MODE_MIN_BIT);
assert(depth_stencil_resolve_properties.supportedDepthResolveModes& VK_RESOLVE_MODE_MAX_BIT);
vkGetPhysicalDeviceFeatures2(physicalDevice, &features2);
@@ -5097,6 +5103,8 @@ using namespace vulkan_internal;
VkAttachmentReference2 resolveAttachmentRefs[8] = {};
VkAttachmentReference2 shadingRateAttachmentRef = {};
VkAttachmentReference2 depthAttachmentRef = {};
VkSubpassDescriptionDepthStencilResolve depthResolve = {};
VkAttachmentReference2 depthResolveAttachmentRef = {};
VkFragmentShadingRateAttachmentInfoKHR shading_rate_attachment = {};
shading_rate_attachment.sType = VK_STRUCTURE_TYPE_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR;
@@ -5109,6 +5117,7 @@ using namespace vulkan_internal;
VkSubpassDescription2 subpass = {};
subpass.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
const void** subpass_chain = &subpass.pNext;
uint32_t validAttachmentCount = 0;
for (auto& attachment : renderpass->desc.attachments)
@@ -5258,6 +5267,58 @@ using namespace vulkan_internal;
resolvecount++;
subpass.pResolveAttachments = resolveAttachmentRefs;
}
else if (attachment.type == RenderPassAttachment::Type::RESOLVE_DEPTH)
{
if (attachment.texture == nullptr)
{
resolveAttachmentRefs[resolvecount].attachment = VK_ATTACHMENT_UNUSED;
}
else
{
if (subresource < 0 || texture_internal_state->subresources_srv.empty())
{
attachments[validAttachmentCount] = texture_internal_state->srv.image_view;
}
else
{
assert(texture_internal_state->subresources_srv.size() > size_t(subresource) && "Invalid SRV subresource!");
attachments[validAttachmentCount] = texture_internal_state->subresources_srv[subresource].image_view;
}
if (attachments[validAttachmentCount] == VK_NULL_HANDLE)
{
continue;
}
}
depthResolve.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE;
switch (attachment.depth_resolve_mode)
{
default:
case RenderPassAttachment::DepthResolveMode::Min:
depthResolve.depthResolveMode = VK_RESOLVE_MODE_MIN_BIT;
depthResolve.stencilResolveMode = VK_RESOLVE_MODE_MIN_BIT;
break;
case RenderPassAttachment::DepthResolveMode::Max:
depthResolve.depthResolveMode = VK_RESOLVE_MODE_MAX_BIT;
depthResolve.stencilResolveMode = VK_RESOLVE_MODE_MAX_BIT;
break;
}
depthResolveAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
depthResolveAttachmentRef.attachment = validAttachmentCount;
depthResolveAttachmentRef.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if (IsFormatStencilSupport(attachment.texture->desc.format))
{
depthResolveAttachmentRef.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
depthResolveAttachmentRef.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
depthResolve.pDepthStencilResolveAttachment = &depthResolveAttachmentRef;
*subpass_chain = &depthResolve;
subpass_chain = &depthResolve.pNext;
}
else if (attachment.type == RenderPassAttachment::Type::SHADING_RATE_SOURCE && CheckCapability(GraphicsDeviceCapability::VARIABLE_RATE_SHADING_TIER2))
{
shadingRateAttachmentRef.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2;
@@ -5286,7 +5347,8 @@ using namespace vulkan_internal;
shadingRateAttachmentRef.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
}
subpass.pNext = &shading_rate_attachment;
*subpass_chain = &shading_rate_attachment;
subpass_chain = &shading_rate_attachment.pNext;
}
validAttachmentCount++;
+1
View File
@@ -55,6 +55,7 @@ namespace wi::graphics
VkPhysicalDeviceFragmentShadingRatePropertiesKHR fragment_shading_rate_properties = {};
VkPhysicalDeviceMeshShaderPropertiesNV mesh_shader_properties = {};
VkPhysicalDeviceMemoryProperties2 memory_properties_2 = {};
VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve_properties = {};
VkPhysicalDeviceFeatures2 features2 = {};
VkPhysicalDeviceVulkan11Features features_1_1 = {};
+7 -5
View File
@@ -220,7 +220,7 @@ void RenderPath3D::ResizeBuffers()
desc.sample_count = getMSAASampleCount();
desc.layout = ResourceState::DEPTHSTENCIL_READONLY;
desc.format = Format::R32G8X24_TYPELESS;
desc.format = Format::D32_FLOAT_S8X24_UINT;
desc.bind_flags = BindFlag::DEPTH_STENCIL;
device->CreateTexture(&desc, nullptr, &depthBuffer_Main);
device->SetName(&depthBuffer_Main, "depthBuffer_Main");
@@ -918,7 +918,8 @@ void RenderPath3D::Render() const
{
wi::renderer::Postprocess_VolumetricClouds(
volumetriccloudResources,
cmd
cmd,
scene->weather.volumetricCloudsWeatherMap.IsValid() ? &scene->weather.volumetricCloudsWeatherMap.GetTexture() : nullptr
);
}
@@ -1017,7 +1018,8 @@ void RenderPath3D::Render() const
{
wi::renderer::Postprocess_VolumetricClouds(
volumetriccloudResources_reflection,
cmd
cmd,
scene->weather.volumetricCloudsWeatherMap.IsValid() ? &scene->weather.volumetricCloudsWeatherMap.GetTexture() : nullptr
);
}
@@ -1066,7 +1068,7 @@ void RenderPath3D::Render() const
wi::image::Params fx;
fx.enableFullScreen();
fx.blendFlag = BLENDMODE_PREMULTIPLIED;
wi::image::Draw(&volumetriccloudResources_reflection.texture_temporal[device->GetFrameCount() % 2], fx, cmd);
wi::image::Draw(&volumetriccloudResources_reflection.texture_reproject[device->GetFrameCount() % 2], fx, cmd);
device->EventEnd(cmd);
}
@@ -1175,7 +1177,7 @@ void RenderPath3D::Render() const
{
device->EventBegin("Volumetric Clouds Upsample + Blend", cmd);
wi::renderer::Postprocess_Upsample_Bilateral(
volumetriccloudResources.texture_temporal[device->GetFrameCount() % 2],
volumetriccloudResources.texture_reproject[device->GetFrameCount() % 2],
rtLinearDepth,
rtMain_render, // only desc is taken if pixel shader upsampling is used
cmd,
File diff suppressed because it is too large Load Diff
+9 -3
View File
@@ -206,8 +206,13 @@ namespace wi::renderer
// Render mip levels for textures that reqested it:
void ProcessDeferredMipGenRequests(wi::graphics::CommandList cmd);
// Compute volumetric cloud shadow data
void ComputeVolumetricCloudShadows(
wi::graphics::CommandList cmd,
const wi::graphics::Texture* weatherMap = nullptr
);
// Compute essential atmospheric scattering textures for skybox, fog and clouds
void RenderAtmosphericScatteringTextures(wi::graphics::CommandList cmd);
void ComputeAtmosphericScatteringTextures(wi::graphics::CommandList cmd);
// Update atmospheric scattering primarily for environment probes.
void RefreshAtmosphericScatteringTextures(wi::graphics::CommandList cmd);
// Draw skydome centered to camera.
@@ -621,13 +626,14 @@ namespace wi::renderer
wi::graphics::Texture texture_cloudDepth;
wi::graphics::Texture texture_reproject[2];
wi::graphics::Texture texture_reproject_depth[2];
wi::graphics::Texture texture_temporal[2];
wi::graphics::Texture texture_reproject_additional[2];
wi::graphics::Texture texture_cloudMask;
};
void CreateVolumetricCloudResources(VolumetricCloudResources& res, XMUINT2 resolution);
void Postprocess_VolumetricClouds(
const VolumetricCloudResources& res,
wi::graphics::CommandList cmd
wi::graphics::CommandList cmd,
const wi::graphics::Texture* weatherMap = nullptr
);
void Postprocess_FXAA(
const wi::graphics::Texture& input,
+22 -21
View File
@@ -2060,17 +2060,10 @@ namespace wi::scene
shaderscene.weather.sun_direction = weather.sunDirection;
shaderscene.weather.most_important_light_index = weather.most_important_light_index;
shaderscene.weather.ambient = weather.ambient;
shaderscene.weather.cloudiness = weather.cloudiness;
shaderscene.weather.cloud_scale = weather.cloudScale;
shaderscene.weather.cloud_speed = weather.cloudSpeed;
shaderscene.weather.cloud_shadow_amount = weather.cloud_shadow_amount;
shaderscene.weather.cloud_shadow_scale = weather.cloud_shadow_scale;
shaderscene.weather.cloud_shadow_speed = weather.cloud_shadow_speed;
shaderscene.weather.fog.start = weather.fogStart;
shaderscene.weather.fog.end = weather.fogEnd;
shaderscene.weather.fog.height_start = weather.fogHeightStart;
shaderscene.weather.fog.height_end = weather.fogHeightEnd;
shaderscene.weather.fog.height_sky = weather.fogHeightSky;
shaderscene.weather.horizon = weather.horizon;
shaderscene.weather.zenith = weather.zenith;
shaderscene.weather.sky_exposure = weather.skyExposure;
@@ -2315,9 +2308,6 @@ namespace wi::scene
transform.UpdateTransform();
ForceFieldComponent& force = forces.Create(entity);
force.gravity = 0;
force.range = 0;
force.type = ENTITY_TYPE_FORCEFIELD_POINT;
return entity;
}
@@ -4835,12 +4825,9 @@ namespace wi::scene
desc.mip_levels = 1;
desc.usage = Usage::DEFAULT;
desc.bind_flags = BindFlag::DEPTH_STENCIL;
desc.format = Format::D16_UNORM;
desc.layout = ResourceState::DEPTHSTENCIL;
desc.misc_flags = ResourceMiscFlag::TRANSIENT_ATTACHMENT;
device->CreateTexture(&desc, nullptr, &envrenderingDepthBuffer);
device->SetName(&envrenderingDepthBuffer, "envrenderingDepthBuffer");
desc.bind_flags = BindFlag::DEPTH_STENCIL | BindFlag::SHADER_RESOURCE;
desc.format = Format::R16_TYPELESS;
desc.layout = ResourceState::SHADER_RESOURCE;
desc.sample_count = envmapMSAASampleCount;
device->CreateTexture(&desc, nullptr, &envrenderingDepthBuffer_MSAA);
device->SetName(&envrenderingDepthBuffer_MSAA, "envrenderingDepthBuffer_MSAA");
@@ -4862,17 +4849,25 @@ namespace wi::scene
desc.misc_flags = ResourceMiscFlag::TEXTURECUBE;
desc.usage = Usage::DEFAULT;
desc.layout = ResourceState::SHADER_RESOURCE;
device->CreateTexture(&desc, nullptr, &envmapArray);
device->SetName(&envmapArray, "envmapArray");
desc.array_size = 6;
desc.mip_levels = 1;
desc.format = Format::R16_TYPELESS;
desc.bind_flags = BindFlag::DEPTH_STENCIL | BindFlag::SHADER_RESOURCE;
desc.layout = ResourceState::SHADER_RESOURCE;
device->CreateTexture(&desc, nullptr, &envrenderingDepthBuffer);
device->SetName(&envrenderingDepthBuffer, "envrenderingDepthBuffer");
// Cube arrays per mip level:
for (uint32_t i = 0; i < envmapArray.desc.mip_levels; ++i)
{
int subresource_index;
subresource_index = device->CreateSubresource(&envmapArray, SubresourceType::SRV, 0, desc.array_size, i, 1);
subresource_index = device->CreateSubresource(&envmapArray, SubresourceType::SRV, 0, envmapArray.desc.array_size, i, 1);
assert(subresource_index == i);
subresource_index = device->CreateSubresource(&envmapArray, SubresourceType::UAV, 0, desc.array_size, i, 1);
subresource_index = device->CreateSubresource(&envmapArray, SubresourceType::UAV, 0, envmapArray.desc.array_size, i, 1);
assert(subresource_index == i);
}
@@ -4907,7 +4902,10 @@ namespace wi::scene
RenderPassAttachment::DepthStencil(
&envrenderingDepthBuffer,
RenderPassAttachment::LoadOp::CLEAR,
RenderPassAttachment::StoreOp::DONTCARE
RenderPassAttachment::StoreOp::STORE,
ResourceState::SHADER_RESOURCE,
ResourceState::DEPTHSTENCIL,
ResourceState::SHADER_RESOURCE
)
);
renderpassdesc.attachments.push_back(
@@ -4931,7 +4929,10 @@ namespace wi::scene
RenderPassAttachment::DepthStencil(
&envrenderingDepthBuffer_MSAA,
RenderPassAttachment::LoadOp::CLEAR,
RenderPassAttachment::StoreOp::DONTCARE
RenderPassAttachment::StoreOp::STORE,
ResourceState::SHADER_RESOURCE,
ResourceState::DEPTHSTENCIL,
ResourceState::SHADER_RESOURCE
)
);
renderpassdesc.attachments.push_back(
+18 -14
View File
@@ -849,6 +849,7 @@ namespace wi::scene
VOLUMETRICS = 1 << 1,
VISUALIZER = 1 << 2,
LIGHTMAPONLY_STATIC = 1 << 3,
VOLUMETRICCLOUDS = 1 << 4,
};
uint32_t _flags = EMPTY;
@@ -892,11 +893,13 @@ namespace wi::scene
inline void SetVolumetricsEnabled(bool value) { if (value) { _flags |= VOLUMETRICS; } else { _flags &= ~VOLUMETRICS; } }
inline void SetVisualizerEnabled(bool value) { if (value) { _flags |= VISUALIZER; } else { _flags &= ~VISUALIZER; } }
inline void SetStatic(bool value) { if (value) { _flags |= LIGHTMAPONLY_STATIC; } else { _flags &= ~LIGHTMAPONLY_STATIC; } }
inline void SetVolumetricCloudsEnabled(bool value) { if (value) { _flags |= VOLUMETRICCLOUDS; } else { _flags &= ~VOLUMETRICCLOUDS; } }
inline bool IsCastingShadow() const { return _flags & CAST_SHADOW; }
inline bool IsVolumetricsEnabled() const { return _flags & VOLUMETRICS; }
inline bool IsVisualizerEnabled() const { return _flags & VISUALIZER; }
inline bool IsStatic() const { return _flags & LIGHTMAPONLY_STATIC; }
inline bool IsVolumetricCloudsEnabled() const { return _flags & VOLUMETRICCLOUDS; }
inline float GetRange() const
{
@@ -1038,9 +1041,14 @@ namespace wi::scene
};
uint32_t _flags = EMPTY;
int type = ENTITY_TYPE_FORCEFIELD_POINT;
float gravity = 0.0f; // negative = deflector, positive = attractor
float range = 0.0f; // affection range
enum class Type
{
Point,
Plane,
} type = Type::Point;
float gravity = 0; // negative = deflector, positive = attractor
float range = 0; // affection range
// Non-serialized attributes:
XMFLOAT3 position;
@@ -1227,24 +1235,25 @@ namespace wi::scene
{
EMPTY = 0,
OCEAN_ENABLED = 1 << 0,
SIMPLE_SKY = 1 << 1,
_DEPRECATED_SIMPLE_SKY = 1 << 1,
REALISTIC_SKY = 1 << 2,
VOLUMETRIC_CLOUDS = 1 << 3,
HEIGHT_FOG = 1 << 4,
VOLUMETRIC_CLOUDS_SHADOWS = 1 << 5,
};
uint32_t _flags = EMPTY;
inline bool IsOceanEnabled() const { return _flags & OCEAN_ENABLED; }
inline bool IsSimpleSky() const { return _flags & SIMPLE_SKY; }
inline bool IsRealisticSky() const { return _flags & REALISTIC_SKY; }
inline bool IsVolumetricClouds() const { return _flags & VOLUMETRIC_CLOUDS; }
inline bool IsHeightFog() const { return _flags & HEIGHT_FOG; }
inline bool IsVolumetricCloudsShadows() const { return _flags & VOLUMETRIC_CLOUDS_SHADOWS; }
inline void SetOceanEnabled(bool value = true) { if (value) { _flags |= OCEAN_ENABLED; } else { _flags &= ~OCEAN_ENABLED; } }
inline void SetSimpleSky(bool value = true) { if (value) { _flags |= SIMPLE_SKY; } else { _flags &= ~SIMPLE_SKY; } }
inline void SetRealisticSky(bool value = true) { if (value) { _flags |= REALISTIC_SKY; } else { _flags &= ~REALISTIC_SKY; } }
inline void SetVolumetricClouds(bool value = true) { if (value) { _flags |= VOLUMETRIC_CLOUDS; } else { _flags &= ~VOLUMETRIC_CLOUDS; } }
inline void SetHeightFog(bool value = true) { if (value) { _flags |= HEIGHT_FOG; } else { _flags &= ~HEIGHT_FOG; } }
inline void SetVolumetricCloudsShadows(bool value = true) { if (value) { _flags |= VOLUMETRIC_CLOUDS_SHADOWS; } else { _flags &= ~VOLUMETRIC_CLOUDS_SHADOWS; } }
XMFLOAT3 sunColor = XMFLOAT3(0, 0, 0);
XMFLOAT3 sunDirection = XMFLOAT3(0, 1, 0);
@@ -1256,13 +1265,6 @@ namespace wi::scene
float fogEnd = 1000;
float fogHeightStart = 1;
float fogHeightEnd = 3;
float fogHeightSky = 0;
float cloudiness = 0.0f;
float cloudScale = 0.0003f;
float cloudSpeed = 0.1f;
float cloud_shadow_amount = 0;
float cloud_shadow_scale = 0.002f;
float cloud_shadow_speed = 0.2f;
XMFLOAT3 windDirection = XMFLOAT3(0, 0, 0);
float windRandomness = 5;
float windWaveSize = 1;
@@ -1275,11 +1277,13 @@ namespace wi::scene
std::string skyMapName;
std::string colorGradingMapName;
std::string volumetricCloudsWeatherMapName;
// Non-serialized attributes:
uint32_t most_important_light_index = ~0u;
wi::Resource skyMap;
wi::Resource colorGradingMap;
wi::Resource volumetricCloudsWeatherMap;
XMFLOAT4 stars_rotation_quaternion = XMFLOAT4(0, 0, 0, 1);
void Serialize(wi::Archive& archive, wi::ecs::EntitySerializer& seri);
@@ -1554,7 +1558,7 @@ namespace wi::scene
wi::ecs::ComponentManager<CameraComponent>& cameras = componentLibrary.Register<CameraComponent>("wi::scene::Scene::cameras");
wi::ecs::ComponentManager<EnvironmentProbeComponent>& probes = componentLibrary.Register<EnvironmentProbeComponent>("wi::scene::Scene::probes");
wi::ecs::ComponentManager<wi::primitive::AABB>& aabb_probes = componentLibrary.Register<wi::primitive::AABB>("wi::scene::Scene::aabb_probes");
wi::ecs::ComponentManager<ForceFieldComponent>& forces = componentLibrary.Register<ForceFieldComponent>("wi::scene::Scene::forces");
wi::ecs::ComponentManager<ForceFieldComponent>& forces = componentLibrary.Register<ForceFieldComponent>("wi::scene::Scene::forces", 1); // version = 1
wi::ecs::ComponentManager<DecalComponent>& decals = componentLibrary.Register<DecalComponent>("wi::scene::Scene::decals");
wi::ecs::ComponentManager<wi::primitive::AABB>& aabb_decals = componentLibrary.Register<wi::primitive::AABB>("wi::scene::Scene::aabb_decals");
wi::ecs::ComponentManager<AnimationComponent>& animations = componentLibrary.Register<AnimationComponent>("wi::scene::Scene::animations");
+3 -7
View File
@@ -3872,13 +3872,9 @@ Luna<Weather_VolumetricCloudParams_BindLua>::PropertyType Weather_VolumetricClou
lunaproperty(Weather_VolumetricCloudParams_BindLua,DetailScale),
lunaproperty(Weather_VolumetricCloudParams_BindLua,WeatherScale),
lunaproperty(Weather_VolumetricCloudParams_BindLua,CurlScale),
lunaproperty(Weather_VolumetricCloudParams_BindLua,ShapeNoiseHeightGradientAmount),
lunaproperty(Weather_VolumetricCloudParams_BindLua,ShapeNoiseMultiplier),
lunaproperty(Weather_VolumetricCloudParams_BindLua,ShapeNoiseMinMax),
lunaproperty(Weather_VolumetricCloudParams_BindLua,ShapeNoisePower),
lunaproperty(Weather_VolumetricCloudParams_BindLua,DetailNoiseModifier),
lunaproperty(Weather_VolumetricCloudParams_BindLua,TypeAmount),
lunaproperty(Weather_VolumetricCloudParams_BindLua,TypeOverall),
lunaproperty(Weather_VolumetricCloudParams_BindLua,TypeMinimum),
lunaproperty(Weather_VolumetricCloudParams_BindLua,AnvilAmount),
lunaproperty(Weather_VolumetricCloudParams_BindLua,AnvilOverhangHeight),
lunaproperty(Weather_VolumetricCloudParams_BindLua,AnimationMultiplier),
@@ -4011,7 +4007,7 @@ int WeatherComponent_BindLua::SetOceanEnabled(lua_State* L)
}
int WeatherComponent_BindLua::IsSimpleSky(lua_State* L)
{
wi::lua::SSetBool(L, component->IsSimpleSky());
wi::lua::SSetBool(L, !component->IsRealisticSky());
return 1;
}
int WeatherComponent_BindLua::SetSimpleSky(lua_State* L)
@@ -4020,7 +4016,7 @@ int WeatherComponent_BindLua::SetSimpleSky(lua_State* L)
if (argc > 0)
{
bool value = wi::lua::SGetBool(L, 1);
component->SetSimpleSky(value);
component->SetRealisticSky(!value);
}
else
{
+3 -25
View File
@@ -849,15 +849,10 @@ namespace wi::lua::scene
WeatherScale = FloatProperty(&parameter->WeatherScale);
CurlScale = FloatProperty(&parameter->CurlScale);
ShapeNoiseHeightGradientAmount = FloatProperty(&parameter->ShapeNoiseHeightGradientAmount);
ShapeNoiseMultiplier = FloatProperty(&parameter->ShapeNoiseMultiplier);
ShapeNoiseMinMax = VectorProperty(&parameter->ShapeNoiseMinMax);
ShapeNoisePower = FloatProperty(&parameter->ShapeNoisePower);
DetailNoiseModifier = FloatProperty(&parameter->DetailNoiseModifier);
TypeAmount = FloatProperty(&parameter->TypeAmount);
TypeOverall = FloatProperty(&parameter->TypeOverall);
TypeMinimum = FloatProperty(&parameter->TypeMinimum);
AnvilAmount = FloatProperty(&parameter->AnvilAmount);
AnvilOverhangHeight = FloatProperty(&parameter->AnvilOverhangHeight);
@@ -895,15 +890,10 @@ namespace wi::lua::scene
FloatProperty WeatherScale;
FloatProperty CurlScale;
FloatProperty ShapeNoiseHeightGradientAmount;
FloatProperty ShapeNoiseMultiplier;
VectorProperty ShapeNoiseMinMax;
FloatProperty ShapeNoisePower;
FloatProperty DetailNoiseModifier;
FloatProperty TypeAmount;
FloatProperty TypeOverall;
FloatProperty TypeMinimum;
FloatProperty AnvilAmount;
FloatProperty AnvilOverhangHeight;
@@ -935,15 +925,10 @@ namespace wi::lua::scene
PropertyFunction(WeatherScale)
PropertyFunction(CurlScale)
PropertyFunction(ShapeNoiseHeightGradientAmount)
PropertyFunction(ShapeNoiseMultiplier)
PropertyFunction(ShapeNoiseMinMax)
PropertyFunction(ShapeNoisePower)
PropertyFunction(DetailNoiseModifier)
PropertyFunction(TypeAmount)
PropertyFunction(TypeOverall)
PropertyFunction(TypeMinimum)
PropertyFunction(AnvilAmount)
PropertyFunction(AnvilOverhangHeight)
@@ -992,13 +977,6 @@ namespace wi::lua::scene
fogEnd = FloatProperty(&component->fogEnd);
fogHeightStart = FloatProperty(&component->fogHeightStart);
fogHeightEnd = FloatProperty(&component->fogHeightEnd);
fogHeightSky = FloatProperty(&component->fogHeightSky);
cloudiness = FloatProperty(&component->cloudiness);
cloudScale = FloatProperty(&component->cloudScale);
cloudSpeed = FloatProperty(&component->cloudSpeed);
cloud_shadow_amount = FloatProperty(&component->cloud_shadow_amount);
cloud_shadow_scale = FloatProperty(&component->cloud_shadow_scale);
cloud_shadow_speed = FloatProperty(&component->cloud_shadow_speed);
windDirection = VectorProperty(&component->windDirection);
windRandomness = FloatProperty(&component->windRandomness);
windWaveSize = FloatProperty(&component->windWaveSize);
+75 -28
View File
@@ -900,14 +900,23 @@ namespace wi::scene
if (archive.IsReadMode())
{
archive >> _flags;
archive >> type;
uint32_t value;
archive >> value;
if (seri.GetVersion() < 1)
{
if (value == 200)
value = 0;
if (value == 201)
value = 1;
}
type = (Type)value;
archive >> gravity;
archive >> range;
}
else
{
archive << _flags;
archive << type;
archive << (uint32_t)type;
archive << gravity;
archive << range;
}
@@ -1034,10 +1043,17 @@ namespace wi::scene
archive >> ambient;
archive >> fogStart;
archive >> fogEnd;
archive >> fogHeightSky;
archive >> cloudiness;
archive >> cloudScale;
archive >> cloudSpeed;
if (archive.GetVersion() < 86)
{
float fogHeightSky;
float cloudiness;
float cloudScale;
float cloudSpeed;
archive >> fogHeightSky;
archive >> cloudiness;
archive >> cloudScale;
archive >> cloudSpeed;
}
archive >> windDirection;
archive >> windRandomness;
archive >> windWaveSize;
@@ -1135,17 +1151,24 @@ namespace wi::scene
archive >> volumetricCloudParameters.DetailScale;
archive >> volumetricCloudParameters.WeatherScale;
archive >> volumetricCloudParameters.CurlScale;
archive >> volumetricCloudParameters.ShapeNoiseHeightGradientAmount;
archive >> volumetricCloudParameters.ShapeNoiseMultiplier;
archive >> volumetricCloudParameters.ShapeNoiseMinMax;
archive >> volumetricCloudParameters.ShapeNoisePower;
if (archive.GetVersion() < 86)
{
float ShapeNoiseHeightGradientAmount;
float ShapeNoiseMultiplier;
XMFLOAT2 ShapeNoiseMinMax;
float ShapeNoisePower;
archive >> ShapeNoiseHeightGradientAmount;
archive >> ShapeNoiseMultiplier;
archive >> ShapeNoiseMinMax;
archive >> ShapeNoisePower;
}
archive >> volumetricCloudParameters.DetailNoiseModifier;
archive >> volumetricCloudParameters.DetailNoiseHeightFraction;
archive >> volumetricCloudParameters.CurlNoiseModifier;
archive >> volumetricCloudParameters.CoverageAmount;
archive >> volumetricCloudParameters.CoverageMinimum;
archive >> volumetricCloudParameters.TypeAmount;
archive >> volumetricCloudParameters.TypeOverall;
archive >> volumetricCloudParameters.TypeMinimum;
archive >> volumetricCloudParameters.AnvilAmount;
archive >> volumetricCloudParameters.AnvilOverhangHeight;
archive >> volumetricCloudParameters.AnimationMultiplier;
@@ -1167,6 +1190,15 @@ namespace wi::scene
archive >> volumetricCloudParameters.TransmittanceThreshold;
archive >> volumetricCloudParameters.ShadowSampleCount;
archive >> volumetricCloudParameters.GroundContributionSampleCount;
if (archive.GetVersion() < 86)
{
volumetricCloudParameters.HorizonBlendAmount *= 0.00001f;
volumetricCloudParameters.TotalNoiseScale *= 0.0004f;
volumetricCloudParameters.WeatherScale *= 0.0004f;
volumetricCloudParameters.CoverageAmount /= 2.0f;
volumetricCloudParameters.CoverageMinimum = std::max(0.0f, volumetricCloudParameters.CoverageMinimum - 1.0f);
}
}
if (archive.GetVersion() >= 71)
@@ -1175,8 +1207,11 @@ namespace wi::scene
archive >> fogHeightEnd;
}
if (archive.GetVersion() >= 77)
if (archive.GetVersion() >= 77 && archive.GetVersion() < 86)
{
float cloud_shadow_amount;
float cloud_shadow_scale;
float cloud_shadow_speed;
archive >> cloud_shadow_amount;
archive >> cloud_shadow_scale;
archive >> cloud_shadow_speed;
@@ -1186,6 +1221,16 @@ namespace wi::scene
{
archive >> stars;
}
if (archive.GetVersion() >= 86)
{
archive >> volumetricCloudsWeatherMapName;
if (!volumetricCloudsWeatherMapName.empty())
{
volumetricCloudsWeatherMapName = dir + volumetricCloudsWeatherMapName;
volumetricCloudsWeatherMap = wi::resourcemanager::Load(volumetricCloudsWeatherMapName, wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA);
}
}
}
else
{
@@ -1197,10 +1242,6 @@ namespace wi::scene
archive << ambient;
archive << fogStart;
archive << fogEnd;
archive << fogHeightSky;
archive << cloudiness;
archive << cloudScale;
archive << cloudSpeed;
archive << windDirection;
archive << windRandomness;
archive << windWaveSize;
@@ -1220,6 +1261,7 @@ namespace wi::scene
wi::helper::MakePathRelative(dir, skyMapName);
wi::helper::MakePathRelative(dir, colorGradingMapName);
wi::helper::MakePathRelative(dir, volumetricCloudsWeatherMapName);
if (archive.GetVersion() >= 32)
{
@@ -1280,17 +1322,24 @@ namespace wi::scene
archive << volumetricCloudParameters.DetailScale;
archive << volumetricCloudParameters.WeatherScale;
archive << volumetricCloudParameters.CurlScale;
archive << volumetricCloudParameters.ShapeNoiseHeightGradientAmount;
archive << volumetricCloudParameters.ShapeNoiseMultiplier;
archive << volumetricCloudParameters.ShapeNoiseMinMax;
archive << volumetricCloudParameters.ShapeNoisePower;
if (archive.GetVersion() < 86)
{
float ShapeNoiseHeightGradientAmount = 0;
float ShapeNoiseMultiplier = 0;
XMFLOAT2 ShapeNoiseMinMax = XMFLOAT2(0, 0);
float ShapeNoisePower = 0;
archive << ShapeNoiseHeightGradientAmount;
archive << ShapeNoiseMultiplier;
archive << ShapeNoiseMinMax;
archive << ShapeNoisePower;
}
archive << volumetricCloudParameters.DetailNoiseModifier;
archive << volumetricCloudParameters.DetailNoiseHeightFraction;
archive << volumetricCloudParameters.CurlNoiseModifier;
archive << volumetricCloudParameters.CoverageAmount;
archive << volumetricCloudParameters.CoverageMinimum;
archive << volumetricCloudParameters.TypeAmount;
archive << volumetricCloudParameters.TypeOverall;
archive << volumetricCloudParameters.TypeMinimum;
archive << volumetricCloudParameters.AnvilAmount;
archive << volumetricCloudParameters.AnvilOverhangHeight;
archive << volumetricCloudParameters.AnimationMultiplier;
@@ -1320,17 +1369,15 @@ namespace wi::scene
archive << fogHeightEnd;
}
if (archive.GetVersion() >= 77)
{
archive << cloud_shadow_amount;
archive << cloud_shadow_scale;
archive << cloud_shadow_speed;
}
if (archive.GetVersion() >= 78)
{
archive << stars;
}
if (archive.GetVersion() >= 86)
{
archive << volumetricCloudsWeatherMapName;
}
}
}
void SoundComponent::Serialize(wi::Archive& archive, EntitySerializer& seri)
+1 -1
View File
@@ -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 = 29;
const int revision = 30;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);