mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-06 00:53:52 +00:00
feat(editor): smooth entire tile, snap-to-ground toggle, object list improvements
- Smooth Entire Tile: global smoothing pass with configurable iterations (1-10). Smooths across chunk boundaries for seamless results. Updates inner vertices from smoothed outer grid. Great after noise generation. - Snap to Ground checkbox: on by default, objects placed at terrain surface. Disable for floating/airborne objects. - Random Rotation + Snap Ground checkboxes side-by-side for fast setup - Toast notifications on noise apply and smooth operations - Smooth pass uses cross-chunk neighbor averaging for edge continuity
This commit is contained in:
parent
5df007b7b9
commit
9bc05fae87
4 changed files with 82 additions and 1 deletions
|
|
@ -336,9 +336,16 @@ void EditorUI::renderBrushPanel(EditorApp& app) {
|
|||
if (ImGui::Button("Apply Noise", ImVec2(-1, 0))) {
|
||||
app.getTerrainEditor().applyNoise(noiseFreq, noiseAmp, noiseOctaves,
|
||||
static_cast<uint32_t>(noiseSeed));
|
||||
app.showToast("Noise applied");
|
||||
}
|
||||
static int smoothPasses = 2;
|
||||
ImGui::SliderInt("Smooth Passes", &smoothPasses, 1, 10);
|
||||
if (ImGui::Button("Smooth Entire Tile", ImVec2(-1, 0))) {
|
||||
app.getTerrainEditor().smoothEntireTile(smoothPasses);
|
||||
app.showToast("Tile smoothed");
|
||||
}
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1),
|
||||
"Adds procedural hills/valleys to entire tile");
|
||||
"Generate terrain, then smooth for natural look");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
|
@ -466,6 +473,10 @@ void EditorUI::renderObjectPanel(EditorApp& app) {
|
|||
bool randRot = placer.getRandomRotation();
|
||||
if (ImGui::Checkbox("Random Rotation", &randRot))
|
||||
placer.setRandomRotation(randRot);
|
||||
ImGui::SameLine();
|
||||
bool snap = placer.getSnapToGround();
|
||||
if (ImGui::Checkbox("Snap Ground", &snap))
|
||||
placer.setSnapToGround(snap);
|
||||
float scale = placer.getPlacementScale();
|
||||
if (ImGui::SliderFloat("Scale", &scale, 0.1f, 10.0f, "%.2f"))
|
||||
placer.setPlacementScale(scale);
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ public:
|
|||
void setPlacementScale(float s) { placementScale_ = s; }
|
||||
bool getRandomRotation() const { return randomRotation_; }
|
||||
void setRandomRotation(bool v) { randomRotation_ = v; }
|
||||
bool getSnapToGround() const { return snapToGround_; }
|
||||
void setSnapToGround(bool v) { snapToGround_ = v; }
|
||||
|
||||
// Undo last placement
|
||||
bool canUndoPlace() const { return !undoStack_.empty(); }
|
||||
|
|
@ -81,6 +83,7 @@ private:
|
|||
float placementRotY_ = 0.0f;
|
||||
float placementScale_ = 1.0f;
|
||||
bool randomRotation_ = false;
|
||||
bool snapToGround_ = true;
|
||||
};
|
||||
|
||||
} // namespace editor
|
||||
|
|
|
|||
|
|
@ -588,6 +588,70 @@ void TerrainEditor::removeWater(const glm::vec3& center, float radius) {
|
|||
}
|
||||
}
|
||||
|
||||
void TerrainEditor::smoothEntireTile(int iterations) {
|
||||
if (!terrain_) return;
|
||||
|
||||
for (int iter = 0; iter < iterations; iter++) {
|
||||
// Snapshot all heights
|
||||
std::array<std::array<float, 145>, 256> snap;
|
||||
for (int ci = 0; ci < 256; ci++)
|
||||
for (int v = 0; v < 145; v++)
|
||||
snap[ci][v] = terrain_->chunks[ci].heightMap.heights[v];
|
||||
|
||||
for (int ci = 0; ci < 256; ci++) {
|
||||
auto& chunk = terrain_->chunks[ci];
|
||||
if (!chunk.hasHeightMap()) continue;
|
||||
int cx = ci % 16, cy = ci / 16;
|
||||
|
||||
for (int v = 0; v < 145; v++) {
|
||||
int row = v / 17, col = v % 17;
|
||||
if (col > 8) continue; // smooth outer vertices only
|
||||
|
||||
float sum = snap[ci][v];
|
||||
int count = 1;
|
||||
|
||||
// Same-chunk neighbors
|
||||
if (col > 0) { sum += snap[ci][row * 17 + col - 1]; count++; }
|
||||
if (col < 8) { sum += snap[ci][row * 17 + col + 1]; count++; }
|
||||
if (row > 0) { sum += snap[ci][(row - 1) * 17 + col]; count++; }
|
||||
if (row < 8) { sum += snap[ci][(row + 1) * 17 + col]; count++; }
|
||||
|
||||
// Cross-chunk neighbors at edges
|
||||
if (col == 0 && cx > 0) { sum += snap[cy * 16 + cx - 1][row * 17 + 8]; count++; }
|
||||
if (col == 8 && cx < 15) { sum += snap[cy * 16 + cx + 1][row * 17 + 0]; count++; }
|
||||
if (row == 0 && cy > 0) { sum += snap[(cy - 1) * 16 + cx][8 * 17 + col]; count++; }
|
||||
if (row == 8 && cy < 15) { sum += snap[(cy + 1) * 16 + cx][0 * 17 + col]; count++; }
|
||||
|
||||
chunk.heightMap.heights[v] = sum / static_cast<float>(count);
|
||||
}
|
||||
|
||||
// Update inner vertices from smoothed outer vertices
|
||||
for (int v = 0; v < 145; v++) {
|
||||
int row = v / 17, col = v % 17;
|
||||
if (col <= 8) continue;
|
||||
int innerCol = col - 9;
|
||||
// Average of 4 surrounding outer vertices
|
||||
int tl = row * 17 + innerCol;
|
||||
int tr = row * 17 + innerCol + 1;
|
||||
int bl = (row + 1) * 17 + innerCol;
|
||||
int br = (row + 1) * 17 + innerCol + 1;
|
||||
if (tl < 145 && tr < 145 && bl < 145 && br < 145)
|
||||
chunk.heightMap.heights[v] = (chunk.heightMap.heights[tl] +
|
||||
chunk.heightMap.heights[tr] + chunk.heightMap.heights[bl] +
|
||||
chunk.heightMap.heights[br]) * 0.25f;
|
||||
}
|
||||
}
|
||||
|
||||
// Stitch all edges
|
||||
for (int ci = 0; ci < 256; ci++)
|
||||
stitchEdges(ci);
|
||||
}
|
||||
|
||||
for (int ci = 0; ci < 256; ci++)
|
||||
dirtyChunks_.push_back(ci);
|
||||
dirty_ = true;
|
||||
}
|
||||
|
||||
void TerrainEditor::applyErode(float dt) {
|
||||
float factor = std::min(1.0f, brush_.settings().strength * dt * 0.3f);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,9 @@ public:
|
|||
// Noise generator: applies procedural height noise to the terrain
|
||||
void applyNoise(float frequency, float amplitude, int octaves, uint32_t seed);
|
||||
|
||||
// Global smooth pass across entire tile (N iterations)
|
||||
void smoothEntireTile(int iterations);
|
||||
|
||||
// Import/export heightmap (raw 16-bit grayscale, 129x129)
|
||||
bool importHeightmap(const std::string& path, float heightScale);
|
||||
bool exportHeightmap(const std::string& path, float heightScale);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue