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:
@@ -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
@@ -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(®ion3Slider);
|
||||
|
||||
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);
|
||||
|
||||
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user