From 18108223df35761a7ef8e277ab670defd5aa37ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Mon, 2 May 2022 10:34:27 +0200 Subject: [PATCH] Terrain Virtual Texture (#422) --- Editor/AnimationWindow.cpp | 4 +- Editor/Editor.cpp | 6 +- Editor/MeshWindow.cpp | 160 +----- Editor/MeshWindow.h | 6 - Editor/TerrainGenerator.cpp | 465 +++++++++++++----- Editor/TerrainGenerator.h | 34 +- Editor/WeatherWindow.cpp | 2 +- WickedEngine/ArchiveVersionHistory.txt | 1 + WickedEngine/offlineshadercompiler.cpp | 4 +- WickedEngine/shaders/ShaderInterop_Renderer.h | 7 +- WickedEngine/shaders/Shaders_SOURCE.vcxitems | 35 +- .../shaders/Shaders_SOURCE.vcxitems.filters | 12 +- WickedEngine/shaders/envMapPS_terrain.hlsl | 2 - WickedEngine/shaders/objectHF.hlsli | 307 ------------ WickedEngine/shaders/objectPS_terrain.hlsl | 8 - WickedEngine/shaders/objectPS_voxelizer.hlsl | 116 ----- .../shaders/objectPS_voxelizer_terrain.hlsl | 2 - .../terrainVirtualTextureUpdateCS.hlsl | 87 ++++ WickedEngine/wiArchive.cpp | 2 +- WickedEngine/wiEnums.h | 4 +- WickedEngine/wiRenderer.cpp | 52 +- WickedEngine/wiScene.cpp | 7 - WickedEngine/wiScene.h | 18 +- WickedEngine/wiScene_Serializers.cpp | 12 +- WickedEngine/wiVersion.cpp | 2 +- 25 files changed, 491 insertions(+), 864 deletions(-) delete mode 100644 WickedEngine/shaders/envMapPS_terrain.hlsl delete mode 100644 WickedEngine/shaders/objectPS_terrain.hlsl delete mode 100644 WickedEngine/shaders/objectPS_voxelizer_terrain.hlsl create mode 100644 WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl diff --git a/Editor/AnimationWindow.cpp b/Editor/AnimationWindow.cpp index eca464286..28abf3a4c 100644 --- a/Editor/AnimationWindow.cpp +++ b/Editor/AnimationWindow.cpp @@ -54,7 +54,6 @@ void AnimationWindow::Create(EditorComponent* editor) else { animation->Play(); - animation->amount = 0; } } }); @@ -87,7 +86,7 @@ void AnimationWindow::Create(EditorComponent* editor) timerSlider.SetTooltip("Set the animation timer by hand."); AddWidget(&timerSlider); - amountSlider.Create(0, 1, 0, 100000, "Amount: "); + amountSlider.Create(0, 1, 1, 100000, "Amount: "); amountSlider.SetSize(XMFLOAT2(250, hei)); amountSlider.SetPos(XMFLOAT2(x, y += step)); amountSlider.OnSlide([&](wi::gui::EventArgs args) { @@ -169,7 +168,6 @@ void AnimationWindow::Update() if (animation.IsPlaying()) { playButton.SetText("Pause"); - animation.amount = wi::math::Lerp(animation.amount, 1, 0.1f); } else { diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index fef23972a..e3707b949 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -374,9 +374,8 @@ void EditorComponent::Load() if (terragen.terrainEntity == INVALID_ENTITY) { // Customize terrain generator before it's initialized: - terragen.material_Base.SetUseVertexColors(true); terragen.material_Base.SetRoughness(1); - terragen.material_Slope.SetRoughness(0.5f); + terragen.material_Slope.SetRoughness(0.1f); terragen.material_LowAltitude.SetRoughness(1); terragen.material_HighAltitude.SetRoughness(1); terragen.material_Base.textures[MaterialComponent::BASECOLORMAP].name = "terrain/base.jpg"; @@ -750,6 +749,7 @@ void EditorComponent::Load() wi::resourcemanager::Mode embed_mode = (wi::resourcemanager::Mode)saveModeComboBox.GetItemUserData(saveModeComboBox.GetSelected()); wi::resourcemanager::SetMode(embed_mode); + terragen.BakeVirtualTexturesToFiles(); scene.Serialize(archive); if (dump_to_header) @@ -1902,7 +1902,7 @@ void EditorComponent::Update(float dt) pathTraceStatisticsLabel.SetText(ss); } - terragen.Generation_Update(); + terragen.Generation_Update(camera); wi::profiler::EndRange(profrange); diff --git a/Editor/MeshWindow.cpp b/Editor/MeshWindow.cpp index 141327fad..9f1343814 100644 --- a/Editor/MeshWindow.cpp +++ b/Editor/MeshWindow.cpp @@ -14,21 +14,22 @@ using namespace wi::scene; void MeshWindow::Create(EditorComponent* editor) { wi::gui::Window::Create("Mesh Window"); - SetSize(XMFLOAT2(580, 600)); + SetSize(XMFLOAT2(580, 580)); float x = 150; float y = 0; float hei = 18; float step = hei + 2; + float infolabel_height = 190; meshInfoLabel.Create("Mesh Info"); meshInfoLabel.SetPos(XMFLOAT2(x - 50, y += step)); - meshInfoLabel.SetSize(XMFLOAT2(450, 190)); + meshInfoLabel.SetSize(XMFLOAT2(450, infolabel_height)); meshInfoLabel.SetColor(wi::Color::Transparent()); AddWidget(&meshInfoLabel); // Left side: - y = meshInfoLabel.GetScale().y + 5; + y = infolabel_height + 10; subsetComboBox.Create("Selected subset: "); subsetComboBox.SetSize(XMFLOAT2(40, hei)); @@ -49,35 +50,6 @@ void MeshWindow::Create(EditorComponent* editor) subsetComboBox.SetTooltip("Select a subset. A subset can also be selected by picking it in the 3D scene."); AddWidget(&subsetComboBox); - terrainCheckBox.Create("Terrain: "); - terrainCheckBox.SetTooltip("If enabled, the mesh will use multiple materials and blend between them based on vertex colors."); - terrainCheckBox.SetSize(XMFLOAT2(hei, hei)); - terrainCheckBox.SetPos(XMFLOAT2(x, y += step)); - terrainCheckBox.OnClick([&](wi::gui::EventArgs args) { - MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr) - { - mesh->SetTerrain(args.bValue); - if (args.bValue && mesh->vertex_colors.empty()) - { - mesh->vertex_colors.resize(mesh->vertex_positions.size()); - std::fill(mesh->vertex_colors.begin(), mesh->vertex_colors.end(), wi::Color::Red().rgba); // fill red (meaning only blend base material) - mesh->CreateRenderData(); - - for (auto& subset : mesh->subsets) - { - MaterialComponent* material = wi::scene::GetScene().materials.GetComponent(subset.materialID); - if (material != nullptr) - { - material->SetUseVertexColors(true); - } - } - } - SetEntity(entity, subset); // refresh information label - } - }); - AddWidget(&terrainCheckBox); - doubleSidedCheckBox.Create("Double Sided: "); doubleSidedCheckBox.SetTooltip("If enabled, the inside of the mesh will be visible."); doubleSidedCheckBox.SetSize(XMFLOAT2(hei, hei)); @@ -165,14 +137,14 @@ void MeshWindow::Create(EditorComponent* editor) impostorCreateButton.SetSize(XMFLOAT2(200, hei)); impostorCreateButton.SetPos(XMFLOAT2(x - 50, y += step)); impostorCreateButton.OnClick([&](wi::gui::EventArgs args) { - Scene& scene = wi::scene::GetScene(); + Scene& scene = wi::scene::GetScene(); ImpostorComponent* impostor = scene.impostors.GetComponent(entity); - if (impostor == nullptr) + if (impostor == nullptr) { - impostorCreateButton.SetText("Delete Impostor"); + impostorCreateButton.SetText("Delete Impostor"); scene.impostors.Create(entity).swapInDistance = impostorDistanceSlider.GetValue(); } - else + else { impostorCreateButton.SetText("Create Impostor"); scene.impostors.Remove(entity); @@ -497,10 +469,12 @@ void MeshWindow::Create(EditorComponent* editor) AddWidget(&optimizeButton); - // Right side: + + + // Right side: x = 150; - y = meshInfoLabel.GetScale().y + 5; + y = infolabel_height + 10; subsetMaterialComboBox.Create("Subset Material: "); subsetMaterialComboBox.SetSize(XMFLOAT2(200, hei)); @@ -526,82 +500,16 @@ void MeshWindow::Create(EditorComponent* editor) subsetMaterialComboBox.SetTooltip("Set the base material of the selected MeshSubset"); AddWidget(&subsetMaterialComboBox); - terrainMat1Combo.Create("Terrain Material 1: "); - terrainMat1Combo.SetSize(XMFLOAT2(200, hei)); - terrainMat1Combo.SetPos(XMFLOAT2(x + 180, y += step)); - terrainMat1Combo.SetEnabled(false); - terrainMat1Combo.OnSelect([&](wi::gui::EventArgs args) { - MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr) - { - if (args.iValue == 0) - { - mesh->terrain_material1 = INVALID_ENTITY; - } - else - { - Scene& scene = wi::scene::GetScene(); - mesh->terrain_material1 = scene.materials.GetEntity(args.iValue - 1); - } - } - }); - terrainMat1Combo.SetTooltip("Choose a sub terrain blend material. (GREEN vertex color mask)"); - AddWidget(&terrainMat1Combo); - - terrainMat2Combo.Create("Terrain Material 2: "); - terrainMat2Combo.SetSize(XMFLOAT2(200, hei)); - terrainMat2Combo.SetPos(XMFLOAT2(x + 180, y += step)); - terrainMat2Combo.SetEnabled(false); - terrainMat2Combo.OnSelect([&](wi::gui::EventArgs args) { - MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr) - { - if (args.iValue == 0) - { - mesh->terrain_material2 = INVALID_ENTITY; - } - else - { - Scene& scene = wi::scene::GetScene(); - mesh->terrain_material2 = scene.materials.GetEntity(args.iValue - 1); - } - } - }); - terrainMat2Combo.SetTooltip("Choose a sub terrain blend material. (BLUE vertex color mask)"); - AddWidget(&terrainMat2Combo); - - terrainMat3Combo.Create("Terrain Material 3: "); - terrainMat3Combo.SetSize(XMFLOAT2(200, hei)); - terrainMat3Combo.SetPos(XMFLOAT2(x + 180, y += step)); - terrainMat3Combo.SetEnabled(false); - terrainMat3Combo.OnSelect([&](wi::gui::EventArgs args) { - MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr) - { - if (args.iValue == 0) - { - mesh->terrain_material3 = INVALID_ENTITY; - } - else - { - Scene& scene = wi::scene::GetScene(); - mesh->terrain_material3 = scene.materials.GetEntity(args.iValue - 1); - } - } - }); - terrainMat3Combo.SetTooltip("Choose a sub terrain blend material. (ALPHA vertex color mask)"); - AddWidget(&terrainMat3Combo); - morphTargetCombo.Create("Morph Target:"); morphTargetCombo.SetSize(XMFLOAT2(100, hei)); morphTargetCombo.SetPos(XMFLOAT2(x + 280, y += step)); morphTargetCombo.OnSelect([&](wi::gui::EventArgs args) { - MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr && args.iValue < (int)mesh->targets.size()) - { + MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); + if (mesh != nullptr && args.iValue < (int)mesh->targets.size()) + { morphTargetSlider.SetValue(mesh->targets[args.iValue].weight); - } + } }); morphTargetCombo.SetTooltip("Choose a morph target to edit weight."); AddWidget(&morphTargetCombo); @@ -611,12 +519,12 @@ void MeshWindow::Create(EditorComponent* editor) morphTargetSlider.SetSize(XMFLOAT2(100, hei)); morphTargetSlider.SetPos(XMFLOAT2(x + 280, y += step)); morphTargetSlider.OnSlide([&](wi::gui::EventArgs args) { - MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); - if (mesh != nullptr && morphTargetCombo.GetSelected() < (int)mesh->targets.size()) - { + MeshComponent* mesh = wi::scene::GetScene().meshes.GetComponent(entity); + if (mesh != nullptr && morphTargetCombo.GetSelected() < (int)mesh->targets.size()) + { mesh->targets[morphTargetCombo.GetSelected()].weight = args.fValue; mesh->dirty_morph = true; - } + } }); AddWidget(&morphTargetSlider); @@ -793,11 +701,8 @@ void MeshWindow::SetEntity(Entity entity, int subset) if (mesh->vb_tan.IsValid()) ss += "tangent; "; if (mesh->so_pos_nor_wind.IsValid()) ss += "streamout_position; "; if (mesh->so_tan.IsValid()) ss += "streamout_tangents; "; - if (mesh->IsTerrain()) ss += "\n\nTerrain will use 4 blend materials and blend by vertex colors, the default one is always the subset material and uses RED vertex color channel mask, the other 3 are selectable below."; meshInfoLabel.SetText(ss); - terrainCheckBox.SetCheck(mesh->IsTerrain()); - subsetComboBox.ClearItems(); for (size_t i = 0; i < mesh->subsets.size(); ++i) { @@ -810,37 +715,16 @@ void MeshWindow::SetEntity(Entity entity, int subset) subsetMaterialComboBox.ClearItems(); subsetMaterialComboBox.AddItem("NO MATERIAL"); - terrainMat1Combo.ClearItems(); - terrainMat1Combo.AddItem("OFF (Use subset)"); - terrainMat2Combo.ClearItems(); - terrainMat2Combo.AddItem("OFF (Use subset)"); - terrainMat3Combo.ClearItems(); - terrainMat3Combo.AddItem("OFF (Use subset)"); for (size_t i = 0; i < scene.materials.GetCount(); ++i) { Entity entity = scene.materials.GetEntity(i); const NameComponent& name = *scene.names.GetComponent(entity); subsetMaterialComboBox.AddItem(name.name); - terrainMat1Combo.AddItem(name.name); - terrainMat2Combo.AddItem(name.name); - terrainMat3Combo.AddItem(name.name); if (subset >= 0 && subset < mesh->subsets.size() && mesh->subsets[subset].materialID == entity) { subsetMaterialComboBox.SetSelected((int)i + 1); } - if (mesh->terrain_material1 == entity) - { - terrainMat1Combo.SetSelected((int)i + 1); - } - if (mesh->terrain_material2 == entity) - { - terrainMat2Combo.SetSelected((int)i + 1); - } - if (mesh->terrain_material3 == entity) - { - terrainMat3Combo.SetSelected((int)i + 1); - } } doubleSidedCheckBox.SetCheck(mesh->IsDoubleSided()); @@ -867,11 +751,11 @@ void MeshWindow::SetEntity(Entity entity, int subset) morphTargetCombo.ClearItems(); for (size_t i = 0; i < mesh->targets.size(); i++) { - morphTargetCombo.AddItem(std::to_string(i).c_str()); + morphTargetCombo.AddItem(std::to_string(i).c_str()); } if (selected < mesh->targets.size()) { - morphTargetCombo.SetSelected(selected); + morphTargetCombo.SetSelected(selected); } SetEnabled(true); diff --git a/Editor/MeshWindow.h b/Editor/MeshWindow.h index 07707aa80..98f64e865 100644 --- a/Editor/MeshWindow.h +++ b/Editor/MeshWindow.h @@ -5,7 +5,6 @@ class EditorComponent; class MeshWindow : public wi::gui::Window { - bool terragen_initialized = false; public: void Create(EditorComponent* editor); @@ -33,11 +32,6 @@ public: wi::gui::Button mergeButton; wi::gui::Button optimizeButton; - wi::gui::CheckBox terrainCheckBox; - wi::gui::ComboBox terrainMat1Combo; - wi::gui::ComboBox terrainMat2Combo; - wi::gui::ComboBox terrainMat3Combo; - wi::gui::ComboBox morphTargetCombo; wi::gui::Slider morphTargetSlider; diff --git a/Editor/TerrainGenerator.cpp b/Editor/TerrainGenerator.cpp index 16fbe52e8..4bb4a5657 100644 --- a/Editor/TerrainGenerator.cpp +++ b/Editor/TerrainGenerator.cpp @@ -5,6 +5,7 @@ using namespace wi::ecs; using namespace wi::scene; +using namespace wi::graphics; enum PRESET { @@ -161,31 +162,31 @@ void TerrainGenerator::init() ClearTransform(); wi::gui::Window::Create("TerraGen (Preview version)"); - SetSize(XMFLOAT2(410, 560)); + SetSize(XMFLOAT2(420, 590)); - float xx = 150; - float yy = 0; - float stepstep = 25; - float heihei = 20; + float x = 160; + float y = 0; + float step = 25; + float hei = 20; centerToCamCheckBox.Create("Center to Cam: "); centerToCamCheckBox.SetTooltip("Automatically generate chunks around camera. This sets the center chunk to camera position."); - centerToCamCheckBox.SetSize(XMFLOAT2(heihei, heihei)); - centerToCamCheckBox.SetPos(XMFLOAT2(xx, yy += stepstep)); + centerToCamCheckBox.SetSize(XMFLOAT2(hei, hei)); + centerToCamCheckBox.SetPos(XMFLOAT2(x, y += step)); centerToCamCheckBox.SetCheck(true); AddWidget(¢erToCamCheckBox); removalCheckBox.Create("Removal: "); removalCheckBox.SetTooltip("Automatically remove chunks that are farther than generation distance around center chunk."); - removalCheckBox.SetSize(XMFLOAT2(heihei, heihei)); - removalCheckBox.SetPos(XMFLOAT2(xx + 100, yy)); + removalCheckBox.SetSize(XMFLOAT2(hei, hei)); + removalCheckBox.SetPos(XMFLOAT2(x + 100, y)); removalCheckBox.SetCheck(true); AddWidget(&removalCheckBox); - lodSlider.Create(0.0001f, 0.01f, 0.005f, 10000, "LOD Distance: "); + lodSlider.Create(0.0001f, 0.01f, 0.005f, 10000, "Mesh LOD Distance: "); lodSlider.SetTooltip("Set the LOD (Level Of Detail) distance multiplier.\nLow values increase LOD detail in distance"); - lodSlider.SetSize(XMFLOAT2(200, heihei)); - lodSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + lodSlider.SetSize(XMFLOAT2(200, hei)); + lodSlider.SetPos(XMFLOAT2(x, y += step)); lodSlider.OnSlide([this](wi::gui::EventArgs args) { for (auto& it : chunks) { @@ -202,16 +203,22 @@ void TerrainGenerator::init() }); AddWidget(&lodSlider); + texlodSlider.Create(0.01f, 0.05f, 0.01f, 10000, "Texture LOD Distance: "); + texlodSlider.SetTooltip("Set the LOD (Level Of Detail) distance multiplier.\nLow values increase LOD detail in distance"); + texlodSlider.SetSize(XMFLOAT2(200, hei)); + texlodSlider.SetPos(XMFLOAT2(x, y += step)); + AddWidget(&texlodSlider); + generationSlider.Create(0, 16, 12, 16, "Generation Distance: "); generationSlider.SetTooltip("How far out chunks will be generated (value is in number of chunks)"); - generationSlider.SetSize(XMFLOAT2(200, heihei)); - generationSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + generationSlider.SetSize(XMFLOAT2(200, hei)); + generationSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&generationSlider); presetCombo.Create("Preset: "); presetCombo.SetTooltip("Select a terrain preset"); - presetCombo.SetSize(XMFLOAT2(200, heihei)); - presetCombo.SetPos(XMFLOAT2(xx, yy += stepstep)); + presetCombo.SetSize(XMFLOAT2(200, hei)); + presetCombo.SetPos(XMFLOAT2(x, y += step)); presetCombo.AddItem("Hills", PRESET_HILLS); presetCombo.AddItem("Islands", PRESET_ISLANDS); presetCombo.AddItem("Mountains", PRESET_MOUNTAINS); @@ -295,105 +302,105 @@ void TerrainGenerator::init() seedSlider.Create(1, 12345, 3926, 12344, "Seed: "); seedSlider.SetTooltip("Seed for terrain randomness"); - seedSlider.SetSize(XMFLOAT2(200, heihei)); - seedSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + seedSlider.SetSize(XMFLOAT2(200, hei)); + seedSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&seedSlider); bottomLevelSlider.Create(-100, 0, -60, 10000, "Bottom Level: "); bottomLevelSlider.SetTooltip("Terrain mesh grid lowest level"); - bottomLevelSlider.SetSize(XMFLOAT2(200, heihei)); - bottomLevelSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + bottomLevelSlider.SetSize(XMFLOAT2(200, hei)); + bottomLevelSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&bottomLevelSlider); topLevelSlider.Create(0, 5000, 380, 10000, "Top Level: "); topLevelSlider.SetTooltip("Terrain mesh grid topmost level"); - topLevelSlider.SetSize(XMFLOAT2(200, heihei)); - topLevelSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + topLevelSlider.SetSize(XMFLOAT2(200, hei)); + topLevelSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&topLevelSlider); perlinBlendSlider.Create(0, 1, 0.5f, 10000, "Perlin Blend: "); perlinBlendSlider.SetTooltip("Amount of perlin noise to use"); - perlinBlendSlider.SetSize(XMFLOAT2(200, heihei)); - perlinBlendSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + perlinBlendSlider.SetSize(XMFLOAT2(200, hei)); + perlinBlendSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&perlinBlendSlider); perlinFrequencySlider.Create(0.0001f, 0.01f, 0.0008f, 10000, "Perlin Frequency: "); perlinFrequencySlider.SetTooltip("Frequency for the perlin noise"); - perlinFrequencySlider.SetSize(XMFLOAT2(200, heihei)); - perlinFrequencySlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + perlinFrequencySlider.SetSize(XMFLOAT2(200, hei)); + perlinFrequencySlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&perlinFrequencySlider); perlinOctavesSlider.Create(1, 8, 6, 7, "Perlin Octaves: "); perlinOctavesSlider.SetTooltip("Octave count for the perlin noise"); - perlinOctavesSlider.SetSize(XMFLOAT2(200, heihei)); - perlinOctavesSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + perlinOctavesSlider.SetSize(XMFLOAT2(200, hei)); + perlinOctavesSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&perlinOctavesSlider); voronoiBlendSlider.Create(0, 1, 0.5f, 10000, "Voronoi Blend: "); voronoiBlendSlider.SetTooltip("Amount of voronoi to use for elevation"); - voronoiBlendSlider.SetSize(XMFLOAT2(200, heihei)); - voronoiBlendSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + voronoiBlendSlider.SetSize(XMFLOAT2(200, hei)); + voronoiBlendSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&voronoiBlendSlider); voronoiFrequencySlider.Create(0.0001f, 0.01f, 0.001f, 10000, "Voronoi Frequency: "); voronoiFrequencySlider.SetTooltip("Voronoi can create distinctly elevated areas, the more cells there are, smaller the consecutive areas"); - voronoiFrequencySlider.SetSize(XMFLOAT2(200, heihei)); - voronoiFrequencySlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + voronoiFrequencySlider.SetSize(XMFLOAT2(200, hei)); + voronoiFrequencySlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&voronoiFrequencySlider); voronoiFadeSlider.Create(0, 100, 2.59f, 10000, "Voronoi Fade: "); voronoiFadeSlider.SetTooltip("Fade out voronoi regions by distance from cell's center"); - voronoiFadeSlider.SetSize(XMFLOAT2(200, heihei)); - voronoiFadeSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + voronoiFadeSlider.SetSize(XMFLOAT2(200, hei)); + voronoiFadeSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&voronoiFadeSlider); voronoiShapeSlider.Create(0, 1, 0.7f, 10000, "Voronoi Shape: "); voronoiShapeSlider.SetTooltip("How much the voronoi shape will be kept"); - voronoiShapeSlider.SetSize(XMFLOAT2(200, heihei)); - voronoiShapeSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + voronoiShapeSlider.SetSize(XMFLOAT2(200, hei)); + voronoiShapeSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&voronoiShapeSlider); voronoiFalloffSlider.Create(0, 8, 6, 10000, "Voronoi Falloff: "); voronoiFalloffSlider.SetTooltip("Controls the falloff of the voronoi distance fade effect"); - voronoiFalloffSlider.SetSize(XMFLOAT2(200, heihei)); - voronoiFalloffSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + voronoiFalloffSlider.SetSize(XMFLOAT2(200, hei)); + voronoiFalloffSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&voronoiFalloffSlider); voronoiPerturbationSlider.Create(0, 1, 0.1f, 10000, "Voronoi Perturbation: "); voronoiPerturbationSlider.SetTooltip("Controls the random look of voronoi region edges"); - voronoiPerturbationSlider.SetSize(XMFLOAT2(200, heihei)); - voronoiPerturbationSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + voronoiPerturbationSlider.SetSize(XMFLOAT2(200, hei)); + voronoiPerturbationSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&voronoiPerturbationSlider); heightmapButton.Create("Load Heightmap..."); heightmapButton.SetTooltip("Load a heightmap texture, where the red channel corresponds to terrain height and the resolution to dimensions.\nThe heightmap will be placed in the world center."); - heightmapButton.SetSize(XMFLOAT2(200, heihei)); - heightmapButton.SetPos(XMFLOAT2(xx, yy += stepstep)); + heightmapButton.SetSize(XMFLOAT2(200, hei)); + heightmapButton.SetPos(XMFLOAT2(x, y += step)); AddWidget(&heightmapButton); heightmapBlendSlider.Create(0, 1, 1, 10000, "Heightmap Blend: "); heightmapBlendSlider.SetTooltip("Amount of displacement coming from the heightmap texture"); - heightmapBlendSlider.SetSize(XMFLOAT2(200, heihei)); - heightmapBlendSlider.SetPos(XMFLOAT2(xx, yy += stepstep)); + heightmapBlendSlider.SetSize(XMFLOAT2(200, hei)); + heightmapBlendSlider.SetPos(XMFLOAT2(x, y += step)); AddWidget(&heightmapBlendSlider); region1Slider.Create(0, 8, 1, 10000, "Slope Region: "); region1Slider.SetTooltip("The region's falloff power"); - region1Slider.SetSize(XMFLOAT2(200, heihei)); - region1Slider.SetPos(XMFLOAT2(xx, yy += stepstep)); + region1Slider.SetSize(XMFLOAT2(200, hei)); + region1Slider.SetPos(XMFLOAT2(x, y += step)); AddWidget(®ion1Slider); region2Slider.Create(0, 8, 2, 10000, "Low Altitude Region: "); region2Slider.SetTooltip("The region's falloff power"); - region2Slider.SetSize(XMFLOAT2(200, heihei)); - region2Slider.SetPos(XMFLOAT2(xx, yy += stepstep)); + region2Slider.SetSize(XMFLOAT2(200, hei)); + region2Slider.SetPos(XMFLOAT2(x, y += step)); AddWidget(®ion2Slider); region3Slider.Create(0, 8, 8, 10000, "High Altitude Region: "); region3Slider.SetTooltip("The region's falloff power"); - region3Slider.SetSize(XMFLOAT2(200, heihei)); - region3Slider.SetPos(XMFLOAT2(xx, yy += stepstep)); + region3Slider.SetSize(XMFLOAT2(200, hei)); + region3Slider.SetPos(XMFLOAT2(x, y += step)); AddWidget(®ion3Slider); @@ -457,61 +464,12 @@ void TerrainGenerator::Generation_Restart() Generation_Cancel(); generation_scene.Clear(); - // If these already exist, save them before recreating: - // (This is helpful if eg: someone edits them in the editor and then regenerates the terrain) - if (materialEntity_Base != INVALID_ENTITY) - { - MaterialComponent* material = scene->materials.GetComponent(materialEntity_Base); - if (material != nullptr) - { - material_Base = *material; - } - } - if (materialEntity_Slope != INVALID_ENTITY) - { - MaterialComponent* material = scene->materials.GetComponent(materialEntity_Slope); - if (material != nullptr) - { - material_Slope = *material; - } - } - if (materialEntity_LowAltitude != INVALID_ENTITY) - { - MaterialComponent* material = scene->materials.GetComponent(materialEntity_LowAltitude); - if (material != nullptr) - { - material_LowAltitude = *material; - } - } - if (materialEntity_HighAltitude != INVALID_ENTITY) - { - MaterialComponent* material = scene->materials.GetComponent(materialEntity_HighAltitude); - if (material != nullptr) - { - material_HighAltitude = *material; - } - } - chunks.clear(); scene->Entity_Remove(terrainEntity); scene->transforms.Create(terrainEntity); scene->names.Create(terrainEntity) = "terrain"; - materialEntity_Base = scene->Entity_CreateMaterial("terrainMaterial_Base"); - materialEntity_Slope = scene->Entity_CreateMaterial("terrainMaterial_Slope"); - materialEntity_LowAltitude = scene->Entity_CreateMaterial("terrainMaterial_LowAltitude"); - materialEntity_HighAltitude = scene->Entity_CreateMaterial("terrainMaterial_HighAltitude"); - scene->Component_Attach(materialEntity_Base, terrainEntity); - scene->Component_Attach(materialEntity_Slope, terrainEntity); - scene->Component_Attach(materialEntity_LowAltitude, terrainEntity); - scene->Component_Attach(materialEntity_HighAltitude, terrainEntity); - // init/restore materials: - *scene->materials.GetComponent(materialEntity_Base) = material_Base; - *scene->materials.GetComponent(materialEntity_Slope) = material_Slope; - *scene->materials.GetComponent(materialEntity_LowAltitude) = material_LowAltitude; - *scene->materials.GetComponent(materialEntity_HighAltitude) = material_HighAltitude; - const uint32_t seed = (uint32_t)seedSlider.GetValue(); perlin.init(seed); @@ -564,7 +522,7 @@ void TerrainGenerator::Generation_Restart() } } -void TerrainGenerator::Generation_Update() +void TerrainGenerator::Generation_Update(const wi::scene::CameraComponent& camera) { // The generation task is always cancelled every frame so we are sure that generation is not running at this point Generation_Cancel(); @@ -580,20 +538,59 @@ void TerrainGenerator::Generation_Update() if (centerToCamCheckBox.GetCheck()) { - const CameraComponent& camera = GetCamera(); center_chunk.x = (int)std::floor((camera.Eye.x + chunk_half_width) * chunk_width_rcp); center_chunk.z = (int)std::floor((camera.Eye.z + chunk_half_width) * chunk_width_rcp); } - // Chunk removal checks: - if (removalCheckBox.GetCheck()) + const int removal_threshold = (int)generationSlider.GetValue() + 2; + const float texlodMultiplier = texlodSlider.GetValue(); + GraphicsDevice* device = GetDevice(); + virtual_texture_updates.clear(); + virtual_texture_barriers_begin.clear(); + virtual_texture_barriers_end.clear(); + + // Check whether there are any materials that would write to virtual textures: + uint32_t max_texture_resolution = 0; + bool virtual_texture_available[MaterialComponent::TEXTURESLOT_COUNT] = {}; + virtual_texture_available[MaterialComponent::SURFACEMAP] = true; // this is always needed to bake individual material properties + MaterialComponent* virtual_materials[4] = { + &material_Base, + &material_Slope, + &material_LowAltitude, + &material_HighAltitude, + }; + for (auto& material : virtual_materials) { - const int removal_threshold = (int)generationSlider.GetValue() + 2; - for (auto it = chunks.begin(); it != chunks.end();) + for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i) + { + switch (i) + { + case MaterialComponent::BASECOLORMAP: + case MaterialComponent::NORMALMAP: + case MaterialComponent::SURFACEMAP: + if (material->textures[i].resource.IsValid()) + { + virtual_texture_available[i] = true; + const TextureDesc& desc = material->textures[i].resource.GetTexture().GetDesc(); + max_texture_resolution = std::max(max_texture_resolution, desc.width); + max_texture_resolution = std::max(max_texture_resolution, desc.height); + } + break; + default: + break; + } + } + } + + for (auto it = chunks.begin(); it != chunks.end();) + { + const Chunk& chunk = it->first; + ChunkData& chunk_data = it->second; + const int dist = std::max(std::abs(center_chunk.x - chunk.x), std::abs(center_chunk.z - chunk.z)); + + // chunk removal: + if (removalCheckBox.GetCheck()) { - const Chunk& chunk = it->first; - ChunkData& chunk_data = it->second; - const int dist = std::max(std::abs(center_chunk.x - chunk.x), std::abs(center_chunk.z - chunk.z)); if (dist > removal_threshold) { scene->Entity_Remove(it->second.entity); @@ -607,18 +604,115 @@ void TerrainGenerator::Generation_Update() { if (dist > 1) { - wi::HairParticleSystem* grass = scene->hairs.GetComponent(chunk_data.entity); - if (grass != nullptr) - { - // remove this chunk's grass patch from the scene - scene->hairs.Remove(chunk_data.entity); - chunk_data.grass_exists = false; // grass can be generated here by generation thread... - } + scene->Entity_Remove(chunk_data.grass_entity); + chunk_data.grass_exists = false; // grass can be generated here by generation thread... } } } - it++; } + + // Collect virtual texture update requests: + if (max_texture_resolution > 0) + { + uint32_t texture_lod = 0; + const float distsq = wi::math::DistanceSquared(camera.Eye, chunk_data.sphere.center); + const float radius = chunk_data.sphere.radius; + const float radiussq = radius * radius; + if (distsq < radiussq) + { + texture_lod = 0; + } + else + { + const float dist = std::sqrt(distsq); + const float dist_to_sphere = dist - radius; + texture_lod = uint32_t(dist_to_sphere * texlodMultiplier); + } + + uint32_t chunk_required_texture_resolution = uint32_t(max_texture_resolution / std::pow(2.0f, (float)std::max(0u, texture_lod))); + chunk_required_texture_resolution = std::max(8u, chunk_required_texture_resolution); + if (chunk_data.virtual_texture_resolution != chunk_required_texture_resolution) + { + chunk_data.virtual_texture_resolution = chunk_required_texture_resolution; + + MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity); + if (material != nullptr) + { + for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i) + { + if (virtual_texture_available[i]) + { + TextureDesc desc; + desc.width = chunk_required_texture_resolution; + desc.height = chunk_required_texture_resolution; + desc.format = Format::R8G8B8A8_UNORM; + desc.bind_flags = BindFlag::SHADER_RESOURCE | BindFlag::UNORDERED_ACCESS; + Texture texture; + bool success = device->CreateTexture(&desc, nullptr, &texture); + assert(success); + + material->textures[i].resource.SetTexture(texture); + virtual_texture_barriers_begin.push_back(GPUBarrier::Image(&material->textures[i].resource.GetTexture(), desc.layout, ResourceState::UNORDERED_ACCESS)); + virtual_texture_barriers_end.push_back(GPUBarrier::Image(&material->textures[i].resource.GetTexture(), ResourceState::UNORDERED_ACCESS, desc.layout)); + } + } + + virtual_texture_updates.push_back(chunk); + } + + } + } + + it++; + } + + // Execute batched virtual texture updates: + if (!virtual_texture_updates.empty()) + { + CommandList cmd = device->BeginCommandList(); + device->EventBegin("TerrainVirtualTextureUpdate", cmd); + auto range = wi::profiler::BeginRangeGPU("TerrainVirtualTextureUpdate", cmd); + device->Barrier(virtual_texture_barriers_begin.data(), (uint32_t)virtual_texture_barriers_begin.size(), cmd); + + device->BindComputeShader(wi::renderer::GetShader(wi::enums::CSTYPE_TERRAIN_VIRTUALTEXTURE_UPDATE), cmd); + + ShaderMaterial materials[4]; + material_Base.WriteShaderMaterial(&materials[0]); + material_Slope.WriteShaderMaterial(&materials[1]); + material_LowAltitude.WriteShaderMaterial(&materials[2]); + material_HighAltitude.WriteShaderMaterial(&materials[3]); + device->BindDynamicConstantBuffer(materials, 10, cmd); + + for (auto& chunk : virtual_texture_updates) + { + auto it = chunks.find(chunk); + if (it == chunks.end()) + continue; + ChunkData& chunk_data = it->second; + + const GPUResource* res[] = { + &chunk_data.region_weights_texture, + }; + device->BindResources(res, 0, arraysize(res), cmd); + + const MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity); + if (material != nullptr) + { + for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i) + { + if (virtual_texture_available[i]) + { + device->BindUAV(material->textures[i].GetGPUResource(), i, cmd); + } + } + } + + device->Dispatch(chunk_data.virtual_texture_resolution / 8u, chunk_data.virtual_texture_resolution / 8u, 1, cmd); + } + + device->Barrier(virtual_texture_barriers_end.data(), (uint32_t)virtual_texture_barriers_end.size(), cmd); + wi::profiler::EndRange(range); + device->EventEnd(cmd); } // Start the generation on a background thread and keep it running until the next frame @@ -667,24 +761,26 @@ void TerrainGenerator::Generation_Update() transform.Translate(chunk_pos); transform.UpdateTransform(); + MaterialComponent& material = generation_scene.materials.Create(chunk_data.entity); + // material params will be 1 because they will be created from only texture maps + // because region materials are blended together into one texture + material.SetRoughness(1); + material.SetMetalness(1); + material.SetReflectance(1); + MeshComponent& mesh = generation_scene.meshes.Create(chunk_data.entity); object.meshID = chunk_data.entity; mesh.indices = indices; - mesh.SetTerrain(true); - mesh.terrain_material1 = materialEntity_Slope; - mesh.terrain_material2 = materialEntity_LowAltitude; - mesh.terrain_material3 = materialEntity_HighAltitude; for (auto& lod : lods) { mesh.subsets.emplace_back(); - mesh.subsets.back().materialID = materialEntity_Base; + mesh.subsets.back().materialID = chunk_data.entity; mesh.subsets.back().indexCount = lod.indexCount; mesh.subsets.back().indexOffset = lod.indexOffset; } mesh.subsets_per_lod = 1; mesh.vertex_positions.resize(vertexCount); mesh.vertex_normals.resize(vertexCount); - mesh.vertex_colors.resize(vertexCount); mesh.vertex_uvset_0.resize(vertexCount); wi::HairParticleSystem grass = grass_properties; @@ -763,9 +859,10 @@ void TerrainGenerator::Generation_Update() materialBlendWeights.z *= weight_norm; materialBlendWeights.w *= weight_norm; + chunk_data.region_weights[index] = wi::Color::fromFloat4(materialBlendWeights); + mesh.vertex_positions[index] = XMFLOAT3(x, height, z); mesh.vertex_normals[index] = normal; - mesh.vertex_colors[index] = wi::Color::fromFloat4(materialBlendWeights); const XMFLOAT2 uv = XMFLOAT2(x * chunk_width_rcp + 0.5f, z * chunk_width_rcp + 0.5f); mesh.vertex_uvset_0[index] = uv; @@ -788,16 +885,21 @@ void TerrainGenerator::Generation_Update() wi::jobsystem::Execute(ctx, [&](wi::jobsystem::JobArgs args) { mesh.CreateRenderData(); + chunk_data.sphere.center = mesh.aabb.getCenter(); + chunk_data.sphere.center.x += chunk_pos.x; + chunk_data.sphere.center.y += chunk_pos.y; + chunk_data.sphere.center.z += chunk_pos.z; + chunk_data.sphere.radius = mesh.aabb.getRadius(); }); // If there were any vertices in this chunk that could be valid for grass, store the grass particle system: if (grass_valid_vertex_count.load() > 0) { + chunk_data.grass_entity = CreateEntity(); chunk_data.grass = std::move(grass); // the grass will be added to the scene later, only when the chunk is close to the camera (center chunk's neighbors) chunk_data.grass.meshID = chunk_data.entity; chunk_data.grass.strandCount = grass_valid_vertex_count.load() * 3; chunk_data.grass.viewDistance = chunk_width; - generation_scene.materials.Create(chunk_data.entity) = material_GrassParticle; } // Prop placement: @@ -817,12 +919,9 @@ void TerrainGenerator::Generation_Update() const XMFLOAT3& pos0 = mesh.vertex_positions[ind0]; const XMFLOAT3& pos1 = mesh.vertex_positions[ind1]; const XMFLOAT3& pos2 = mesh.vertex_positions[ind2]; - const uint32_t& col0 = mesh.vertex_colors[ind0]; - const uint32_t& col1 = mesh.vertex_colors[ind1]; - const uint32_t& col2 = mesh.vertex_colors[ind2]; - const XMFLOAT4 region0 = wi::Color(col0).toFloat4(); - const XMFLOAT4 region1 = wi::Color(col1).toFloat4(); - const XMFLOAT4 region2 = wi::Color(col2).toFloat4(); + const XMFLOAT4 region0 = chunk_data.region_weights[ind0]; + const XMFLOAT4 region1 = chunk_data.region_weights[ind1]; + const XMFLOAT4 region2 = chunk_data.region_weights[ind2]; // random barycentric coords on the triangle: float f = float_distr(chunk_data.prop_rand); float g = float_distr(chunk_data.prop_rand); @@ -863,6 +962,20 @@ void TerrainGenerator::Generation_Update() } } + // Create the blend weights texture for virtual texture update: + { + TextureDesc desc; + desc.width = (uint32_t)chunk_width; + desc.height = (uint32_t)chunk_width; + desc.format = Format::R8G8B8A8_UNORM; + desc.bind_flags = BindFlag::SHADER_RESOURCE; + SubresourceData data; + data.data_ptr = chunk_data.region_weights; + data.row_pitch = chunk_width * sizeof(chunk_data.region_weights[0]); + bool success = device->CreateTexture(&desc, &data, &chunk_data.region_weights_texture); + assert(success); + } + wi::jobsystem::Wait(ctx); // wait until mesh.CreateRenderData() async task finishes generated_something = true; } @@ -880,13 +993,12 @@ void TerrainGenerator::Generation_Update() if (!chunk_data.grass_exists) { // add patch for this chunk - wi::HairParticleSystem& grass = generation_scene.hairs.Create(chunk_data.entity); + wi::HairParticleSystem& grass = generation_scene.hairs.Create(chunk_data.grass_entity); grass = chunk_data.grass; - const MeshComponent* mesh = generation_scene.meshes.GetComponent(chunk_data.entity); - if (mesh != nullptr) - { - grass.CreateRenderData(*mesh); - } + generation_scene.materials.Create(chunk_data.grass_entity) = material_GrassParticle; + generation_scene.transforms.Create(chunk_data.grass_entity); + generation_scene.names.Create(chunk_data.grass_entity) = "grass"; + generation_scene.Component_Attach(chunk_data.grass_entity, chunk_data.entity, true); chunk_data.grass_exists = true; // don't generate more grass here generated_something = true; } @@ -947,3 +1059,84 @@ void TerrainGenerator::Generation_Cancel() wi::jobsystem::Wait(generation_workload); // waits until generation thread exits generation_cancelled.store(false); // the next generation can run } + +void TerrainGenerator::BakeVirtualTexturesToFiles() +{ + if (terrainEntity == INVALID_ENTITY) + { + return; + } + + wi::jobsystem::context ctx; + + static const std::string extension = "PNG"; + + for (auto it = chunks.begin(); it != chunks.end(); it++) + { + const Chunk& chunk = it->first; + ChunkData& chunk_data = it->second; + MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity); + if (material != nullptr) + { + for (int i = 0; i < MaterialComponent::TEXTURESLOT_COUNT; ++i) + { + auto& tex = material->textures[i]; + switch (i) + { + case MaterialComponent::BASECOLORMAP: + case MaterialComponent::SURFACEMAP: + case MaterialComponent::NORMALMAP: + if (tex.name.empty() && tex.GetGPUResource() != nullptr) + { + wi::vector filedata; + if (wi::helper::saveTextureToMemory(tex.resource.GetTexture(), filedata)) + { + tex.resource.SetFileData(std::move(filedata)); + wi::jobsystem::Execute(ctx, [i, &tex, chunk](wi::jobsystem::JobArgs args) { + wi::vector filedata_ktx2; + if (wi::helper::saveTextureToMemoryFile(tex.resource.GetFileData(), tex.resource.GetTexture().desc, extension, filedata_ktx2)) + { + tex.name = std::to_string(chunk.x) + "_" + std::to_string(chunk.z); + switch (i) + { + case MaterialComponent::BASECOLORMAP: + tex.name += "_basecolormap"; + break; + case MaterialComponent::SURFACEMAP: + tex.name += "_surfacemap"; + break; + case MaterialComponent::NORMALMAP: + tex.name += "_normalmap"; + break; + default: + break; + } + tex.name += "." + extension; + tex.resource = wi::resourcemanager::Load(tex.name, wi::resourcemanager::Flags::IMPORT_RETAIN_FILEDATA, filedata_ktx2.data(), filedata_ktx2.size()); + } + }); + } + } + break; + default: + break; + } + } + } + } + + wi::helper::messageBox("Baking terrain virtual textures, this could take a while!", "Attention!"); + + wi::jobsystem::Wait(ctx); + + for (auto it = chunks.begin(); it != chunks.end(); it++) + { + const Chunk& chunk = it->first; + ChunkData& chunk_data = it->second; + MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity); + if (material != nullptr) + { + material->CreateRenderData(); + } + } +} diff --git a/Editor/TerrainGenerator.h b/Editor/TerrainGenerator.h index bfbc09c9f..338de55df 100644 --- a/Editor/TerrainGenerator.h +++ b/Editor/TerrainGenerator.h @@ -29,27 +29,28 @@ namespace std }; } +inline static const int chunk_width = 64 + 3; // + 3: filler vertices for lod apron and grid perimeter +inline static const float chunk_half_width = (chunk_width - 1) * 0.5f; +inline static const float chunk_width_rcp = 1.0f / (chunk_width - 1); +inline static const uint32_t vertexCount = chunk_width * chunk_width; +inline static const int max_lod = (int)std::log2(chunk_width - 3) + 1; struct ChunkData { wi::ecs::Entity entity = wi::ecs::INVALID_ENTITY; + wi::ecs::Entity grass_entity = wi::ecs::INVALID_ENTITY; wi::HairParticleSystem grass; bool grass_exists = false; std::mt19937 prop_rand; + wi::Color region_weights[vertexCount] = {}; + wi::graphics::Texture region_weights_texture; + uint32_t virtual_texture_resolution = 0; + wi::primitive::Sphere sphere; }; struct TerrainGenerator : public wi::gui::Window { - inline static const int chunk_width = 64 + 3; // + 3: filler vertices for lod apron and grid perimeter - inline static const float chunk_half_width = (chunk_width - 1) * 0.5f; - inline static const float chunk_width_rcp = 1.0f / (chunk_width - 1); - inline static const uint32_t vertexCount = chunk_width * chunk_width; - inline static const int max_lod = (int)std::log2(chunk_width - 3) + 1; - wi::scene::Scene* scene = &wi::scene::GetScene(); // by default it uses the global scene, but this can be changed wi::ecs::Entity terrainEntity = wi::ecs::INVALID_ENTITY; - wi::ecs::Entity materialEntity_Base = wi::ecs::INVALID_ENTITY; - wi::ecs::Entity materialEntity_Slope = wi::ecs::INVALID_ENTITY; - wi::ecs::Entity materialEntity_LowAltitude = wi::ecs::INVALID_ENTITY; - wi::ecs::Entity materialEntity_HighAltitude = wi::ecs::INVALID_ENTITY; + wi::scene::Scene* scene = &wi::scene::GetScene(); // by default it uses the global scene, but this can be changed wi::scene::MaterialComponent material_Base; wi::scene::MaterialComponent material_Slope; wi::scene::MaterialComponent material_LowAltitude; @@ -99,9 +100,18 @@ struct TerrainGenerator : public wi::gui::Window std::atomic_bool generation_cancelled; float generation_time_budget_milliseconds = 12; // after this much time, the generation thread will exit. This can help avoid a very long running, resource consuming and slow cancellation generation + // Virtual texture updates will be batched like: + // 1) Execute all barriers (dst: UNORDERED_ACCESS) + // 2) Execute all compute shaders + // 3) Execute all barriers (dst: SHADER_RESOURCE) + wi::vector virtual_texture_updates; + wi::vector virtual_texture_barriers_begin; + wi::vector virtual_texture_barriers_end; + wi::gui::CheckBox centerToCamCheckBox; wi::gui::CheckBox removalCheckBox; wi::gui::Slider lodSlider; + wi::gui::Slider texlodSlider; wi::gui::Slider generationSlider; wi::gui::ComboBox presetCombo; wi::gui::Slider seedSlider; @@ -130,8 +140,10 @@ struct TerrainGenerator : public wi::gui::Window // This will remove previously existing terrain void Generation_Restart(); // This will run the actual generation tasks, call it once per frame - void Generation_Update(); + void Generation_Update(const wi::scene::CameraComponent& camera); // Tells the generation thread that it should be cancelled and blocks until that is confirmed void Generation_Cancel(); + // The virtual textures will be compressed and saved into resources. They can be serialized from there + void BakeVirtualTexturesToFiles(); }; diff --git a/Editor/WeatherWindow.cpp b/Editor/WeatherWindow.cpp index ad99f888c..d2fc8fd8d 100644 --- a/Editor/WeatherWindow.cpp +++ b/Editor/WeatherWindow.cpp @@ -605,7 +605,7 @@ void WeatherWindow::Create(EditorComponent* editor) ktxConvButton.Create("KTX2 Convert"); - ktxConvButton.SetTooltip("All material textures in the scene will be cinverted to KTX2 format.\nTHIS MIGHT TAKE LONG, SO GET YOURSELF A COFFEE OR TEA!"); + ktxConvButton.SetTooltip("All material textures in the scene will be converted to KTX2 format.\nTHIS MIGHT TAKE LONG, SO GET YOURSELF A COFFEE OR TEA!"); ktxConvButton.SetSize(XMFLOAT2(colorPicker.GetScale().x, hei)); ktxConvButton.SetPos(XMFLOAT2(x, y += step)); ktxConvButton.OnClick([=](wi::gui::EventArgs args) { diff --git a/WickedEngine/ArchiveVersionHistory.txt b/WickedEngine/ArchiveVersionHistory.txt index 01d9c76ba..cd887782d 100644 --- a/WickedEngine/ArchiveVersionHistory.txt +++ b/WickedEngine/ArchiveVersionHistory.txt @@ -1,5 +1,6 @@ This file contains changelog of wi::Archive versions +79: removed terrain blend materials from mesh 78: serialized stars parameter in weather 77: serialized cloud shadow properties 76: serialized LOD parameters diff --git a/WickedEngine/offlineshadercompiler.cpp b/WickedEngine/offlineshadercompiler.cpp index ea68c11b9..f1dac1fce 100644 --- a/WickedEngine/offlineshadercompiler.cpp +++ b/WickedEngine/offlineshadercompiler.cpp @@ -246,6 +246,7 @@ int main(int argc, char* argv[]) "ddgi_raytraceCS_rtapi.hlsl", "ddgi_updateCS.hlsl", "ddgi_updateCS_depth.hlsl", + "terrainVirtualTextureUpdateCS.hlsl", }; shaders[static_cast(ShaderStage::PS)] = { @@ -275,12 +276,10 @@ int main(int argc, char* argv[]) "objectPS_transparent_pom.hlsl" , "objectPS_water.hlsl" , "objectPS_voxelizer.hlsl" , - "objectPS_voxelizer_terrain.hlsl" , "objectPS_transparent.hlsl" , "objectPS_transparent_planarreflection.hlsl" , "objectPS_planarreflection.hlsl" , "objectPS_pom.hlsl" , - "objectPS_terrain.hlsl" , "objectPS.hlsl" , "objectPS_hologram.hlsl" , "objectPS_paintradius.hlsl" , @@ -312,7 +311,6 @@ int main(int argc, char* argv[]) "envMap_skyPS_static.hlsl" , "envMap_skyPS_dynamic.hlsl" , "envMapPS.hlsl" , - "envMapPS_terrain.hlsl" , "emittedparticlePS_soft_distortion.hlsl" , "downsampleDepthBuffer4xPS.hlsl" , "emittedparticlePS_simple.hlsl" , diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index 0a369fbe3..32f983bac 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -159,10 +159,8 @@ struct ShaderGeometry int vb_atl; int vb_pre; + uint3 padding; uint materialIndex; - uint blendmaterial1; - uint blendmaterial2; - uint blendmaterial3; float3 aabb_min; uint flags; @@ -182,9 +180,6 @@ struct ShaderGeometry vb_pre = -1; materialIndex = 0; - blendmaterial1 = 0; - blendmaterial2 = 0; - blendmaterial3 = 0; aabb_min = float3(0, 0, 0); flags = 0; diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index c86e2326a..44e560be2 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -1062,6 +1062,10 @@ Compute 4.0 + + Compute + 4.0 + Compute 4.0 @@ -1447,16 +1451,6 @@ Pixel Pixel - - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Vertex Vertex @@ -2205,17 +2199,6 @@ Pixel Document - - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Document - Pixel Pixel @@ -2270,16 +2253,6 @@ Pixel Pixel - - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Pixel - Vertex Vertex diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index eed48d987..d25ab88be 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -551,9 +551,6 @@ PS - - PS - PS @@ -596,9 +593,6 @@ PS - - PS - PS @@ -764,9 +758,6 @@ PS - - PS - PS @@ -1052,6 +1043,9 @@ CS + + CS + diff --git a/WickedEngine/shaders/envMapPS_terrain.hlsl b/WickedEngine/shaders/envMapPS_terrain.hlsl deleted file mode 100644 index 095b21cc0..000000000 --- a/WickedEngine/shaders/envMapPS_terrain.hlsl +++ /dev/null @@ -1,2 +0,0 @@ -#define TERRAIN -#include "envMapPS.hlsl" diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index 006c514ed..90fb1cb13 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -40,18 +40,6 @@ inline ShaderMaterial GetMaterial() { return load_material(push.GetMaterialIndex()); } -inline ShaderMaterial GetMaterial1() -{ - return load_material(GetMesh().blendmaterial1); -} -inline ShaderMaterial GetMaterial2() -{ - return load_material(GetMesh().blendmaterial2); -} -inline ShaderMaterial GetMaterial3() -{ - return load_material(GetMesh().blendmaterial3); -} #define sampler_objectshader bindless_samplers[GetFrame().sampler_objectshader_index] @@ -69,21 +57,6 @@ inline ShaderMaterial GetMaterial3() #define texture_clearcoatnormalmap bindless_textures[GetMaterial().texture_clearcoatnormalmap_index] #define texture_specularmap bindless_textures[GetMaterial().texture_specularmap_index] -#define texture_blend1_basecolormap bindless_textures[GetMaterial1().texture_basecolormap_index] -#define texture_blend1_normalmap bindless_textures[GetMaterial1().texture_normalmap_index] -#define texture_blend1_surfacemap bindless_textures[GetMaterial1().texture_surfacemap_index] -#define texture_blend1_emissivemap bindless_textures[GetMaterial1().texture_emissivemap_index] - -#define texture_blend2_basecolormap bindless_textures[GetMaterial2().texture_basecolormap_index] -#define texture_blend2_normalmap bindless_textures[GetMaterial2().texture_normalmap_index] -#define texture_blend2_surfacemap bindless_textures[GetMaterial2().texture_surfacemap_index] -#define texture_blend2_emissivemap bindless_textures[GetMaterial2().texture_emissivemap_index] - -#define texture_blend3_basecolormap bindless_textures[GetMaterial3().texture_basecolormap_index] -#define texture_blend3_normalmap bindless_textures[GetMaterial3().texture_normalmap_index] -#define texture_blend3_surfacemap bindless_textures[GetMaterial3().texture_surfacemap_index] -#define texture_blend3_emissivemap bindless_textures[GetMaterial3().texture_emissivemap_index] - uint load_entitytile(uint tileIndex) { #ifdef TRANSPARENT @@ -1050,7 +1023,6 @@ PixelInput main(VertexInput input) // PLANARREFLECTION - include planar reflection sampling // POM - include parallax occlusion mapping computation // WATER - include specialized water shader code -// TERRAIN - include specialized terrain material blending code #ifdef DISABLE_ALPHATEST [earlydepthstencil] @@ -1212,285 +1184,6 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_Target -#ifdef TERRAIN - color = 1; - surface.N = 0; - surface.albedo = 0; - surface.f0 = 0; - surface.roughness = 0; - surface.occlusion = 0; - surface.emissiveColor = 0; - surface.opacity = 1; - - float4 sam; - float4 blend_weights = input.color; - blend_weights /= blend_weights.x + blend_weights.y + blend_weights.z + blend_weights.w; - float3 baseN = normalize(input.nor); - - [branch] - if (blend_weights.x > 0) - { - float4 color2 = GetMaterial().baseColor; - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial().uvset_baseColorMap == 0 ? uvsets.xy : uvsets.zw; - float4 basecolorMap = texture_basecolormap.Sample(sampler_objectshader, uv); - basecolorMap.rgb = DEGAMMA(basecolorMap.rgb); - color2 *= basecolorMap; - } -#endif // OBJECTSHADER_USE_UVSETS - - float4 surfaceMap2 = 1; - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial().uvset_surfaceMap >= 0) - { - float2 uv = GetMaterial().uvset_surfaceMap == 0 ? uvsets.xy : uvsets.zw; - surfaceMap2 = texture_surfacemap.Sample(sampler_objectshader, uv); - } -#endif // OBJECTSHADER_USE_UVSETS - - Surface surface2; - surface2.N = baseN; - surface2.create(GetMaterial(), color2, surfaceMap2); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial().normalMapStrength > 0 && GetMaterial().uvset_normalMap >= 0) - { - float2 uv = GetMaterial().uvset_normalMap == 0 ? uvsets.xy : uvsets.zw; - sam.rgb = texture_normalmap.Sample(sampler_objectshader, uv).rgb; - sam.rgb = sam.rgb * 2 - 1; - surface2.N = lerp(baseN, mul(sam.rgb, TBN), GetMaterial().normalMapStrength); - } -#endif // OBJECTSHADER_USE_UVSETS - - surface2.emissiveColor = GetMaterial().GetEmissive(); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) - { - float2 uv = GetMaterial().uvset_emissiveMap == 0 ? uvsets.xy : uvsets.zw; - sam = texture_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam.rgb * sam.a; - } -#endif // OBJECTSHADER_USE_UVSETS - - surface.N += surface2.N * blend_weights.x; - surface.albedo += surface2.albedo * blend_weights.x; - surface.f0 += surface2.f0 * blend_weights.x; - surface.roughness += surface2.roughness * blend_weights.x; - surface.occlusion += surface2.occlusion * blend_weights.x; - surface.emissiveColor += surface2.emissiveColor * blend_weights.x; - } - - [branch] - if (blend_weights.y > 0) - { - float4 color2 = GetMaterial1().baseColor; - float4 uvsets = input.uvsets; - uvsets.xy = mad(uvsets.xy, GetMaterial1().texMulAdd.xy, GetMaterial1().texMulAdd.zw); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial1().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial1().uvset_baseColorMap == 0 ? uvsets.xy : uvsets.zw; - float4 basecolorMap = texture_blend1_basecolormap.Sample(sampler_objectshader, uv); - basecolorMap.rgb = DEGAMMA(basecolorMap.rgb); - color2 *= basecolorMap; - } -#endif // OBJECTSHADER_USE_UVSETS - - float4 surfaceMap2 = 1; - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial1().uvset_surfaceMap >= 0) - { - float2 uv = GetMaterial1().uvset_surfaceMap == 0 ? uvsets.xy : uvsets.zw; - surfaceMap2 = texture_blend1_surfacemap.Sample(sampler_objectshader, uv); - } -#endif // OBJECTSHADER_USE_UVSETS - - Surface surface2; - surface2.N = baseN; - surface2.create(GetMaterial1(), color2, surfaceMap2); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial1().normalMapStrength > 0 && GetMaterial1().uvset_normalMap >= 0) - { - float2 uv = GetMaterial1().uvset_normalMap == 0 ? uvsets.xy : uvsets.zw; - sam.rgb = texture_blend1_normalmap.Sample(sampler_objectshader, uv).rgb; - sam.rgb = sam.rgb * 2 - 1; - surface2.N = lerp(baseN, mul(sam.rgb, TBN), GetMaterial1().normalMapStrength); - } -#endif // OBJECTSHADER_USE_UVSETS - - surface2.emissiveColor = GetMaterial1().GetEmissive(); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial1().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) - { - float2 uv = GetMaterial1().uvset_emissiveMap == 0 ? uvsets.xy : uvsets.zw; - sam = texture_blend1_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam.rgb * sam.a; - } -#endif // OBJECTSHADER_USE_UVSETS - - surface.N += surface2.N * blend_weights.y; - surface.albedo += surface2.albedo * blend_weights.y; - surface.f0 += surface2.f0 * blend_weights.y; - surface.roughness += surface2.roughness * blend_weights.y; - surface.occlusion += surface2.occlusion * blend_weights.y; - surface.emissiveColor += surface2.emissiveColor * blend_weights.y; - } - - [branch] - if (blend_weights.z > 0) - { - float4 color2 = GetMaterial2().baseColor; - float4 uvsets = input.uvsets; - uvsets.xy = mad(uvsets.xy, GetMaterial2().texMulAdd.xy, GetMaterial2().texMulAdd.zw); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial2().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial2().uvset_baseColorMap == 0 ? uvsets.xy : uvsets.zw; - float4 basecolorMap = texture_blend2_basecolormap.Sample(sampler_objectshader, uv); - basecolorMap.rgb = DEGAMMA(basecolorMap.rgb); - color2 *= basecolorMap; - } -#endif // OBJECTSHADER_USE_UVSETS - - float4 surfaceMap2 = 1; - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial2().uvset_surfaceMap >= 0) - { - float2 uv = GetMaterial2().uvset_surfaceMap == 0 ? uvsets.xy : uvsets.zw; - surfaceMap2 = texture_blend2_surfacemap.Sample(sampler_objectshader, uv); - } -#endif // OBJECTSHADER_USE_UVSETS - - Surface surface2; - surface2.N = baseN; - surface2.create(GetMaterial2(), color2, surfaceMap2); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial2().normalMapStrength > 0 && GetMaterial2().uvset_normalMap >= 0) - { - float2 uv = GetMaterial2().uvset_normalMap == 0 ? uvsets.xy : uvsets.zw; - sam.rgb = texture_blend2_normalmap.Sample(sampler_objectshader, uv).rgb; - sam.rgb = sam.rgb * 2 - 1; - surface2.N = lerp(baseN, mul(sam.rgb, TBN), GetMaterial2().normalMapStrength); - } -#endif // OBJECTSHADER_USE_UVSETS - - surface2.emissiveColor = GetMaterial2().GetEmissive(); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial2().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) - { - float2 uv = GetMaterial2().uvset_emissiveMap == 0 ? uvsets.xy : uvsets.zw; - sam = texture_blend2_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam.rgb * sam.a; - } -#endif // OBJECTSHADER_USE_UVSETS - - surface.N += surface2.N * blend_weights.z; - surface.albedo += surface2.albedo * blend_weights.z; - surface.f0 += surface2.f0 * blend_weights.z; - surface.roughness += surface2.roughness * blend_weights.z; - surface.occlusion += surface2.occlusion * blend_weights.z; - surface.emissiveColor += surface2.emissiveColor * blend_weights.z; - } - - [branch] - if (blend_weights.w > 0) - { - float4 color2 = GetMaterial3().baseColor; - float4 uvsets = input.uvsets; - uvsets.xy = mad(uvsets.xy, GetMaterial3().texMulAdd.xy, GetMaterial3().texMulAdd.zw); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial3().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial3().uvset_baseColorMap == 0 ? uvsets.xy : uvsets.zw; - float4 basecolorMap = texture_blend3_basecolormap.Sample(sampler_objectshader, uv); - basecolorMap.rgb = DEGAMMA(basecolorMap.rgb); - color2 *= basecolorMap; - } -#endif // OBJECTSHADER_USE_UVSETS - - float4 surfaceMap2 = 1; - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial3().uvset_surfaceMap >= 0) - { - float2 uv = GetMaterial3().uvset_surfaceMap == 0 ? uvsets.xy : uvsets.zw; - surfaceMap2 = texture_blend3_surfacemap.Sample(sampler_objectshader, uv); - } -#endif // OBJECTSHADER_USE_UVSETS - - Surface surface2; - surface2.N = baseN; - surface2.create(GetMaterial3(), color2, surfaceMap2); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial3().normalMapStrength > 0 && GetMaterial3().uvset_normalMap >= 0) - { - float2 uv = GetMaterial3().uvset_normalMap == 0 ? uvsets.xy : uvsets.zw; - sam.rgb = texture_blend3_normalmap.Sample(sampler_objectshader, uv).rgb; - sam.rgb = sam.rgb * 2 - 1; - surface2.N = lerp(baseN, mul(sam.rgb, TBN), GetMaterial3().normalMapStrength); - } -#endif // OBJECTSHADER_USE_UVSETS - - surface2.emissiveColor = GetMaterial3().GetEmissive(); - -#ifdef OBJECTSHADER_USE_UVSETS - [branch] - if (GetMaterial3().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) - { - float2 uv = GetMaterial3().uvset_emissiveMap == 0 ? uvsets.xy : uvsets.zw; - sam = texture_blend3_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam.rgb * sam.a; - } -#endif // OBJECTSHADER_USE_UVSETS - - surface.N += surface2.N * blend_weights.w; - surface.albedo += surface2.albedo * blend_weights.w; - surface.f0 += surface2.f0 * blend_weights.w; - surface.roughness += surface2.roughness * blend_weights.w; - surface.occlusion += surface2.occlusion * blend_weights.w; - surface.emissiveColor += surface2.emissiveColor * blend_weights.w; - } - - surface.N = normalize(surface.N); - -#endif // TERRAIN - - - #ifdef OBJECTSHADER_USE_EMISSIVE surface.emissiveColor *= Unpack_R11G11B10_FLOAT(input.emissiveColor); #endif // OBJECTSHADER_USE_EMISSIVE diff --git a/WickedEngine/shaders/objectPS_terrain.hlsl b/WickedEngine/shaders/objectPS_terrain.hlsl deleted file mode 100644 index e0bc645ad..000000000 --- a/WickedEngine/shaders/objectPS_terrain.hlsl +++ /dev/null @@ -1,8 +0,0 @@ -#define OBJECTSHADER_COMPILE_PS -#define OBJECTSHADER_LAYOUT_COMMON -#define SHADOW_MASK_ENABLED -#define OUTPUT_GBUFFER -#define TILEDFORWARD -#define DISABLE_ALPHATEST -#define TERRAIN -#include "objectHF.hlsli" diff --git a/WickedEngine/shaders/objectPS_voxelizer.hlsl b/WickedEngine/shaders/objectPS_voxelizer.hlsl index 97b8be80a..4852b2f84 100644 --- a/WickedEngine/shaders/objectPS_voxelizer.hlsl +++ b/WickedEngine/shaders/objectPS_voxelizer.hlsl @@ -51,122 +51,6 @@ void main(PSInput input) emissiveColor *= emissiveMap.rgb * emissiveMap.a; } - -#ifdef TERRAIN - color = 0; - emissiveColor = 0; - float4 blend_weights = input.color; - blend_weights /= blend_weights.x + blend_weights.y + blend_weights.z + blend_weights.w; - float4 sam; - - [branch] - if (blend_weights.x > 0) - { - [branch] - if (GetMaterial().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial().uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_basecolormap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - } - else - { - sam = 1; - } - color += sam * GetMaterial().baseColor * blend_weights.x; - - [branch] - if (GetMaterial().uvset_emissiveMap >= 0 && any(GetMaterial().GetEmissive())) - { - float2 uv = GetMaterial().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam.rgb * sam.a * GetMaterial().GetEmissive() * blend_weights.x; - } - } - - [branch] - if (blend_weights.y > 0) - { - [branch] - if (GetMaterial1().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial1().uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_blend1_basecolormap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - } - else - { - sam = 1; - } - color += sam * GetMaterial1().baseColor * blend_weights.y; - - [branch] - if (GetMaterial1().uvset_emissiveMap >= 0 && any(GetMaterial1().GetEmissive())) - { - float2 uv = GetMaterial1().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_blend1_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam.rgb * sam.a * GetMaterial1().GetEmissive() * blend_weights.y; - } - } - - [branch] - if (blend_weights.z > 0) - { - [branch] - if (GetMaterial2().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial2().uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_blend2_basecolormap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - } - else - { - sam = 1; - } - color += sam * GetMaterial2().baseColor * blend_weights.z; - - [branch] - if (GetMaterial2().uvset_emissiveMap >= 0 && any(GetMaterial2().GetEmissive())) - { - float2 uv = GetMaterial2().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_blend2_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam.rgb * sam.a * GetMaterial2().GetEmissive() * blend_weights.z; - } - } - - [branch] - if (blend_weights.w > 0) - { - [branch] - if (GetMaterial3().uvset_baseColorMap >= 0 && (GetFrame().options & OPTION_BIT_DISABLE_ALBEDO_MAPS) == 0) - { - float2 uv = GetMaterial3().uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_blend3_basecolormap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - } - else - { - sam = 1; - } - color += sam * GetMaterial3().baseColor * blend_weights.w; - - [branch] - if (GetMaterial3().uvset_emissiveMap >= 0 && any(GetMaterial3().GetEmissive())) - { - float2 uv = GetMaterial3().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; - sam = texture_blend3_emissivemap.Sample(sampler_objectshader, uv); - sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam.rgb * sam.a * GetMaterial3().GetEmissive() * blend_weights.w; - } - } - - color.a = 1; - -#endif // TERRAIN - Lighting lighting; lighting.create(0, 0, 0, 0); diff --git a/WickedEngine/shaders/objectPS_voxelizer_terrain.hlsl b/WickedEngine/shaders/objectPS_voxelizer_terrain.hlsl deleted file mode 100644 index 88517a702..000000000 --- a/WickedEngine/shaders/objectPS_voxelizer_terrain.hlsl +++ /dev/null @@ -1,2 +0,0 @@ -#define TERRAIN -#include "objectPS_voxelizer.hlsl" diff --git a/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl b/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl new file mode 100644 index 000000000..167a2e95f --- /dev/null +++ b/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl @@ -0,0 +1,87 @@ +#include "globals.hlsli" + +static const uint region_count = 4; +Texture2D region_weights_texture : register(t0); + +struct Terrain +{ + ShaderMaterial materials[region_count]; +}; +ConstantBuffer terrain : register(b10); + +// These are expected to be in the same bind slots as corresponding MaterialComponent::TEXTURESLOT enums +RWTexture2D output_baseColorMap : register(u0); +RWTexture2D output_normalMap : register(u1); +RWTexture2D output_surfaceMap : register(u2); + +[numthreads(8, 8, 1)] +void main(uint3 DTid : SV_DispatchThreadID) +{ + float2 output_dim = 0; + output_baseColorMap.GetDimensions(output_dim.x, output_dim.y); + const float2 uv = (DTid.xy + 0.5f) / output_dim; + + float4 region_weights = region_weights_texture.SampleLevel(sampler_linear_clamp, uv, 0); + + float weight_sum = 0; + float4 total_baseColor = 0; + float4 total_surface = 0; + float2 total_normal = 0; + for (uint i = 0; i < region_count; ++i) + { + float weight = region_weights[i]; + + ShaderMaterial material = terrain.materials[i]; + + float4 baseColor = material.baseColor; + [branch] + if (material.texture_basecolormap_index >= 0) + { + Texture2D tex = bindless_textures[material.texture_basecolormap_index]; + float2 dim = 0; + tex.GetDimensions(dim.x, dim.y); + float2 diff = dim / output_dim; + float lod = log2(max(diff.x, diff.y)); + float4 baseColorMap = tex.SampleLevel(sampler_linear_clamp, uv, lod); + baseColor *= baseColorMap; + } + total_baseColor += baseColor * weight; + + float4 surface = float4(1, material.roughness, material.metalness, material.reflectance); + [branch] + if (material.texture_surfacemap_index >= 0) + { + Texture2D tex = bindless_textures[material.texture_surfacemap_index]; + float2 dim = 0; + tex.GetDimensions(dim.x, dim.y); + float2 diff = dim / output_dim; + float lod = log2(max(diff.x, diff.y)); + float4 surfaceMap = tex.SampleLevel(sampler_linear_clamp, uv, lod); + surface *= surfaceMap; + } + total_surface += surface * weight; + + float2 normal = float2(0.5, 0.5); + [branch] + if (material.texture_normalmap_index >= 0) + { + Texture2D tex = bindless_textures[material.texture_normalmap_index]; + float2 dim = 0; + tex.GetDimensions(dim.x, dim.y); + float2 diff = dim / output_dim; + float lod = log2(max(diff.x, diff.y)); + float2 normalMap = tex.SampleLevel(sampler_linear_clamp, uv, lod).rg; + normal = normalMap; + } + total_normal += normal * weight; + + weight_sum += weight; + } + total_baseColor /= weight_sum; + total_surface /= weight_sum; + total_normal /= weight_sum; + + output_baseColorMap[DTid.xy] = total_baseColor; + output_surfaceMap[DTid.xy] = total_surface; + output_normalMap[DTid.xy] = float4(total_normal, 1, 1); +} diff --git a/WickedEngine/wiArchive.cpp b/WickedEngine/wiArchive.cpp index a73a434f0..1e0f4c4c6 100644 --- a/WickedEngine/wiArchive.cpp +++ b/WickedEngine/wiArchive.cpp @@ -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 = 78; + static constexpr uint64_t __archiveVersion = 79; // this is the version number of which below the archive is not compatible with the current version static constexpr uint64_t __archiveVersionBarrier = 22; diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h index a2c19a6c6..354dbd3e2 100644 --- a/WickedEngine/wiEnums.h +++ b/WickedEngine/wiEnums.h @@ -145,7 +145,6 @@ namespace wi::enums PSTYPE_OBJECT_UNLIT, PSTYPE_OBJECT_TRANSPARENT_UNLIT, PSTYPE_OBJECT_WATER, - PSTYPE_OBJECT_TERRAIN, PSTYPE_IMPOSTOR, PSTYPE_OBJECT_HOLOGRAM, @@ -172,7 +171,6 @@ namespace wi::enums PSTYPE_SKY_DYNAMIC, PSTYPE_SUN, PSTYPE_ENVMAP, - PSTYPE_ENVMAP_TERRAIN, PSTYPE_ENVMAP_SKY_STATIC, PSTYPE_ENVMAP_SKY_DYNAMIC, PSTYPE_CUBEMAP, @@ -180,7 +178,6 @@ namespace wi::enums PSTYPE_CAPTUREIMPOSTOR_NORMAL, PSTYPE_CAPTUREIMPOSTOR_SURFACE, PSTYPE_VOXELIZER, - PSTYPE_VOXELIZER_TERRAIN, PSTYPE_VOXEL, PSTYPE_FORCEFIELDVISUALIZER, PSTYPE_RENDERLIGHTMAP, @@ -359,6 +356,7 @@ namespace wi::enums CSTYPE_DDGI_RAYTRACE, CSTYPE_DDGI_UPDATE, CSTYPE_DDGI_UPDATE_DEPTH, + CSTYPE_TERRAIN_VIRTUALTEXTURE_UPDATE, // raytracing pipelines: diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 2d191f635..db8c94315 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -285,7 +285,6 @@ PipelineState PSO_object [OBJECTRENDERING_DOUBLESIDED_COUNT] [OBJECTRENDERING_TESSELLATION_COUNT] [OBJECTRENDERING_ALPHATEST_COUNT]; -PipelineState PSO_object_terrain[RENDERPASS_COUNT]; PipelineState PSO_object_wire; PipelineState PSO_object_wire_tessellation; @@ -806,7 +805,6 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_OBJECT_UNLIT], "objectPS_unlit.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_OBJECT_TRANSPARENT_UNLIT], "objectPS_transparent_unlit.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_OBJECT_WATER], "objectPS_water.cso"); }); - wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_OBJECT_TERRAIN], "objectPS_terrain.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_IMPOSTOR], "impostorPS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_OBJECT_HOLOGRAM], "objectPS_hologram.cso"); }); @@ -824,7 +822,6 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_VOLUMETRICLIGHT_POINT], "volumetricLight_PointPS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_VOLUMETRICLIGHT_SPOT], "volumetricLight_SpotPS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_ENVMAP], "envMapPS.cso"); }); - wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_ENVMAP_TERRAIN], "envMapPS_terrain.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_ENVMAP_SKY_STATIC], "envMap_skyPS_static.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_ENVMAP_SKY_DYNAMIC], "envMap_skyPS_dynamic.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_CAPTUREIMPOSTOR_ALBEDO], "captureImpostorPS_albedo.cso"); }); @@ -839,7 +836,6 @@ void LoadShaders() wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_SHADOW_TRANSPARENT], "shadowPS_transparent.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_SHADOW_WATER], "shadowPS_water.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_VOXELIZER], "objectPS_voxelizer.cso"); }); - wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_VOXELIZER_TERRAIN], "objectPS_voxelizer_terrain.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_VOXEL], "voxelPS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::PS, shaders[PSTYPE_FORCEFIELDVISUALIZER], "forceFieldVisualizerPS.cso"); }); if (device->CheckCapability(GraphicsDeviceCapability::RAYTRACING)) @@ -1034,6 +1030,7 @@ void LoadShaders() } wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_DDGI_UPDATE], "ddgi_updateCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_DDGI_UPDATE_DEPTH], "ddgi_updateCS_depth.cso"); }); + wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::CS, shaders[CSTYPE_TERRAIN_VIRTUALTEXTURE_UPDATE], "terrainVirtualTextureUpdateCS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT], "objectHS.cso"); }); wi::jobsystem::Execute(ctx, [](wi::jobsystem::JobArgs args) { LoadShader(ShaderStage::HS, shaders[HSTYPE_OBJECT_PREPASS], "objectHS_prepass.cso"); }); @@ -1189,48 +1186,6 @@ void LoadShaders() } }); - wi::jobsystem::Dispatch(ctx, RENDERPASS_COUNT, 1, [](wi::jobsystem::JobArgs args) { - - SHADERTYPE realVS = GetVSTYPE((RENDERPASS) args.jobIndex, false, false, false); - - PipelineStateDesc desc; - desc.rs = &rasterizers[RSTYPE_FRONT]; - desc.bs = &blendStates[BSTYPE_OPAQUE]; - desc.dss = &depthStencils[DSSTYPE_DEFAULT]; - desc.vs = &shaders[realVS]; - - switch (args.jobIndex) - { - case RENDERPASS_MAIN: - desc.dss = &depthStencils[DSSTYPE_DEPTHREADEQUAL]; - desc.ps = &shaders[PSTYPE_OBJECT_TERRAIN]; - break; - case RENDERPASS_PREPASS: - desc.ps = &shaders[PSTYPE_OBJECT_PREPASS]; - break; - case RENDERPASS_VOXELIZE: - desc.dss = &depthStencils[DSSTYPE_DEPTHDISABLED]; - desc.rs = &rasterizers[RSTYPE_VOXELIZE]; - desc.vs = &shaders[VSTYPE_VOXELIZER]; - desc.gs = &shaders[GSTYPE_VOXELIZER]; - desc.ps = &shaders[PSTYPE_VOXELIZER_TERRAIN]; - break; - case RENDERPASS_ENVMAPCAPTURE: - desc.ps = &shaders[PSTYPE_ENVMAP_TERRAIN]; - break; - case RENDERPASS_SHADOW: - case RENDERPASS_SHADOWCUBE: - desc.dss = &depthStencils[DSSTYPE_SHADOW]; - desc.rs = &rasterizers[RSTYPE_SHADOW_DOUBLESIDED]; - desc.ps = nullptr; - break; - default: - return; - } - - device->CreatePipelineState(&desc, &PSO_object_terrain[args.jobIndex]); - }); - // Clear custom shaders (Custom shaders coming from user will need to be handled by the user in case of shader reload): customShaders.clear(); @@ -2417,7 +2372,6 @@ void RenderMeshes( const float tessF = mesh.GetTessellationFactor(); const bool tessellatorRequested = tessF > 0 && tessellation; - const bool terrain = mesh.IsTerrain(); if (forwardLightmaskRequest) { @@ -2462,10 +2416,6 @@ void RenderMeshes( pso = tessellatorRequested ? &PSO_object_wire_tessellation : &PSO_object_wire; } } - else if (mesh.IsTerrain()) - { - pso = &PSO_object_terrain[renderPass]; - } else if (material.customShaderID >= 0 && material.customShaderID < (int)customShaders.size()) { const CustomShader& customShader = customShaders[material.customShaderID]; diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index ae511d8ad..4802aadfb 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -2997,10 +2997,6 @@ namespace wi::scene mesh._flags &= ~MeshComponent::TLAS_FORCE_DOUBLE_SIDED; - mesh.terrain_material1_index = (uint32_t)materials.GetIndex(mesh.terrain_material1); - mesh.terrain_material2_index = (uint32_t)materials.GetIndex(mesh.terrain_material2); - mesh.terrain_material3_index = (uint32_t)materials.GetIndex(mesh.terrain_material3); - // Update morph targets if needed: if (mesh.dirty_morph && !mesh.targets.empty()) { @@ -3060,9 +3056,6 @@ namespace wi::scene geometry.vb_uvs = mesh.vb_uvs.descriptor_srv; geometry.vb_atl = mesh.vb_atl.descriptor_srv; geometry.vb_pre = mesh.so_pre.descriptor_srv; - geometry.blendmaterial1 = mesh.terrain_material1_index; - geometry.blendmaterial2 = mesh.terrain_material2_index; - geometry.blendmaterial3 = mesh.terrain_material3_index; geometry.aabb_min = mesh.aabb._min; geometry.aabb_max = mesh.aabb._max; geometry.tessellation_factor = mesh.tessellationFactor; diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 38acc5673..cbe621ddd 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -314,7 +314,7 @@ namespace wi::scene RENDERABLE = 1 << 0, DOUBLE_SIDED = 1 << 1, DYNAMIC = 1 << 2, - TERRAIN = 1 << 3, + _DEPRECATED_TERRAIN = 1 << 3, _DEPRECATED_DIRTY_MORPH = 1 << 4, _DEPRECATED_DIRTY_BINDLESS = 1 << 5, TLAS_FORCE_DOUBLE_SIDED = 1 << 6, @@ -347,15 +347,6 @@ namespace wi::scene float tessellationFactor = 0.0f; wi::ecs::Entity armatureID = wi::ecs::INVALID_ENTITY; - // Terrain blend materials: - // There are 4 blend materials, the first one (default) being the subset material - // Must have TERRAIN flag enabled - // Must have vertex colors to blend between materials - // extra materials that are not set will use the base subset material - wi::ecs::Entity terrain_material1 = wi::ecs::INVALID_ENTITY; - wi::ecs::Entity terrain_material2 = wi::ecs::INVALID_ENTITY; - wi::ecs::Entity terrain_material3 = wi::ecs::INVALID_ENTITY; - // Morph Targets struct MeshMorphTarget { @@ -407,22 +398,15 @@ namespace wi::scene }; mutable BLAS_STATE BLAS_state = BLAS_STATE_NEEDS_REBUILD; - // Only valid for 1 frame material component indices: - uint32_t terrain_material1_index = ~0u; - uint32_t terrain_material2_index = ~0u; - uint32_t terrain_material3_index = ~0u; - mutable bool dirty_morph = false; inline void SetRenderable(bool value) { if (value) { _flags |= RENDERABLE; } else { _flags &= ~RENDERABLE; } } inline void SetDoubleSided(bool value) { if (value) { _flags |= DOUBLE_SIDED; } else { _flags &= ~DOUBLE_SIDED; } } inline void SetDynamic(bool value) { if (value) { _flags |= DYNAMIC; } else { _flags &= ~DYNAMIC; } } - inline void SetTerrain(bool value) { if (value) { _flags |= TERRAIN; } else { _flags &= ~TERRAIN; } } inline bool IsRenderable() const { return _flags & RENDERABLE; } inline bool IsDoubleSided() const { return _flags & DOUBLE_SIDED; } inline bool IsDynamic() const { return _flags & DYNAMIC; } - inline bool IsTerrain() const { return _flags & TERRAIN; } inline float GetTessellationFactor() const { return tessellationFactor; } inline wi::graphics::IndexBufferFormat GetIndexFormat() const { return vertex_positions.size() > 65536 ? wi::graphics::IndexBufferFormat::UINT32 : wi::graphics::IndexBufferFormat::UINT16; } diff --git a/WickedEngine/wiScene_Serializers.cpp b/WickedEngine/wiScene_Serializers.cpp index f0e35612d..e8444e296 100644 --- a/WickedEngine/wiScene_Serializers.cpp +++ b/WickedEngine/wiScene_Serializers.cpp @@ -373,8 +373,12 @@ namespace wi::scene archive >> vertex_uvset_1; } - if (archive.GetVersion() >= 41) + if (archive.GetVersion() >= 41 && archive.GetVersion() < 79) { + // These are no longer used: + Entity terrain_material1; + Entity terrain_material2; + Entity terrain_material3; SerializeEntity(archive, terrain_material1, seri); SerializeEntity(archive, terrain_material2, seri); SerializeEntity(archive, terrain_material3, seri); @@ -440,8 +444,12 @@ namespace wi::scene archive << vertex_uvset_1; } - if (archive.GetVersion() >= 41) + if (archive.GetVersion() >= 41 && archive.GetVersion() < 79) { + // These are no longer used: + Entity terrain_material1; + Entity terrain_material2; + Entity terrain_material3; SerializeEntity(archive, terrain_material1, seri); SerializeEntity(archive, terrain_material2, seri); SerializeEntity(archive, terrain_material3, seri); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 7f5ea8a6a..33a41ca24 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 60; // minor bug fixes, alterations, refactors, updates - const int revision = 61; + const int revision = 62; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);