diff --git a/Editor/TerrainWindow.cpp b/Editor/TerrainWindow.cpp index 3783a8d42..e60104da8 100644 --- a/Editor/TerrainWindow.cpp +++ b/Editor/TerrainWindow.cpp @@ -274,7 +274,7 @@ void TerrainWindow::Create(EditorComponent* _editor) ClearTransform(); wi::gui::Window::Create(ICON_TERRAIN " Terrain", wi::gui::Window::WindowControls::COLLAPSE | wi::gui::Window::WindowControls::CLOSE); - SetSize(XMFLOAT2(420, 860)); + SetSize(XMFLOAT2(420, 900)); closeButton.SetTooltip("Delete Terrain.\nThis will bake generated virtual textures to static textures which could take a while!"); OnClose([=](wi::gui::EventArgs args) { @@ -303,11 +303,13 @@ void TerrainWindow::Create(EditorComponent* _editor) terrain->SetGrassEnabled(grassCheckBox.GetCheck()); terrain->lod_multiplier = lodSlider.GetValue(); terrain->texlod = texlodSlider.GetValue(); + terrain->target_texture_resolution = (uint32_t)texResolutionSlider.GetValue(); terrain->generation = (int)generationSlider.GetValue(); terrain->prop_generation = (int)propGenerationSlider.GetValue(); terrain->physics_generation = (int)physicsGenerationSlider.GetValue(); terrain->prop_density = propDensitySlider.GetValue(); terrain->grass_density = grassDensitySlider.GetValue(); + terrain->grass_length = grassLengthSlider.GetValue(); terrain->chunk_scale = scaleSlider.GetValue(); terrain->seed = (uint32_t)seedSlider.GetValue(); terrain->bottomLevel = bottomLevelSlider.GetValue(); @@ -390,6 +392,15 @@ void TerrainWindow::Create(EditorComponent* _editor) }); AddWidget(&texlodSlider); + texResolutionSlider.Create(256, 4096, 1024, 4096 - 256, "Tex Resolution: "); + texResolutionSlider.SetTooltip("Virtual texture target resolution for most detailed chunk.\nNote: if chunk resolution is bigger than texture resolution, texture scaling will be applied to those chunks."); + texResolutionSlider.SetSize(XMFLOAT2(wid, hei)); + texResolutionSlider.SetPos(XMFLOAT2(x, y += step)); + texResolutionSlider.OnSlide([this](wi::gui::EventArgs args) { + terrain->target_texture_resolution = (uint32_t)args.iValue; + }); + AddWidget(&texResolutionSlider); + 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(wid, hei)); @@ -426,7 +437,7 @@ void TerrainWindow::Create(EditorComponent* _editor) }); AddWidget(&propDensitySlider); - grassDensitySlider.Create(0, 4, 1, 1000, "Grass Density: "); + grassDensitySlider.Create(0, 4, 2, 1000, "Grass Density: "); grassDensitySlider.SetTooltip("Modifies overall grass density."); grassDensitySlider.SetSize(XMFLOAT2(wid, hei)); grassDensitySlider.SetPos(XMFLOAT2(x, y += step)); @@ -435,6 +446,15 @@ void TerrainWindow::Create(EditorComponent* _editor) }); AddWidget(&grassDensitySlider); + grassLengthSlider.Create(0, 8, 2, 1000, "Grass Length: "); + grassLengthSlider.SetTooltip("Modifies overall grass length."); + grassLengthSlider.SetSize(XMFLOAT2(wid, hei)); + grassLengthSlider.SetPos(XMFLOAT2(x, y += step)); + grassLengthSlider.OnSlide([this](wi::gui::EventArgs args) { + terrain->grass_properties.length = args.fValue; + }); + AddWidget(&grassLengthSlider); + presetCombo.Create("Preset: "); presetCombo.SetTooltip("Select a terrain preset"); presetCombo.SetSize(XMFLOAT2(wid, hei)); @@ -769,10 +789,13 @@ void TerrainWindow::SetEntity(Entity entity) physicsCheckBox.SetCheck(terrain->IsPhysicsEnabled()); lodSlider.SetValue(terrain->lod_multiplier); texlodSlider.SetValue(terrain->texlod); + texResolutionSlider.SetValue((float)terrain->target_texture_resolution); generationSlider.SetValue((float)terrain->generation); propGenerationSlider.SetValue((float)terrain->prop_generation); physicsGenerationSlider.SetValue((float)terrain->physics_generation); propDensitySlider.SetValue(terrain->prop_density); + grassDensitySlider.SetValue(terrain->grass_density); + grassLengthSlider.SetValue(terrain->grass_properties.length); scaleSlider.SetValue(terrain->chunk_scale); seedSlider.SetValue((float)terrain->seed); bottomLevelSlider.SetValue(terrain->bottomLevel); @@ -847,7 +870,7 @@ void TerrainWindow::SetupAssets() terrain_preset.material_HighAltitude.textures[MaterialComponent::NORMALMAP].name = "terrain/high_altitude_nor.jpg"; terrain_preset.material_GrassParticle.textures[MaterialComponent::BASECOLORMAP].name = "terrain/grassparticle.png"; terrain_preset.material_GrassParticle.alphaRef = 0.75f; - terrain_preset.grass_properties.length = 5; + terrain_preset.grass_properties.length = 2; terrain_preset.grass_properties.frameCount = 2; terrain_preset.grass_properties.framesX = 1; terrain_preset.grass_properties.framesY = 2; @@ -866,16 +889,16 @@ void TerrainWindow::SetupAssets() { wi::terrain::Prop& prop = terrain_preset.props.emplace_back(); prop.min_count_per_chunk = 0; - prop.max_count_per_chunk = 10; + prop.max_count_per_chunk = 20; prop.region = 0; prop.region_power = 2; prop.noise_frequency = 0.1f; prop.noise_power = 1; prop.threshold = 0.4f; - prop.min_size = 2.0f; - prop.max_size = 8.0f; - prop.min_y_offset = -0.5f; - prop.max_y_offset = -0.5f; + prop.min_size = 1.0f; + prop.max_size = 4.0f; + prop.min_y_offset = -0.25f; + prop.max_y_offset = -0.25f; Entity mesh_entity = props_scene.Entity_FindByName("tree_mesh"); props_scene.impostors.Create(mesh_entity).swapInDistance = 200; Entity object_entity = props_scene.Entity_FindByName("tree_object"); @@ -908,9 +931,9 @@ void TerrainWindow::SetupAssets() prop.noise_power = 2; prop.threshold = 0.5f; prop.min_size = 0.02f; - prop.max_size = 4.0f; - prop.min_y_offset = -2; - prop.max_y_offset = 0.5f; + prop.max_size = 2.0f; + prop.min_y_offset = -1; + prop.max_y_offset = 0.25f; Entity mesh_entity = props_scene.Entity_FindByName("rock_mesh"); Entity object_entity = props_scene.Entity_FindByName("rock_object"); ObjectComponent* object = props_scene.objects.GetComponent(object_entity); @@ -942,9 +965,9 @@ void TerrainWindow::SetupAssets() prop.noise_frequency = 0.01f; prop.noise_power = 4; prop.threshold = 0.1f; - prop.min_size = 0.1f; - prop.max_size = 1.5f; - prop.min_y_offset = -1; + prop.min_size = 0.05f; + prop.max_size = 0.5f; + prop.min_y_offset = -0.25; prop.max_y_offset = 0; Entity mesh_entity = props_scene.Entity_FindByName("bush_mesh"); Entity object_entity = props_scene.Entity_FindByName("bush_object"); @@ -1032,11 +1055,13 @@ void TerrainWindow::ResizeLayout() physicsCheckBox.SetPos(XMFLOAT2(grassCheckBox.GetPos().x - 100, grassCheckBox.GetPos().y)); add(lodSlider); add(texlodSlider); + add(texResolutionSlider); add(generationSlider); add(propGenerationSlider); add(physicsGenerationSlider); add(propDensitySlider); add(grassDensitySlider); + add(grassLengthSlider); add(presetCombo); add(scaleSlider); add(seedSlider); diff --git a/Editor/TerrainWindow.h b/Editor/TerrainWindow.h index c885e9dcf..4a4551438 100644 --- a/Editor/TerrainWindow.h +++ b/Editor/TerrainWindow.h @@ -58,11 +58,13 @@ public: wi::gui::CheckBox physicsCheckBox; wi::gui::Slider lodSlider; wi::gui::Slider texlodSlider; + wi::gui::Slider texResolutionSlider; wi::gui::Slider generationSlider; wi::gui::Slider propGenerationSlider; wi::gui::Slider physicsGenerationSlider; wi::gui::Slider propDensitySlider; wi::gui::Slider grassDensitySlider; + wi::gui::Slider grassLengthSlider; wi::gui::ComboBox presetCombo; wi::gui::Slider scaleSlider; wi::gui::Slider seedSlider; diff --git a/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl b/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl index 167a2e95f..03921cc12 100644 --- a/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl +++ b/WickedEngine/shaders/terrainVirtualTextureUpdateCS.hlsl @@ -42,7 +42,8 @@ void main(uint3 DTid : SV_DispatchThreadID) 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); + float2 overscale = lod < 0 ? diff : 1; + float4 baseColorMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod); baseColor *= baseColorMap; } total_baseColor += baseColor * weight; @@ -56,7 +57,8 @@ void main(uint3 DTid : SV_DispatchThreadID) 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); + float2 overscale = lod < 0 ? diff : 1; + float4 surfaceMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod); surface *= surfaceMap; } total_surface += surface * weight; @@ -70,7 +72,8 @@ void main(uint3 DTid : SV_DispatchThreadID) 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; + float2 overscale = lod < 0 ? diff : 1; + float2 normalMap = tex.SampleLevel(sampler_linear_wrap, uv / overscale, lod).rg; normal = normalMap; } total_normal += normal * weight; diff --git a/WickedEngine/wiScene.h b/WickedEngine/wiScene.h index 02586450e..3f217c9d3 100644 --- a/WickedEngine/wiScene.h +++ b/WickedEngine/wiScene.h @@ -51,7 +51,7 @@ namespace wi::scene wi::ecs::ComponentManager& scripts = componentLibrary.Register("wi::scene::Scene::scripts"); wi::ecs::ComponentManager& expressions = componentLibrary.Register("wi::scene::Scene::expressions"); wi::ecs::ComponentManager& humanoids = componentLibrary.Register("wi::scene::Scene::humanoids"); - wi::ecs::ComponentManager& terrains = componentLibrary.Register("wi::scene::Scene::terrains", 1); // version = 1 + wi::ecs::ComponentManager& terrains = componentLibrary.Register("wi::scene::Scene::terrains", 2); // version = 2 // Non-serialized attributes: float dt = 0; diff --git a/WickedEngine/wiTerrain.cpp b/WickedEngine/wiTerrain.cpp index 8f692bb7a..5010168d5 100644 --- a/WickedEngine/wiTerrain.cpp +++ b/WickedEngine/wiTerrain.cpp @@ -308,7 +308,7 @@ namespace wi::terrain 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_any = false; 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] = { @@ -329,9 +329,7 @@ namespace wi::terrain 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); + virtual_texture_any = true; } break; default: @@ -384,14 +382,15 @@ namespace wi::terrain } } - // Grass density modification: - if (chunk_data.grass_entity != INVALID_ENTITY && std::abs(chunk_data.grass_density_current - grass_density) > std::numeric_limits::epsilon()) + // Grass property update: + if (chunk_data.grass_entity != INVALID_ENTITY) { wi::HairParticleSystem* grass = scene->hairs.GetComponent(chunk_data.grass_entity); if (grass != nullptr) { chunk_data.grass_density_current = grass_density; grass->strandCount = uint32_t(chunk_data.grass.strandCount * chunk_data.grass_density_current); + grass->length = grass_properties.length; } } @@ -442,7 +441,7 @@ namespace wi::terrain } // Collect virtual texture update requests: - if (max_texture_resolution > 0) + if (virtual_texture_any) { uint32_t texture_lod = 0; const float distsq = wi::math::DistanceSquared(camera.Eye, chunk_data.sphere.center); @@ -459,7 +458,8 @@ namespace wi::terrain texture_lod = uint32_t(dist_to_sphere * texlodMultiplier); } - chunk_data.required_texture_resolution = uint32_t(max_texture_resolution / std::pow(2.0f, (float)std::max(0u, texture_lod))); + chunk_data.required_texture_resolution = uint32_t(target_texture_resolution / std::pow(2.0f, (float)std::max(0u, texture_lod))); + chunk_data.required_texture_resolution = AlignTo(chunk_data.required_texture_resolution, 8u); chunk_data.required_texture_resolution = std::max(8u, chunk_data.required_texture_resolution); MaterialComponent* material = scene->materials.GetComponent(chunk_data.entity); @@ -935,7 +935,7 @@ namespace wi::terrain case MaterialComponent::BASECOLORMAP: case MaterialComponent::SURFACEMAP: case MaterialComponent::NORMALMAP: - if (!tex.name.empty() && tex.GetGPUResource() != nullptr) + if (tex.GetGPUResource() != nullptr) { wi::vector filedata; if (wi::helper::saveTextureToMemory(tex.resource.GetTexture(), filedata)) @@ -1032,6 +1032,10 @@ namespace wi::terrain { archive >> physics_generation; } + if (seri.GetVersion() >= 2) + { + archive >> target_texture_resolution; + } size_t count = 0; archive >> count; @@ -1180,6 +1184,10 @@ namespace wi::terrain { archive << physics_generation; } + if (seri.GetVersion() >= 2) + { + archive << target_texture_resolution; + } archive << props.size(); for (size_t i = 0; i < props.size(); ++i) diff --git a/WickedEngine/wiTerrain.h b/WickedEngine/wiTerrain.h index 9bf96a626..b938321d8 100644 --- a/WickedEngine/wiTerrain.h +++ b/WickedEngine/wiTerrain.h @@ -140,6 +140,7 @@ namespace wi::terrain int physics_generation = 3; float prop_density = 1; float grass_density = 1; + float grass_length = 1; float chunk_scale = 1; uint32_t seed = 3926; float bottomLevel = -60; @@ -147,6 +148,7 @@ namespace wi::terrain float region1 = 1; float region2 = 2; float region3 = 8; + uint32_t target_texture_resolution = 1024; wi::vector> modifiers; wi::vector modifiers_to_remove; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 9215294eb..b01f982d8 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 55; + const int revision = 56; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);