Dev/terrain material editing (#815)

* terrain material editing

* serialization updates, refactors

---------

Co-authored-by: Turánszki János <turanszkij@users.noreply.github.com>
This commit is contained in:
Egor Zelenkov
2024-03-15 15:47:46 +00:00
committed by GitHub
parent e4d3c64631
commit e97e1cd79c
8 changed files with 417 additions and 94 deletions
+1
View File
@@ -216,6 +216,7 @@ void OptionsWindow::Create(EditorComponent* _editor)
scene.names.Create(pick.entity) = "collider";
break;
case NEW_TERRAIN:
editor->componentsWnd.terrainWnd.entity = pick.entity;
editor->componentsWnd.terrainWnd.SetupAssets();
pick.entity = CreateEntity();
scene.terrains.Create(pick.entity) = editor->componentsWnd.terrainWnd.terrain_preset;
+132 -33
View File
@@ -629,7 +629,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, 980));
SetSize(XMFLOAT2(420, 1000));
closeButton.SetTooltip("Delete Terrain.");
OnClose([=](wi::gui::EventArgs args) {
@@ -1063,6 +1063,58 @@ void TerrainWindow::Create(EditorComponent* _editor)
});
AddWidget(&region3Slider);
materialCombos[wi::terrain::MATERIAL_BASE].Create("Base material: ");
materialCombos[wi::terrain::MATERIAL_SLOPE].Create("Slope material: ");
materialCombos[wi::terrain::MATERIAL_LOW_ALTITUDE].Create("Low altitude material: ");
materialCombos[wi::terrain::MATERIAL_HIGH_ALTITUDE].Create("High altitude material: ");
for (size_t i = 0; i < arraysize(materialCombos); ++i)
{
materialCombos[i].SetTooltip("Select material entity");
materialCombos[i].SetSize(XMFLOAT2(wid, hei));
materialCombos[i].SetPos(XMFLOAT2(x, y += step));
materialCombos[i].OnSelect([&, i](wi::gui::EventArgs args) {
const Scene& scene = editor->GetCurrentScene();
wi::ecs::Entity entity = static_cast<wi::ecs::Entity>(args.userdata);
if (entity != INVALID_ENTITY && scene.materials.Contains(entity))
{
if (terrain->materialEntities[i] != entity)
{
terrain->materialEntities[i] = entity;
terrain->Generation_Restart();
}
}
else
{
terrain->materialEntities[i] = INVALID_ENTITY;
}
});
AddWidget(&materialCombos[i]);
}
materialCombo_GrassParticle.Create("Grass material: ");
materialCombo_GrassParticle.SetTooltip("Select material entity");
materialCombo_GrassParticle.SetSize(XMFLOAT2(wid, hei));
materialCombo_GrassParticle.SetPos(XMFLOAT2(x, y += step));
materialCombo_GrassParticle.OnSelect([&](wi::gui::EventArgs args) {
const Scene& scene = editor->GetCurrentScene();
wi::ecs::Entity entity = static_cast<wi::ecs::Entity>(args.userdata);
if (entity != INVALID_ENTITY && scene.materials.Contains(entity))
{
if (terrain->grassEntity != entity)
{
terrain->grassEntity = entity;
terrain->Generation_Restart();
}
}
else
{
terrain->grassEntity = INVALID_ENTITY;
}
});
AddWidget(&materialCombo_GrassParticle);
propsWindow.reset(new PropsWindow(editor));
AddWidget(propsWindow.get());
@@ -1261,6 +1313,35 @@ void TerrainWindow::SetEntity(Entity entity)
region2Slider.SetValue(terrain->region2);
region3Slider.SetValue(terrain->region3);
auto fillMaterialCombo = [&](wi::gui::ComboBox& comboBox, Entity selected) {
comboBox.ClearItems();
comboBox.AddItem("NO MATERIAL", INVALID_ENTITY);
for (size_t i = 0; i < scene.materials.GetCount(); ++i)
{
Entity entity = scene.materials.GetEntity(i);
if (scene.names.Contains(entity))
{
const NameComponent& name = *scene.names.GetComponent(entity);
comboBox.AddItem(name.name, entity);
}
else
{
comboBox.AddItem(std::to_string(entity), entity);
}
if (selected == entity)
{
comboBox.SetSelectedWithoutCallback(int(i + 1));
}
}
};
for (size_t i = 0; i < arraysize(materialCombos); ++i)
{
fillMaterialCombo(materialCombos[i], terrain->materialEntities[i]);
}
fillMaterialCombo(materialCombo_GrassParticle, terrain->grassEntity);
for (auto& x : terrain->modifiers)
{
switch (x->type)
@@ -1314,23 +1395,37 @@ void TerrainWindow::SetupAssets()
return;
// Customize terrain generator before it's initialized:
terrain_preset.material_Base.SetRoughness(1);
terrain_preset.material_Base.SetReflectance(0.005f);
terrain_preset.material_Slope.SetRoughness(0.1f);
terrain_preset.material_LowAltitude.SetRoughness(1);
terrain_preset.material_HighAltitude.SetRoughness(1);
terrain_preset.material_Base.textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/base.jpg";
terrain_preset.material_Base.textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/base_nor.jpg";
terrain_preset.material_Slope.textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/slope.jpg";
terrain_preset.material_Slope.textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/slope_nor.jpg";
terrain_preset.material_LowAltitude.textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/low_altitude.jpg";
terrain_preset.material_LowAltitude.textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/low_altitude_nor.jpg";
terrain_preset.material_HighAltitude.textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/high_altitude.jpg";
terrain_preset.material_HighAltitude.textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/high_altitude_nor.jpg";
terrain_preset.material_Base.CreateRenderData();
terrain_preset.material_Slope.CreateRenderData();
terrain_preset.material_LowAltitude.CreateRenderData();
terrain_preset.material_HighAltitude.CreateRenderData();
Scene& currentScene = editor->GetCurrentScene();
for (int i = 0; i < wi::terrain::MATERIAL_COUNT; ++i)
{
terrain_preset.materialEntities[i] = CreateEntity();
currentScene.materials.Create(terrain_preset.materialEntities[i]);
currentScene.Component_Attach(terrain_preset.materialEntities[i], entity);
}
MaterialComponent* material_Base = currentScene.materials.GetComponent(terrain_preset.materialEntities[wi::terrain::MATERIAL_BASE]);
MaterialComponent* material_Slope = currentScene.materials.GetComponent(terrain_preset.materialEntities[wi::terrain::MATERIAL_SLOPE]);
MaterialComponent* material_LowAltitude = currentScene.materials.GetComponent(terrain_preset.materialEntities[wi::terrain::MATERIAL_LOW_ALTITUDE]);
MaterialComponent* material_HighAltitude = currentScene.materials.GetComponent(terrain_preset.materialEntities[wi::terrain::MATERIAL_HIGH_ALTITUDE]);
material_Base->SetRoughness(1);
material_Base->SetReflectance(0.005f);
material_Slope->SetRoughness(0.1f);
material_LowAltitude->SetRoughness(1);
material_HighAltitude->SetRoughness(1);
material_Base->textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/base.jpg";
material_Base->textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/base_nor.jpg";
material_Slope->textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/slope.jpg";
material_Slope->textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/slope_nor.jpg";
material_LowAltitude->textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/low_altitude.jpg";
material_LowAltitude->textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/low_altitude_nor.jpg";
material_HighAltitude->textures[MaterialComponent::BASECOLORMAP].name = wi::helper::GetCurrentPath() + "/terrain/high_altitude.jpg";
material_HighAltitude->textures[MaterialComponent::NORMALMAP].name = wi::helper::GetCurrentPath() + "/terrain/high_altitude_nor.jpg";
material_Base->CreateRenderData();
material_Slope->CreateRenderData();
material_LowAltitude->CreateRenderData();
material_HighAltitude->CreateRenderData();
std::string terrain_path = wi::helper::GetCurrentPath() + "/terrain/";
wi::config::File config;
@@ -1431,43 +1526,42 @@ void TerrainWindow::SetupAssets()
}
// Grass config:
terrain_preset.material_GrassParticle.alphaRef = 0.75f;
terrain_preset.grass_properties.length = 2;
terrain_preset.grass_properties.frameCount = 2;
terrain_preset.grass_properties.framesX = 1;
terrain_preset.grass_properties.framesY = 2;
terrain_preset.grass_properties.frameStart = 0;
terrain_preset.grassEntity = CreateEntity();
currentScene.Component_Attach(terrain_preset.grassEntity, entity);
currentScene.materials.Create(terrain_preset.grassEntity);
currentScene.hairs.Create(terrain_preset.grassEntity);
MaterialComponent* material_Grass = currentScene.materials.GetComponent(terrain_preset.grassEntity);
wi::HairParticleSystem* grass = currentScene.hairs.GetComponent(terrain_preset.grassEntity);
wi::config::File grass_config;
grass_config.Open(std::string(terrain_path + "grass.ini").c_str());
if (grass_config.Has("texture"))
{
terrain_preset.material_GrassParticle.textures[MaterialComponent::BASECOLORMAP].name = terrain_path + grass_config.GetText("texture");
terrain_preset.material_GrassParticle.CreateRenderData();
material_Grass->textures[MaterialComponent::BASECOLORMAP].name = terrain_path + grass_config.GetText("texture");
material_Grass->CreateRenderData();
}
if (grass_config.Has("alphaRef"))
{
terrain_preset.material_GrassParticle.alphaRef = grass_config.GetFloat("alphaRef");
material_Grass->alphaRef = grass_config.GetFloat("alphaRef");
}
if (grass_config.Has("length"))
{
terrain_preset.grass_properties.length = grass_config.GetFloat("length");
grass->length = grass_config.GetFloat("length");
}
if (grass_config.Has("frameCount"))
{
terrain_preset.grass_properties.frameCount = grass_config.GetInt("frameCount");
grass->frameCount = grass_config.GetInt("frameCount");
}
if (grass_config.Has("framesX"))
{
terrain_preset.grass_properties.framesX = grass_config.GetInt("framesX");
grass->framesX = grass_config.GetInt("framesX");
}
if (grass_config.Has("framesY"))
{
terrain_preset.grass_properties.framesY = grass_config.GetInt("framesY");
grass->framesY = grass_config.GetInt("framesY");
}
if (grass_config.Has("frameCount"))
{
terrain_preset.grass_properties.frameStart = grass_config.GetInt("frameStart");
grass->frameStart = grass_config.GetInt("frameStart");
}
terrain = &terrain_preset;
@@ -1547,6 +1641,11 @@ void TerrainWindow::ResizeLayout()
add(region1Slider);
add(region2Slider);
add(region3Slider);
for (size_t i = 0; i < arraysize(materialCombos); ++i)
{
add(materialCombos[i]);
}
add(materialCombo_GrassParticle);
add(saveHeightmapButton);
add(saveRegionButton);
add(addModifierCombo);
+3
View File
@@ -122,6 +122,9 @@ public:
wi::gui::Slider region2Slider;
wi::gui::Slider region3Slider;
wi::gui::ComboBox materialCombos[wi::terrain::MATERIAL_COUNT];
wi::gui::ComboBox materialCombo_GrassParticle;
std::unique_ptr<PropsWindow> propsWindow;
enum PRESET
+33 -7
View File
@@ -190,24 +190,24 @@ namespace wi::ecs
{
if (archive.IsReadMode())
{
Clear(); // If we deserialize, we start from empty
const size_t prev_count = components.size();
size_t count;
archive >> count;
components.resize(count);
components.resize(prev_count + count);
for (size_t i = 0; i < count; ++i)
{
components[i].Serialize(archive, seri);
components[prev_count + i].Serialize(archive, seri);
}
entities.resize(count);
entities.resize(prev_count + count);
for (size_t i = 0; i < count; ++i)
{
Entity entity;
SerializeEntity(archive, entity, seri);
entities[i] = entity;
lookup[entity] = i;
entities[prev_count + i] = entity;
lookup[entity] = prev_count + i;
}
}
else
@@ -462,13 +462,39 @@ namespace wi::ecs
// The name must be unique, it will be used in serialization
// version is optional, it will be propagated to ComponentManager::Serialize() inside the EntitySerializer parameter
template<typename T>
inline ComponentManager<T>& Register(std::string name, uint64_t version = 0)
inline ComponentManager<T>& Register(const std::string& name, uint64_t version = 0)
{
entries[name].component_manager = std::make_unique<ComponentManager<T>>();
entries[name].version = version;
return static_cast<ComponentManager<T>&>(*entries[name].component_manager);
}
template<typename T>
inline ComponentManager<T>* Get(const std::string& name)
{
auto it = entries.find(name);
if (it == entries.end())
return nullptr;
return static_cast<ComponentManager<T>*>(it->second.component_manager.get());
}
template<typename T>
inline const ComponentManager<T>* Get(const std::string& name) const
{
auto it = entries.find(name);
if (it == entries.end())
return nullptr;
return static_cast<const ComponentManager<T>*>(it->second.component_manager.get());
}
inline uint64_t GetVersion(std::string name) const
{
auto it = entries.find(name);
if (it == entries.end())
return 0;
return it->second.version;
}
// Serialize all registered component managers
inline void Serialize(wi::Archive& archive, EntitySerializer& seri)
{
+1 -1
View File
@@ -57,7 +57,7 @@ namespace wi::scene
wi::ecs::ComponentManager<ScriptComponent>& scripts = componentLibrary.Register<ScriptComponent>("wi::scene::Scene::scripts");
wi::ecs::ComponentManager<ExpressionComponent>& expressions = componentLibrary.Register<ExpressionComponent>("wi::scene::Scene::expressions");
wi::ecs::ComponentManager<HumanoidComponent>& humanoids = componentLibrary.Register<HumanoidComponent>("wi::scene::Scene::humanoids", 1); // version = 1
wi::ecs::ComponentManager<wi::terrain::Terrain>& terrains = componentLibrary.Register<wi::terrain::Terrain>("wi::scene::Scene::terrains", 3); // version = 3
wi::ecs::ComponentManager<wi::terrain::Terrain>& terrains = componentLibrary.Register<wi::terrain::Terrain>("wi::scene::Scene::terrains", 4); // version = 4
wi::ecs::ComponentManager<wi::Sprite>& sprites = componentLibrary.Register<wi::Sprite>("wi::scene::Scene::sprites");
wi::ecs::ComponentManager<wi::SpriteFont>& fonts = componentLibrary.Register<wi::SpriteFont>("wi::scene::Scene::fonts");
wi::ecs::ComponentManager<wi::VoxelGrid>& voxel_grids = componentLibrary.Register<wi::VoxelGrid>("wi::scene::Scene::voxel_grids");
+234 -47
View File
@@ -410,6 +410,27 @@ namespace wi::terrain
Generation_Cancel();
generator->scene.Clear();
// save material parameters:
wi::scene::MaterialComponent materials[MATERIAL_COUNT];
for (int i = 0; i < MATERIAL_COUNT; ++i)
{
MaterialComponent* material = scene->materials.GetComponent(materialEntities[i]);
if (material == nullptr)
continue;
materials[i] = *material;
materials[i].SetDirty(false);
}
// save grass parameters:
if (scene->hairs.Contains(grassEntity))
{
grass_properties = *scene->hairs.GetComponent(grassEntity);
}
if (scene->materials.Contains(grassEntity))
{
grass_material = *scene->materials.GetComponent(grassEntity);
grass_material.SetDirty(false);
}
for (auto it = chunks.begin(); it != chunks.end(); it++)
{
@@ -463,6 +484,83 @@ namespace wi::terrain
transform.RotateRollPitchYaw(XMFLOAT3(XM_PIDIV4, 0, XM_PIDIV4));
transform.Translate(XMFLOAT3(0, 4, 0));
}
// Restore surface source materials:
{
for (int i = 0; i < MATERIAL_COUNT; ++i)
{
if (materialEntities[i] == INVALID_ENTITY)
{
materialEntities[i] = CreateEntity();
}
scene->Component_Attach(materialEntities[i], terrainEntity);
if (!scene->materials.Contains(materialEntities[i]))
{
scene->materials.Create(materialEntities[i]);
}
if (!scene->names.Contains(materialEntities[i]))
{
NameComponent& name = scene->names.Create(materialEntities[i]);
switch (i)
{
default:
case MATERIAL_BASE:
name = "MATERIAL_BASE";
break;
case MATERIAL_SLOPE:
name = "MATERIAL_SLOPE";
break;
case MATERIAL_LOW_ALTITUDE:
name = "MATERIAL_LOW_ALTITUDE";
break;
case MATERIAL_HIGH_ALTITUDE:
name = "MATERIAL_HIGH_ALTITUDE";
break;
}
}
}
MaterialComponent* material_Base = scene->materials.GetComponent(materialEntities[MATERIAL_BASE]);
MaterialComponent* material_Slope = scene->materials.GetComponent(materialEntities[MATERIAL_SLOPE]);
MaterialComponent* material_LowAltitude = scene->materials.GetComponent(materialEntities[MATERIAL_LOW_ALTITUDE]);
MaterialComponent* material_HighAltitude = scene->materials.GetComponent(materialEntities[MATERIAL_HIGH_ALTITUDE]);
*material_Base = materials[MATERIAL_BASE];
*material_Slope = materials[MATERIAL_SLOPE];
*material_LowAltitude = materials[MATERIAL_LOW_ALTITUDE];
*material_HighAltitude = materials[MATERIAL_HIGH_ALTITUDE];
}
// Restore grass parameters:
{
if (grassEntity == INVALID_ENTITY)
{
grassEntity = CreateEntity();
}
scene->Component_Attach(grassEntity, terrainEntity);
if (!scene->hairs.Contains(grassEntity))
{
scene->hairs.Create(grassEntity) = grass_properties;
}
if (!scene->materials.Contains(grassEntity))
{
scene->materials.Create(grassEntity) = grass_material;
}
if (!scene->names.Contains(grassEntity))
{
scene->names.Create(grassEntity) = "grass";
}
}
if (chunkGroupEntity == INVALID_ENTITY)
{
chunkGroupEntity = CreateEntity();
}
scene->Component_Attach(chunkGroupEntity, terrainEntity);
if (!scene->names.Contains(chunkGroupEntity))
{
scene->names.Create(chunkGroupEntity) = "chunks";
}
}
void Terrain::Generation_Update(const CameraComponent& camera)
@@ -470,9 +568,10 @@ namespace wi::terrain
// The generation task is always cancelled every frame so we are sure that generation is not running at this point
Generation_Cancel();
bool restart_generation = false;
if (!IsGenerationStarted())
{
Generation_Restart();
restart_generation = true;
}
// Check whether any modifiers need to be removed, and we will really remove them here if so:
@@ -489,9 +588,36 @@ namespace wi::terrain
}
}
}
Generation_Restart();
restart_generation = true;
modifiers_to_remove.clear();
}
for (wi::ecs::Entity entity : materialEntities)
{
MaterialComponent* material = scene->materials.GetComponent(entity);
if (material == nullptr)
continue;
if (material->IsDirty())
{
restart_generation = true;
break;
}
}
if (grassEntity != INVALID_ENTITY)
{
MaterialComponent* material_grassparticle_in_scene = scene->materials.GetComponent(grassEntity);
if (material_grassparticle_in_scene != nullptr)
{
if (material_grassparticle_in_scene->IsDirty())
{
restart_generation = true;
}
}
}
if (restart_generation)
{
Generation_Restart();
}
if (terrainEntity == INVALID_ENTITY)
{
@@ -530,34 +656,50 @@ namespace wi::terrain
// Check whether there are any materials that would write to virtual textures:
bool virtual_texture_any = false;
bool virtual_texture_available[TEXTURESLOT_COUNT] = {};
MaterialComponent* virtual_materials[4] = {
&material_Base,
&material_Slope,
&material_LowAltitude,
&material_HighAltitude,
};
for (auto& material : virtual_materials)
if (scene->materials.GetCount() > 0)
{
for (int i = 0; i < TEXTURESLOT_COUNT; ++i)
for (wi::ecs::Entity entity : materialEntities)
{
virtual_texture_available[i] = false;
switch (i)
MaterialComponent* material = scene->materials.GetComponent(entity);
if (material == nullptr)
continue;
for (int i = 0; i < TEXTURESLOT_COUNT; ++i)
{
case MaterialComponent::BASECOLORMAP:
case MaterialComponent::NORMALMAP:
case MaterialComponent::SURFACEMAP:
if (material->textures[i].resource.IsValid())
virtual_texture_available[i] = false;
switch (i)
{
virtual_texture_available[i] = true;
virtual_texture_any = true;
case MaterialComponent::BASECOLORMAP:
case MaterialComponent::NORMALMAP:
case MaterialComponent::SURFACEMAP:
if (material->textures[i].resource.IsValid())
{
virtual_texture_available[i] = true;
virtual_texture_any = true;
}
break;
default:
break;
}
break;
default:
break;
}
}
virtual_texture_available[MaterialComponent::SURFACEMAP] = true; // this is always needed to bake individual material properties
if (grassEntity != INVALID_ENTITY)
{
MaterialComponent* material_grassparticle_in_scene = scene->materials.GetComponent(grassEntity);
if (material_grassparticle_in_scene != nullptr)
{
grass_material = *material_grassparticle_in_scene;
}
HairParticleSystem* hair = scene->hairs.GetComponent(grassEntity);
if (hair != nullptr)
{
grass_properties = *hair;
}
}
}
virtual_texture_available[MaterialComponent::SURFACEMAP] = true; // this is always needed to bake individual material properties
for (auto it = chunks.begin(); it != chunks.end();)
{
@@ -734,7 +876,7 @@ namespace wi::terrain
ObjectComponent& object = *generator->scene.objects.GetComponent(chunk_data.entity);
object.lod_distance_multiplier = lod_multiplier;
object.filterMask |= wi::enums::FILTER_NAVIGATION_MESH;
generator->scene.Component_Attach(chunk_data.entity, terrainEntity);
generator->scene.Component_Attach(chunk_data.entity, chunkGroupEntity);
TransformComponent& transform = *generator->scene.transforms.GetComponent(chunk_data.entity);
transform.ClearTransform();
@@ -899,7 +1041,7 @@ namespace wi::terrain
chunk_data.grass_density_current = grass_density;
grass.strandCount = uint32_t(grass.strandCount * chunk_data.grass_density_current);
grass.CreateRenderData();
generator->scene.materials.Create(chunk_data.grass_entity) = material_GrassParticle;
generator->scene.materials.Create(chunk_data.grass_entity) = grass_material;
generator->scene.transforms.Create(chunk_data.grass_entity);
generator->scene.names.Create(chunk_data.grass_entity) = "grass";
generator->scene.Component_Attach(chunk_data.grass_entity, chunk_data.entity, true);
@@ -1442,11 +1584,14 @@ namespace wi::terrain
device->EventBegin("Render Tile Regions", cmd);
ShaderMaterial materials[4];
material_Base.WriteShaderMaterial(&materials[0]);
material_Slope.WriteShaderMaterial(&materials[1]);
material_LowAltitude.WriteShaderMaterial(&materials[2]);
material_HighAltitude.WriteShaderMaterial(&materials[3]);
ShaderMaterial materials[MATERIAL_COUNT];
for (size_t i = 0; i < MATERIAL_COUNT && scene->materials.GetCount() > 0; ++i)
{
const MaterialComponent* material = scene->materials.GetComponent(materialEntities[i]);
if (material == nullptr)
continue;
material->WriteShaderMaterial(&materials[i]);
}
device->BindDynamicConstantBuffer(materials, 0, cmd);
for (uint32_t map_type = 0; map_type < 3; map_type++)
@@ -1642,10 +1787,11 @@ namespace wi::terrain
Generation_Cancel();
// Note: separate component types serialized within terrain must NOT use the version of the terrain, but their own!
ComponentLibrary& library = *seri.componentlibrary;
const uint64_t terrain_version = seri.GetVersion();
const uint64_t grass_version = seri.componentlibrary->entries["wi::scene::Scene::hairs"].version;
const uint64_t material_version = seri.componentlibrary->entries["wi::scene::Scene::materials"].version;
const uint64_t weather_version = seri.componentlibrary->entries["wi::scene::Scene::weathers"].version;
const uint64_t grass_version = library.GetVersion("wi::scene::Scene::hairs");
const uint64_t material_version = library.GetVersion("wi::scene::Scene::materials");
const uint64_t weather_version = library.GetVersion("wi::scene::Scene::weathers");
if (archive.IsReadMode())
{
@@ -1671,11 +1817,11 @@ namespace wi::terrain
archive >> center_chunk.x;
archive >> center_chunk.z;
if (seri.GetVersion() >= 1)
if (terrain_version >= 1)
{
archive >> physics_generation;
}
if (seri.GetVersion() >= 2 && seri.GetVersion() < 3)
if (terrain_version >= 2 && terrain_version < 3)
{
uint32_t target_texture_resolution;
archive >> target_texture_resolution;
@@ -1687,7 +1833,7 @@ namespace wi::terrain
for (size_t i = 0; i < props.size(); ++i)
{
Prop& prop = props[i];
if (seri.GetVersion() >= 1)
if (terrain_version >= 1)
{
archive >> prop.data;
@@ -1834,7 +1980,7 @@ namespace wi::terrain
{
archive << _flags;
archive << lod_multiplier;
if (seri.GetVersion() < 3)
if (terrain_version < 3)
{
float texlod = 1;
archive << texlod;
@@ -1854,11 +2000,11 @@ namespace wi::terrain
archive << center_chunk.x;
archive << center_chunk.z;
if (seri.GetVersion() >= 1)
if (terrain_version >= 1)
{
archive << physics_generation;
}
if (seri.GetVersion() >= 2 && seri.GetVersion() < 3)
if (terrain_version >= 2 && terrain_version < 3)
{
uint32_t target_texture_resolution = 1024;
archive << target_texture_resolution;
@@ -1940,19 +2086,60 @@ namespace wi::terrain
}
// Caution: seri.version changes must be handled carefully!
seri.version = material_version;
material_Base.Serialize(archive, seri);
material_Slope.Serialize(archive, seri);
material_LowAltitude.Serialize(archive, seri);
material_HighAltitude.Serialize(archive, seri);
material_GrassParticle.Serialize(archive, seri);
if (terrain_version >= 4)
{
SerializeEntity(archive, chunkGroupEntity, seri);
for (size_t i = 0; i < MATERIAL_COUNT; ++i)
{
SerializeEntity(archive, materialEntities[i], seri);
}
SerializeEntity(archive, grassEntity, seri);
}
else
{
// Convert terrain version below 4 to newer version:
seri.version = material_version;
wi::scene::MaterialComponent materials[MATERIAL_COUNT];
materials[MATERIAL_BASE].Serialize(archive, seri);
materials[MATERIAL_SLOPE].Serialize(archive, seri);
materials[MATERIAL_LOW_ALTITUDE].Serialize(archive, seri);
materials[MATERIAL_HIGH_ALTITUDE].Serialize(archive, seri);
grass_material.Serialize(archive, seri);
wi::jobsystem::Wait(seri.ctx); // wait for material CreateRenderData() that was asynchronously launched in Serialize()!
materialEntities[0] = CreateEntity();
materialEntities[1] = CreateEntity();
materialEntities[2] = CreateEntity();
materialEntities[3] = CreateEntity();
grassEntity = CreateEntity();
seri.remap[materialEntities[0]] = materialEntities[0];
seri.remap[materialEntities[1]] = materialEntities[1];
seri.remap[materialEntities[2]] = materialEntities[2];
seri.remap[materialEntities[3]] = materialEntities[3];
seri.remap[grassEntity] = grassEntity;
ComponentManager<MaterialComponent>* scene_materials = library.Get<MaterialComponent>("wi::scene::Scene::materials");
scene_materials->Create(materialEntities[0]) = materials[MATERIAL_BASE];
scene_materials->Create(materialEntities[1]) = materials[MATERIAL_SLOPE];
scene_materials->Create(materialEntities[2]) = materials[MATERIAL_LOW_ALTITUDE];
scene_materials->Create(materialEntities[3]) = materials[MATERIAL_HIGH_ALTITUDE];
scene_materials->Create(grassEntity) = grass_material;
}
seri.version = weather_version;
weather.Serialize(archive, seri);
seri.version = grass_version;
grass_properties.Serialize(archive, seri);
seri.version = terrain_version;
if (terrain_version < 4)
{
seri.version = grass_version;
grass_properties.Serialize(archive, seri);
seri.version = terrain_version;
ComponentManager<wi::HairParticleSystem>* scene_hairs = library.Get<wi::HairParticleSystem>("wi::scene::Scene::hairs");
scene_hairs->Create(grassEntity) = grass_properties;
}
perlin_noise.Serialize(archive);
}
+12 -5
View File
@@ -43,6 +43,14 @@ namespace wi::terrain
static constexpr float chunk_half_width = (chunk_width - 1) * 0.5f;
static constexpr float chunk_width_rcp = 1.0f / (chunk_width - 1);
static constexpr uint32_t vertexCount = chunk_width * chunk_width;
enum
{
MATERIAL_BASE,
MATERIAL_SLOPE,
MATERIAL_LOW_ALTITUDE,
MATERIAL_HIGH_ALTITUDE,
MATERIAL_COUNT
};
struct VirtualTextureAtlas
{
@@ -207,14 +215,13 @@ namespace wi::terrain
uint32_t _flags = CENTER_TO_CAM | REMOVAL | GRASS;
wi::ecs::Entity terrainEntity = wi::ecs::INVALID_ENTITY;
wi::ecs::Entity chunkGroupEntity = wi::ecs::INVALID_ENTITY;
wi::scene::Scene* scene = nullptr;
wi::scene::MaterialComponent material_Base;
wi::scene::MaterialComponent material_Slope;
wi::scene::MaterialComponent material_LowAltitude;
wi::scene::MaterialComponent material_HighAltitude;
wi::scene::MaterialComponent material_GrassParticle;
wi::ecs::Entity materialEntities[MATERIAL_COUNT] = {};
wi::ecs::Entity grassEntity = wi::ecs::INVALID_ENTITY;
wi::scene::WeatherComponent weather;
wi::HairParticleSystem grass_properties;
wi::scene::MaterialComponent grass_material;
wi::unordered_map<Chunk, ChunkData> chunks;
Chunk center_chunk = {};
wi::noise::Perlin perlin_noise;
+1 -1
View File
@@ -9,7 +9,7 @@ namespace wi::version
// minor features, major updates, breaking compatibility changes
const int minor = 71;
// minor bug fixes, alterations, refactors, updates
const int revision = 398;
const int revision = 399;
const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);