diff --git a/include/Midgard/DynamicTerrain.hpp b/include/Midgard/DynamicTerrain.hpp index 6cfc74e..4d59ef1 100644 --- a/include/Midgard/DynamicTerrain.hpp +++ b/include/Midgard/DynamicTerrain.hpp @@ -15,6 +15,7 @@ class DynamicTerrain final : public Terrain { const Raz::Texture2D& getNoiseMap() const noexcept { return *m_noiseMap; } const Raz::Texture2D& getColorMap() const noexcept { return *m_colorMap; } + const Raz::Texture2D& getSlopeMap() const noexcept { return *m_slopeMap; } void setMinTessellationLevel(float minTessLevel) { setParameters(minTessLevel, m_heightFactor, m_flatness); } void setParameters(float heightFactor, float flatness) override { setParameters(m_minTessLevel, heightFactor, flatness); } @@ -35,14 +36,18 @@ class DynamicTerrain final : public Terrain { void generate(unsigned int width, unsigned int depth, float heightFactor, float flatness, float minTessLevel); const Raz::Texture2D& computeNoiseMap(float factor); const Raz::Texture2D& computeColorMap(); + const Raz::Texture2D& computeSlopeMap(); private: float m_minTessLevel {}; Raz::ComputeShaderProgram m_noiseProgram {}; Raz::ComputeShaderProgram m_colorProgram {}; + Raz::ComputeShaderProgram m_slopeProgram {}; + Raz::Texture2DPtr m_noiseMap {}; Raz::Texture2DPtr m_colorMap {}; + Raz::Texture2DPtr m_slopeMap {}; }; #endif // MIDGARD_DYNAMICTERRAIN_HPP diff --git a/main.cpp b/main.cpp index 1c24d71..dbff4ff 100644 --- a/main.cpp +++ b/main.cpp @@ -192,17 +192,18 @@ int main() { overlay.addSeparator(); #if !defined(USE_OPENGL_ES) - Raz::OverlayTexture& dynamicNoiseTexture = overlay.addTexture(dynamicTerrain.getNoiseMap(), 150, 150); - Raz::OverlayTexture& dynamicColorTexture = overlay.addTexture(dynamicTerrain.getColorMap(), 150, 150); + Raz::OverlayTexture& dynamicNoiseTexture = overlay.addTexture(dynamicTerrain.getNoiseMap(), 125, 125); + Raz::OverlayTexture& dynamicColorTexture = overlay.addTexture(dynamicTerrain.getColorMap(), 125, 125); + Raz::OverlayTexture& dynamicSlopeTexture = overlay.addTexture(dynamicTerrain.getSlopeMap(), 125, 125); #endif Raz::Texture2D colorTexture(colorMap, false); Raz::Texture2D normalTexture(normalMap, false); Raz::Texture2D slopeTexture(slopeMap, false); - [[maybe_unused]] Raz::OverlayTexture& staticColorTexture = overlay.addTexture(colorTexture, 150, 150); - [[maybe_unused]] Raz::OverlayTexture& staticNormalTexture = overlay.addTexture(normalTexture, 150, 150); - [[maybe_unused]] Raz::OverlayTexture& staticSlopeTexture = overlay.addTexture(slopeTexture, 150, 150); + [[maybe_unused]] Raz::OverlayTexture& staticColorTexture = overlay.addTexture(colorTexture, 125, 125); + [[maybe_unused]] Raz::OverlayTexture& staticNormalTexture = overlay.addTexture(normalTexture, 125, 125); + [[maybe_unused]] Raz::OverlayTexture& staticSlopeTexture = overlay.addTexture(slopeTexture, 125, 125); overlay.addSeparator(); @@ -210,6 +211,7 @@ int main() { Raz::OverlaySlider& dynamicNoiseMapFactorSlider = overlay.addSlider("Noise map factor", [&dynamicTerrain] (float value) { dynamicTerrain.computeNoiseMap(value); dynamicTerrain.computeColorMap(); + dynamicTerrain.computeSlopeMap(); }, 0.001f, 0.1f, 0.01f); Raz::OverlaySlider& dynamicMinTessLevelSlider = overlay.addSlider("Min tess. level", [&dynamicTerrain] (float value) { @@ -218,10 +220,12 @@ int main() { Raz::OverlaySlider& dynamicHeightFactorSlider = overlay.addSlider("Height factor", [&dynamicTerrain] (float value) { dynamicTerrain.setHeightFactor(value); + dynamicTerrain.computeSlopeMap(); }, 0.001f, 50.f, 30.f); Raz::OverlaySlider& dynamicFlatnessSlider = overlay.addSlider("Flatness", [&dynamicTerrain] (float value) { dynamicTerrain.setFlatness(value); + dynamicTerrain.computeSlopeMap(); }, 1.f, 10.f, 3.f); #endif @@ -249,6 +253,7 @@ int main() { dynamicTerrainEntity.enable(); dynamicNoiseTexture.enable(); dynamicColorTexture.enable(); + dynamicSlopeTexture.enable(); dynamicNoiseMapFactorSlider.enable(); dynamicMinTessLevelSlider.enable(); dynamicHeightFactorSlider.enable(); @@ -271,6 +276,7 @@ int main() { dynamicTerrainEntity.disable(); dynamicNoiseTexture.disable(); dynamicColorTexture.disable(); + dynamicSlopeTexture.disable(); dynamicNoiseMapFactorSlider.disable(); dynamicMinTessLevelSlider.disable(); dynamicHeightFactorSlider.disable(); diff --git a/shaders/slope.comp b/shaders/slope.comp new file mode 100644 index 0000000..db6d3d7 --- /dev/null +++ b/shaders/slope.comp @@ -0,0 +1,24 @@ +layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; + +layout(r16f, binding = 0) uniform readonly restrict image2D uniHeightmap; +layout(rgba16f, binding = 1) uniform writeonly restrict image2D uniSlopeMap; + +uniform float uniFlatness = 3.0; +uniform float uniHeightFactor = 30.0; + +vec2 computeSlope(ivec2 pixelCoords) { + float leftHeight = pow(imageLoad(uniHeightmap, pixelCoords + ivec2(-1, 0)).r, uniFlatness) * uniHeightFactor; + float rightHeight = pow(imageLoad(uniHeightmap, pixelCoords + ivec2( 1, 0)).r, uniFlatness) * uniHeightFactor; + float topHeight = pow(imageLoad(uniHeightmap, pixelCoords + ivec2( 0, -1)).r, uniFlatness) * uniHeightFactor; + float botHeight = pow(imageLoad(uniHeightmap, pixelCoords + ivec2( 0, 1)).r, uniFlatness) * uniHeightFactor; + + return vec2(leftHeight - rightHeight, topHeight - botHeight); +} + +void main() { + ivec2 pixelCoords = ivec2(gl_GlobalInvocationID.xy); + + vec2 slopeVec = computeSlope(pixelCoords); + float slopeStrength = length(slopeVec) * 0.5; + imageStore(uniSlopeMap, pixelCoords, vec4(normalize(slopeVec), slopeStrength, 1.0)); +} diff --git a/src/Midgard/DynamicTerrain.cpp b/src/Midgard/DynamicTerrain.cpp index bd37627..549bf5a 100644 --- a/src/Midgard/DynamicTerrain.cpp +++ b/src/Midgard/DynamicTerrain.cpp @@ -26,6 +26,10 @@ constexpr std::string_view colorCompSource = { #include "terrain_color.comp.embed" }; +constexpr std::string_view slopeCompSource = { +#include "slope.comp.embed" +}; + inline void checkParameters(float& minTessLevel) { if (minTessLevel <= 0.f) { Raz::Logger::warn("[DynamicTerrain] The minimal tessellation level can't be 0 or negative; remapping to +epsilon."); @@ -43,11 +47,13 @@ DynamicTerrain::DynamicTerrain(Raz::Entity& entity) : Terrain(entity) { m_noiseMap = Raz::Texture2D::create(heightmapSize, heightmapSize, Raz::TextureColorspace::GRAY, Raz::TextureDataType::FLOAT16); m_colorMap = Raz::Texture2D::create(heightmapSize, heightmapSize, Raz::TextureColorspace::RGBA, Raz::TextureDataType::BYTE); + m_slopeMap = Raz::Texture2D::create(heightmapSize, heightmapSize, Raz::TextureColorspace::RGBA, Raz::TextureDataType::FLOAT16); #if !defined(USE_OPENGL_ES) if (Raz::Renderer::checkVersion(4, 3)) { Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, m_noiseMap->getIndex(), "Noise map"); Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, m_colorMap->getIndex(), "Color map"); + Raz::Renderer::setLabel(Raz::RenderObjectType::TEXTURE, m_slopeMap->getIndex(), "Slope map"); } #endif @@ -59,10 +65,15 @@ DynamicTerrain::DynamicTerrain(Raz::Entity& entity) : Terrain(entity) { m_colorProgram.setImageTexture(m_noiseMap, "uniHeightmap", Raz::ImageTextureUsage::READ); m_colorProgram.setImageTexture(m_colorMap, "uniColorMap", Raz::ImageTextureUsage::WRITE); + m_slopeProgram.setShader(Raz::ComputeShader::loadFromSource(slopeCompSource)); + m_slopeProgram.setImageTexture(m_noiseMap, "uniHeightmap", Raz::ImageTextureUsage::READ); + m_slopeProgram.setImageTexture(m_slopeMap, "uniSlopeMap", Raz::ImageTextureUsage::WRITE); + terrainProgram.setTexture(m_noiseMap, "uniHeightmap"); terrainProgram.setTexture(m_colorMap, Raz::MaterialTexture::BaseColor); computeNoiseMap(0.01f); + computeSlopeMap(); computeColorMap(); } @@ -86,6 +97,10 @@ void DynamicTerrain::setParameters(float minTessLevel, float heightFactor, float terrainProgram.setAttribute(m_heightFactor, "uniHeightFactor"); terrainProgram.setAttribute(m_flatness, "uniFlatness"); terrainProgram.sendAttributes(); + + m_slopeProgram.setAttribute(m_heightFactor, "uniHeightFactor"); + m_slopeProgram.setAttribute(m_flatness, "uniFlatness"); + m_slopeProgram.sendAttributes(); } void DynamicTerrain::generate(unsigned int width, unsigned int depth, float heightFactor, float flatness, float minTessLevel) { @@ -158,3 +173,9 @@ const Raz::Texture2D& DynamicTerrain::computeColorMap() { return *m_colorMap; } + +const Raz::Texture2D& DynamicTerrain::computeSlopeMap() { + m_slopeProgram.execute(heightmapSize, heightmapSize); + + return *m_slopeMap; +}