diff --git a/application/lucre/sceneDescriptions/terrain.json b/application/lucre/sceneDescriptions/terrain.json index b097c1e2..95b9ae38 100644 --- a/application/lucre/sceneDescriptions/terrain.json +++ b/application/lucre/sceneDescriptions/terrain.json @@ -13,7 +13,7 @@ { "scale": [ - 0.054, 0.054, 0.054 + 0.0054, 0.054, 0.0054 ], "rotation": [ @@ -30,7 +30,7 @@ { "scale": [ - 0.219, 0.392, 0.219 + 0.0219, 0.392, 0.0219 ], "rotation": [ @@ -53,7 +53,30 @@ { "scale": [ - 0.219, 0.392, 0.219 + 0.0219, 0.392, 0.0219 + ], + "rotation": + [ + 0, 1.11096, 0 + ], + "translation": + [ + -10.523, 0.942, -2.375 + ] + } + } + ] + }, + { + "filename": "application/lucre/terrainDescriptions/lucre island.json", + "instances": + [ + { + "transform": + { + "scale": + [ + 0.0219, 0.392, 0.0219 ], "rotation": [ diff --git a/application/lucre/terrainDescriptions/heightmap.json b/application/lucre/terrainDescriptions/heightmap.json index b729884a..7b39a317 100644 --- a/application/lucre/terrainDescriptions/heightmap.json +++ b/application/lucre/terrainDescriptions/heightmap.json @@ -2,5 +2,10 @@ "file format identifier": 1.2, "description": "height map 2", "author": "Copyright (c) 2024 Engine Development Team", - "terrainPngPath": "application/lucre/models/assets/terrain/heightmap.png" + "heightMapPath": "application/lucre/models/assets/terrain/heightmap.png", + "material": + { + "roughness": 0.1, + "metallic": 0.9 + } } diff --git a/application/lucre/terrainDescriptions/heightmap2.json b/application/lucre/terrainDescriptions/heightmap2.json index 1e472600..174f5c2d 100644 --- a/application/lucre/terrainDescriptions/heightmap2.json +++ b/application/lucre/terrainDescriptions/heightmap2.json @@ -2,5 +2,10 @@ "file format identifier": 1.2, "description": "height map 2", "author": "Copyright (c) 2024 Engine Development Team", - "terrainPngPath": "application/lucre/models/assets/terrain/heightmap2.png" + "heightMapPath": "application/lucre/models/assets/terrain/heightmap2.png", + "material": + { + "roughness": 0.1, + "metallic": 0.9 + } } diff --git a/application/lucre/terrainDescriptions/lucre island.json b/application/lucre/terrainDescriptions/lucre island.json new file mode 100644 index 00000000..39d7aae3 --- /dev/null +++ b/application/lucre/terrainDescriptions/lucre island.json @@ -0,0 +1,11 @@ +{ + "file format identifier": 1.2, + "description": "height map 2", + "author": "Copyright (c) 2024 Engine Development Team", + "heightMapPath": "application/lucre/models/assets/terrain/lucreIsland1 heightmap.png", + "material": + { + "roughness": 0.5, + "metallic": 0.1 + } +} diff --git a/engine/renderer/builder/terrainBuilder.cpp b/engine/renderer/builder/terrainBuilder.cpp index 91b553d4..faa5a328 100644 --- a/engine/renderer/builder/terrainBuilder.cpp +++ b/engine/renderer/builder/terrainBuilder.cpp @@ -32,13 +32,12 @@ namespace GfxRenderEngine void TerrainBuilder::PopulateTerrainData(std::vector> const& heightMap) { - float scale = 0.1f; // Scale for the grid spacing - float heightScale = 1.f; // Scale for the height values size_t rows = heightMap.size(); size_t cols = heightMap.empty() ? 0 : heightMap[0].size(); m_Vertices.resize(rows * cols); size_t vertexCounter = 0; + // vertices for (size_t z = 0; z < rows; ++z) { for (size_t x = 0; x < cols; ++x) @@ -46,9 +45,9 @@ namespace GfxRenderEngine Vertex& vertex = m_Vertices[vertexCounter]; ++vertexCounter; - float originY = heightMap[z][x] * heightScale; + float originY = heightMap[z][x]; - vertex.m_Position = glm::vec3(x * scale, originY, z * scale); + vertex.m_Position = glm::vec3(x, originY, z); vertex.m_Color = glm::vec4(0.f, 0.f, heightMap[z][x] / 3, 1.0f); vertex.m_UV = glm::vec2(0.f, 0.f); vertex.m_Tangent = glm::vec3(1.0f); @@ -60,13 +59,13 @@ namespace GfxRenderEngine // left O right // down glm::vec3 sumNormals(0.0f); - float leftY = x > 0 ? heightMap[z][x - 1] * heightScale : 0.0f; - float rightY = x < cols - 1 ? heightMap[z][x + 1] * heightScale : 0.0f; - float upY = z < rows - 1 ? heightMap[z + 1][x] * heightScale : 0.0f; - float downY = z > 0 ? heightMap[z - 1][x] * heightScale : 0.0f; + float leftY = x > 0 ? heightMap[z][x - 1] : 0.0f; + float rightY = x < cols - 1 ? heightMap[z][x + 1] : 0.0f; + float upY = z < rows - 1 ? heightMap[z + 1][x] : 0.0f; + float downY = z > 0 ? heightMap[z - 1][x] : 0.0f; - float dx = scale; - float dz = scale; + float dx = 1.0f; + float dz = 1.0f; glm::vec3 left = glm::vec3(-dx, leftY - originY, 0.0f); glm::vec3 right = glm::vec3(dx, rightY - originY, 0.0f); @@ -97,6 +96,8 @@ namespace GfxRenderEngine vertex.m_Normal = glm::normalize(sumNormals); } } + + // indices for (size_t z = 0; z < rows - 1; ++z) { for (size_t x = 0; x < cols - 1; ++x) @@ -118,14 +119,15 @@ namespace GfxRenderEngine } } - bool TerrainBuilder::LoadTerrainHeightMap(std::string const& filepath, Scene& scene, int instanceCount) + bool TerrainBuilder::LoadTerrainHeightMap(Scene& scene, int instanceCount, Terrain::TerrainSpec const& terrainSpec) { m_Vertices.clear(); m_Indices.clear(); m_Submeshes.clear(); int width, height, bytesPerPixel; stbi_set_flip_vertically_on_load(false); - uchar* localBuffer = stbi_load(filepath.c_str(), &width, &height, &bytesPerPixel, 0); + std::string const& filepathHeightMap = terrainSpec.m_FilepathHeightMap; + uchar* localBuffer = stbi_load(filepathHeightMap.c_str(), &width, &height, &bytesPerPixel, 0); if (localBuffer) { std::vector> terrainData(height, std::vector(width)); @@ -146,7 +148,7 @@ namespace GfxRenderEngine auto& sceneGraph = scene.GetSceneGraph(); auto& dictionary = scene.GetDictionary(); - auto name = EngineCore::GetFilenameWithoutPath(filepath); + auto name = EngineCore::GetFilenameWithoutPath(terrainSpec.m_FilepathTerrainDescription); name = EngineCore::GetFilenameWithoutExtension(name); InstanceTag instanceTag; @@ -161,7 +163,7 @@ namespace GfxRenderEngine // add to scene graph auto instanceStr = std::to_string(instanceIndex); auto shortName = name + "::" + instanceStr; - auto longName = filepath + "::" + instanceStr; + auto longName = terrainSpec.m_FilepathTerrainDescription + "::" + instanceStr; uint newNode = sceneGraph.CreateNode(entity, shortName, longName, dictionary); sceneGraph.GetRoot().AddChild(newNode); @@ -179,9 +181,7 @@ namespace GfxRenderEngine submesh.m_VertexCount = m_Vertices.size(); submesh.m_InstanceCount = instanceCount; - submesh.m_Material.m_PbrMaterial.m_Roughness = 0.1f; - submesh.m_Material.m_PbrMaterial.m_Metallic = 0.9f; - submesh.m_Material.m_PbrMaterial.m_NormalMapIntensity = 1.0f; + submesh.m_Material.m_PbrMaterial = terrainSpec.m_PbrMaterial; { // create material descriptor Material::MaterialTextures materialTextures; @@ -218,7 +218,7 @@ namespace GfxRenderEngine } else { - LOG_CORE_CRITICAL("TerrainBuilder::LoadTerrainHeightMapPNG: Couldn't load file {0}", filepath); + LOG_CORE_CRITICAL("TerrainBuilder::LoadTerrainHeightMap: Couldn't load file {0}", filepathHeightMap); } return false; diff --git a/engine/renderer/builder/terrainBuilder.h b/engine/renderer/builder/terrainBuilder.h index 9d3b8a1b..d648b3b1 100644 --- a/engine/renderer/builder/terrainBuilder.h +++ b/engine/renderer/builder/terrainBuilder.h @@ -24,6 +24,7 @@ #include "renderer/model.h" #include "scene/scene.h" +#include "scene/terrain.h" namespace GfxRenderEngine { @@ -33,7 +34,7 @@ namespace GfxRenderEngine public: TerrainBuilder() = default; - bool LoadTerrainHeightMap(const std::string& filepath, Scene& scene, int instanceCount); + bool LoadTerrainHeightMap(Scene& scene, int instanceCount, Terrain::TerrainSpec const& terrainSpec); private: void PopulateTerrainData(std::vector> const& heightMap); diff --git a/engine/scene/sceneLoaderDeserializeJSON.cpp b/engine/scene/sceneLoaderDeserializeJSON.cpp index bc8ddb9f..890f690b 100644 --- a/engine/scene/sceneLoaderDeserializeJSON.cpp +++ b/engine/scene/sceneLoaderDeserializeJSON.cpp @@ -605,6 +605,7 @@ namespace GfxRenderEngine { std::string entityName = name + std::string("::" + std::to_string(instanceIndex)); entt::entity entity = m_Scene.m_Dictionary.Retrieve(entityName); + CORE_ASSERT(entity != entt::null, "couldn't find entity"); Terrain::Instance& terrainInstance = terrainInstances[instanceIndex]; terrainInstance.m_Entity = entity; ondemand::object instanceObjects = instance.value(); diff --git a/engine/scene/terrain.h b/engine/scene/terrain.h index e3f99308..d66daf2c 100644 --- a/engine/scene/terrain.h +++ b/engine/scene/terrain.h @@ -47,5 +47,12 @@ namespace GfxRenderEngine TerrainDescription(std::string const& filename) : m_Filename{filename} {} }; + struct TerrainSpec + { + Material::PbrMaterial m_PbrMaterial{}; + std::string m_FilepathTerrainDescription; + std::string m_FilepathHeightMap; + }; + } // namespace Terrain } // namespace GfxRenderEngine \ No newline at end of file diff --git a/engine/scene/terrainLoaderDeserializeJSON.cpp b/engine/scene/terrainLoaderDeserializeJSON.cpp index 383974cc..d80ade3e 100644 --- a/engine/scene/terrainLoaderDeserializeJSON.cpp +++ b/engine/scene/terrainLoaderDeserializeJSON.cpp @@ -45,6 +45,9 @@ namespace GfxRenderEngine ondemand::document terrainDocument = parser.iterate(json); ondemand::object terrainAttributess = terrainDocument.get_object(); + Terrain::TerrainSpec terrainSpec{}; + terrainSpec.m_FilepathTerrainDescription = filepath; + for (auto terrainAttributes : terrainAttributess) { std::string_view terrainAttributesKey = terrainAttributes.unescaped_key(); @@ -59,13 +62,14 @@ namespace GfxRenderEngine std::trunc(SUPPORTED_FILE_FORMAT_VERSION)), "The terrain description major version does not match"); } - else if (terrainAttributesKey == "terrainPngPath") + else if (terrainAttributesKey == "heightMapPath") { CORE_ASSERT((terrainAttributes.value().type() == ondemand::json_type::string), - "Terrain path must be string"); + "heightmap path must be string"); std::string_view terrainPath = terrainAttributes.value().get_string(); - m_TerrainDescriptionFile.m_TerrainPngPath = std::string(terrainPath); - LOG_CORE_INFO("Terrain PNG Path: {0}", m_TerrainDescriptionFile.m_TerrainPngPath); + m_TerrainDescriptionFile.m_FilepathHeightMap = std::string(terrainPath); + terrainSpec.m_FilepathHeightMap = m_TerrainDescriptionFile.m_FilepathHeightMap; + LOG_CORE_INFO("Heightmap Path: {0}", m_TerrainDescriptionFile.m_FilepathHeightMap); } else if (terrainAttributesKey == "description") { @@ -81,6 +85,30 @@ namespace GfxRenderEngine m_TerrainDescriptionFile.m_Author = std::string(terrainAuthor); LOG_CORE_INFO("author: {0}", m_TerrainDescriptionFile.m_Author); } + else if (terrainAttributesKey == "material") + { + CORE_ASSERT((terrainAttributes.value().type() == ondemand::json_type::object), "type must be object"); + Material::PbrMaterial& pbrMaterial = m_TerrainDescriptionFile.m_PbrMaterial; + ondemand::object materialJSON = terrainAttributes.value(); + for (auto materialComponent : materialJSON) + { + std::string_view materialComponentKey = materialComponent.unescaped_key(); + if (materialComponentKey == "roughness") + { + pbrMaterial.m_Roughness = materialComponent.value().get_double(); + terrainSpec.m_PbrMaterial.m_Roughness = pbrMaterial.m_Roughness; + } + else if (materialComponentKey == "metallic") + { + pbrMaterial.m_Metallic = materialComponent.value().get_double(); + terrainSpec.m_PbrMaterial.m_Metallic = pbrMaterial.m_Metallic; + } + else + { + LOG_CORE_CRITICAL("unrecognized material property '" + std::string(materialComponentKey) + "'"); + } + } + } else { LOG_CORE_CRITICAL("unrecognized terrain object '" + std::string(terrainAttributesKey) + "'"); @@ -88,7 +116,7 @@ namespace GfxRenderEngine } TerrainBuilder builder{}; - return builder.LoadTerrainHeightMap(m_TerrainDescriptionFile.m_TerrainPngPath, m_Scene, instanceCount); + return builder.LoadTerrainHeightMap(m_Scene, instanceCount, terrainSpec); } } // namespace GfxRenderEngine diff --git a/engine/scene/terrainLoaderJSON.h b/engine/scene/terrainLoaderJSON.h index b896caf8..2d7e218c 100644 --- a/engine/scene/terrainLoaderJSON.h +++ b/engine/scene/terrainLoaderJSON.h @@ -52,7 +52,8 @@ namespace GfxRenderEngine double m_FileFormatIdentifier; std::string m_Description; std::string m_Author; - std::string m_TerrainPngPath; + std::string m_FilepathHeightMap; + Material::PbrMaterial m_PbrMaterial; }; private: