diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index f504f915..601cd5e8 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -651,6 +651,21 @@ void EditorUI::renderBrushPanel(EditorApp& app) { ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1), "No stamp copied"); } + if (ImGui::CollapsingHeader("Detail Noise")) { + static float detailAmp = 2.0f, detailFreq = 0.1f; + static int detailSeed = 99; + ImGui::SliderFloat("Amplitude##detail", &detailAmp, 0.5f, 10.0f); + ImGui::SliderFloat("Frequency##detail", &detailFreq, 0.01f, 0.5f, "%.3f"); + ImGui::InputInt("Seed##detail", &detailSeed); + if (ImGui::Button("Add Detail", ImVec2(-1, 0))) { + app.getTerrainEditor().addDetailNoise(detailAmp, detailFreq, + static_cast(detailSeed)); + app.showToast("Detail noise added"); + } + ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1), + "Adds small-scale roughness to existing terrain"); + } + if (ImGui::CollapsingHeader("Edge Ramp (Multi-tile)")) { static float rampTarget = 100.0f, rampWidth = 20.0f; ImGui::SliderFloat("Target Height##ramp", &rampTarget, 0.0f, 500.0f); diff --git a/tools/editor/terrain_editor.cpp b/tools/editor/terrain_editor.cpp index 34170277..1a0efa79 100644 --- a/tools/editor/terrain_editor.cpp +++ b/tools/editor/terrain_editor.cpp @@ -985,6 +985,29 @@ void TerrainEditor::smoothBeaches(float waterHeight, float beachWidth) { dirty_ = true; } +void TerrainEditor::addDetailNoise(float amplitude, float frequency, uint32_t seed) { + if (!terrain_) return; + auto hash2d = [](int x, int y, uint32_t s) -> float { + uint32_t h = static_cast(x * 374761393 + y * 668265263 + s); + h = (h ^ (h >> 13)) * 1274126177; + h = h ^ (h >> 16); + return (static_cast(h & 0xFFFF) / 65535.0f - 0.5f) * 2.0f; + }; + for (int ci = 0; ci < 256; ci++) { + auto& chunk = terrain_->chunks[ci]; + if (!chunk.hasHeightMap()) continue; + for (int v = 0; v < 145; v++) { + glm::vec3 pos = chunkVertexWorldPos(ci, v); + int ix = static_cast(std::floor(pos.x * frequency)); + int iy = static_cast(std::floor(pos.y * frequency)); + chunk.heightMap.heights[v] += hash2d(ix, iy, seed) * amplitude; + } + dirtyChunks_.push_back(ci); + } + for (int ci = 0; ci < 256; ci++) stitchEdges(ci); + dirty_ = true; +} + void TerrainEditor::rampEdges(float targetHeight, float rampWidth) { if (!terrain_) return; float relTarget = targetHeight - terrain_->chunks[0].position[2]; diff --git a/tools/editor/terrain_editor.hpp b/tools/editor/terrain_editor.hpp index 7ad3ca5a..065e0acc 100644 --- a/tools/editor/terrain_editor.hpp +++ b/tools/editor/terrain_editor.hpp @@ -123,6 +123,9 @@ public: // Ramp tile edges to a target height for seamless multi-tile joins void rampEdges(float targetHeight, float rampWidth); + // Add random detail noise to existing terrain (preserves shape, adds roughness) + void addDetailNoise(float amplitude, float frequency, uint32_t seed); + // Import/export heightmap (raw 16-bit grayscale, 129x129) bool importHeightmap(const std::string& path, float heightScale); bool exportHeightmap(const std::string& path, float heightScale);