Skip to content

Commit

Permalink
density map for grass shader added
Browse files Browse the repository at this point in the history
  • Loading branch information
beaumanvienna committed Jun 23, 2024
1 parent d4eb502 commit 6b7c9eb
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 20 deletions.
23 changes: 23 additions & 0 deletions application/lucre/sceneDescriptions/terrain.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,29 @@
],
"fastgltf files":
[
{
"filename": "application/lucre/models/assets/terrain/house.glb",
"instances":
[
{
"transform":
{
"scale":
[
0.276, 0.2898, 0.276
],
"rotation":
[
0.175195, 1.28096, 0.182655
],
"translation":
[
-3.22584, 5.06019, 41.9383
]
}
}
]
},
{
"filename": "application/lucre/models/assets/grass/grass1.glb",
"instances":
Expand Down
4 changes: 2 additions & 2 deletions application/lucre/scenes/terrainScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace LucreApp
float aspectRatio = 1.777f;
float yfov = 0.51f;
float znear = 0.1f;
float zfar = 500.0f;
float zfar = 1500.0f;

PerspectiveCameraComponent perspectiveCameraComponent(aspectRatio, yfov, zfar, znear);
m_CameraController = std::make_shared<CameraController>(perspectiveCameraComponent);
Expand Down Expand Up @@ -170,7 +170,7 @@ namespace LucreApp
m_Skybox = builder.LoadCubemap(faces, m_Registry);
auto view = m_Registry.view<TransformComponent>();
auto& skyboxTransform = view.get<TransformComponent>(m_Skybox);
skyboxTransform.SetScale(250.0f);
skyboxTransform.SetScale(500.0f);
}
{ // directional lights
{
Expand Down
1 change: 1 addition & 0 deletions application/lucre/terrainDescriptions/lucre island.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
{
"modelPath": "application/lucre/models/assets/grass/grass1.glb",
"heightMapPath": "application/lucre/models/assets/terrain/lucreIsland1 heightmap2.png",
"denistyMapPath": "application/lucre/models/assets/terrain/lucreIsland1 grass density map.png",
"transform":
{
"scale":
Expand Down
20 changes: 13 additions & 7 deletions engine/platform/Vulkan/shaders/grass.vert
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,18 @@ struct DirectionalLight
vec4 m_Color; // w is intensity
};

struct InstanceData
struct BaseModelData
{
mat4 m_ModelMatrix;
mat4 m_NormalMatrix;
};

struct GrassShaderData
{
int m_Height;
int m_Index;
};

layout(set = 0, binding = 0) uniform GlobalUniformBuffer
{
mat4 m_Projection;
Expand All @@ -71,12 +77,12 @@ layout(set = 2, binding = 3) uniform ParameterBuffer

layout(set = 2, binding = 0) uniform InstanceUniformBuffer
{
InstanceData m_InstanceData;
BaseModelData m_BaseModelData;
} baseTransform;

layout(set = 2, binding = 2) readonly buffer HeightMap
{
int m_HeightMapData[1]; // actual array size is larger than 1
GrassShaderData m_GrassShaderData[1]; // actual array size is larger than 1
} heightMap;

layout(location = 0) out vec3 fragPosition;
Expand All @@ -87,11 +93,11 @@ layout(location = 4) out vec3 fragTangent;

void main()
{
mat4 baseModelMatrix = baseTransform.m_InstanceData.m_ModelMatrix;
mat4 normalMatrix = baseTransform.m_InstanceData.m_NormalMatrix;
mat4 baseModelMatrix = baseTransform.m_BaseModelData.m_ModelMatrix;
mat4 normalMatrix = baseTransform.m_BaseModelData.m_NormalMatrix;

int index = gl_InstanceIndex;
float hgt = heightMap.m_HeightMapData[index];
int index = heightMap.m_GrassShaderData[gl_InstanceIndex].m_Index;
float hgt = heightMap.m_GrassShaderData[gl_InstanceIndex].m_Height;
float row = floor(index / parameters.m_Width);
float col = floor((index - parameters.m_Width * row));

Expand Down
36 changes: 26 additions & 10 deletions engine/renderer/builder/terrainBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,23 +285,39 @@ namespace GfxRenderEngine
{ // populate landscape
// create a height map on the GPU for grass locations and load a grass model
Terrain::GrassSpec const& grassSpec = terrainSpec.m_GrassSpec;
bool fileExists = EngineCore::FileExists(grassSpec.m_FilepathGrassModel) &&
!EngineCore::IsDirectory(grassSpec.m_FilepathGrassModel);
if (fileExists)
bool GrassModelFound = EngineCore::FileExists(grassSpec.m_FilepathGrassModel) &&
!EngineCore::IsDirectory(grassSpec.m_FilepathGrassModel);
bool densityMapFound = EngineCore::FileExists(grassSpec.m_FilepathDensityMap) &&
!EngineCore::IsDirectory(grassSpec.m_FilepathDensityMap);
if (GrassModelFound && densityMapFound)
{
Image heightMap(grassSpec.m_FilepathGrassHeightMap);
Image densityMap(grassSpec.m_FilepathDensityMap);
CORE_ASSERT((heightMap.Width() == densityMap.Width()) && (heightMap.Height() == densityMap.Height()),
"dimesnion must match");
uint heightMapSize = heightMap.Size();
Resources::ResourceBuffers resourceBuffers;
uint grassInstances = 0;
{
{ // unforunately, need to copy one buffer into another (glsl does not support uint8_t by default)
std::vector<int> bufferData(heightMapSize);
for (uint index = 0; index < heightMapSize; ++index)
{
std::vector<Terrain::GrassShaderData> bufferData(heightMapSize);
for (uint mapIndex = 0; mapIndex < heightMapSize; ++mapIndex)
{
bufferData[index] = heightMap[index];
float normalizedRandom = std::rand() / static_cast<float>(RAND_MAX);
float normalizedDenisty = densityMap[mapIndex] / 255.0f;
float randomizedDensity = normalizedRandom * normalizedDenisty;
bool placeGrass = (heightMap[mapIndex] > 0) && (randomizedDensity > 0.05f);
if (placeGrass)
{
bufferData[grassInstances].m_Height = heightMap[mapIndex];
bufferData[grassInstances].m_Index = mapIndex;
++grassInstances;
}
}
int bufferSize = heightMapSize * sizeof(int); // in bytes
CORE_ASSERT(grassInstances, "no grass placed");
auto& ubo = resourceBuffers[Resources::HEIGHTMAP];
ubo = Buffer::Create(bufferSize, Buffer::BufferUsage::STORAGE_BUFFER_VISIBLE_TO_CPU);
ubo = Buffer::Create(grassInstances * sizeof(Terrain::GrassShaderData),
Buffer::BufferUsage::STORAGE_BUFFER_VISIBLE_TO_CPU);
ubo->MapBuffer();
// update ubo
ubo->WriteToBuffer(bufferData.data());
Expand Down Expand Up @@ -331,7 +347,7 @@ namespace GfxRenderEngine
TreeNode rootNode = sceneGraph.GetNodeByGameObject(grassEntityRoot);
TreeNode grassNode =
sceneGraph.GetNode(rootNode.GetChild(0)); // grass model must be single game object
GrassTag grassTag{heightMapSize};
GrassTag grassTag{grassInstances};
registry.emplace<GrassTag>(grassNode.GetGameObject(), grassTag);

auto& transform = registry.get<TransformComponent>(grassEntityRoot);
Expand Down
6 changes: 6 additions & 0 deletions engine/scene/terrain.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ namespace GfxRenderEngine
float m_ScaleY;
};

struct GrassShaderData
{
int m_Height;
int m_Index;
};
struct TerrainDescription
{
std::string m_Filename;
Expand All @@ -59,6 +64,7 @@ namespace GfxRenderEngine
{
std::string m_FilepathGrassModel;
std::string m_FilepathGrassHeightMap;
std::string m_FilepathDensityMap;
glm::vec3 m_Translation{};
glm::vec3 m_Rotation{};
glm::vec3 m_Scale{};
Expand Down
17 changes: 17 additions & 0 deletions engine/scene/terrainLoaderDeserializeJSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,23 @@ namespace GfxRenderEngine
return;
}
}
else if (grassAttributeKey == "denistyMapPath")
{
CORE_ASSERT((grassAttribute.value().type() == ondemand::json_type::string),
"grass model filepath must be string");
std::string_view densityMapFilenameStringView = grassAttribute.value().get_string();
std::string& filepath = grassSpec.m_FilepathDensityMap;
filepath = std::string(densityMapFilenameStringView);
if (EngineCore::FileExists(filepath))
{
LOG_CORE_INFO("density map for grass found {0}", filepath);
}
else
{
LOG_CORE_ERROR("density map for grass not found: {0}", filepath);
return;
}
}
else if (grassAttributeKey == "transform")
{
CORE_ASSERT((grassAttribute.value().type() == ondemand::json_type::object), "transform must be object");
Expand Down

0 comments on commit 6b7c9eb

Please sign in to comment.