Trees and rocks on the terrain: terrain.scatter by layer and slope (ENG-F79) #131
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "khyretos/claude/foliage-2"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Requested by Kees · project thread
Rebased onto main after #130 (day/night clock), which it builds on. All 1317 tests pass locally.
What (ENG-F79: trees, rocks and bushes)
Terrain::scatter(rule)puts one point per cell of a jittered grid, so things never pile up or line up in rows, and the same seed gives the same places on every machine. A point is kept only if the rule allows it: on a painted layer aboveminWeight(thinning towards the layer's edge), undermaxSlope, betweenminHeightandmaxHeight, inside an optional circle, and outside everykeepClearcircle. Each kept thing gets a random turn and size and stands straight or leans with the ground (Placement::transform()).terrain.scatter{model, density, layer, minWeight, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max}returns the group and a count. It spawns ordinary ModelModule instances, which are already drawn instanced and frustum-culled.solid = radds a static capsule trunk up the model's height, so the player bumps into trees. Alsoterrain.unscatter(group)andterrain.scattered(). There's a limit of 50,000 per game. Sculpting moves scattered things and their trunks along with the ground.valley.lua(algorithms.md "A valley with the engine's terrain"). It makes a seeded valley round the starter level with a flattened pad, a painted path and a hill, runs a day in a minute, and N makes a new valley. It runs in CI with the other recipes, so the terrain and the clock get a real-GPU check on every push. The screenshot was made withrun_recipes.py --shots.Tests
Terrain.ScatterFollowsTheRulesAndIsTheSameEveryTime: the same seed gives the same points; the count is about density × allowed area; nothing lands on a 63° bank under maxSlope 30; points sit on the ground; a layer, a circle and a clear circle are all respected;maxcaps the count; leaning things point along the ground's normal (through the transform).kke_tests: 1317 passed after the rebase, no warnings;mkdocs --strictis clean;run_recipes.pypasses for valley.lua and terrain.lua.density = 3, maxSlope = 25placed 949 trees with the start kept clear, plus 61 small ones only on the painted dirt path. The screenshot shows a forest on the gentle ground, none on the rock faces, and the clearing round the player.🤖 Generated with Claude Code
https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
Terrain::scatter places points on a jittered grid (one per cell, the same for the same seed everywhere), kept where the rule allows: a painted layer (thinning at its edge), a slope limit, a height band, a circle, and circles kept clear. Placements lean with the ground or stand straight, with a random turn and size. Lua terrain.scatter{model, density, layer, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max} spawns model instances (instanced and culled by ModelModule), optionally with static capsule trunks; unscatter(group) and scattered(). Sculpting moves scattered things and their trunks with the ground. At most 50,000 per game. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7/review
Title
Trees and rocks on the terrain: terrain.scatter by layer and slope (ENG-F79)
User description
Requested by Kees · project thread
Rebased onto main after #130 (day/night clock), which it builds on. All 1317 tests pass locally.
What (ENG-F79: trees, rocks and bushes)
Terrain::scatter(rule)puts one point per cell of a jittered grid, so things never pile up or line up in rows, and the same seed gives the same places on every machine. A point is kept only if the rule allows it: on a painted layer aboveminWeight(thinning towards the layer's edge), undermaxSlope, betweenminHeightandmaxHeight, inside an optional circle, and outside everykeepClearcircle. Each kept thing gets a random turn and size and stands straight or leans with the ground (Placement::transform()).terrain.scatter{model, density, layer, minWeight, maxSlope, minHeight, maxHeight, scale, align, pos, radius, clear, solid, seed, max}returns the group and a count. It spawns ordinary ModelModule instances, which are already drawn instanced and frustum-culled.solid = radds a static capsule trunk up the model's height, so the player bumps into trees. Alsoterrain.unscatter(group)andterrain.scattered(). There's a limit of 50,000 per game. Sculpting moves scattered things and their trunks along with the ground.valley.lua(algorithms.md "A valley with the engine's terrain"). It makes a seeded valley round the starter level with a flattened pad, a painted path and a hill, runs a day in a minute, and N makes a new valley. It runs in CI with the other recipes, so the terrain and the clock get a real-GPU check on every push. The screenshot was made withrun_recipes.py --shots.Tests
Terrain.ScatterFollowsTheRulesAndIsTheSameEveryTime: the same seed gives the same points; the count is about density × allowed area; nothing lands on a 63° bank under maxSlope 30; points sit on the ground; a layer, a circle and a clear circle are all respected;maxcaps the count; leaning things point along the ground's normal (through the transform).kke_tests: 1317 passed after the rebase, no warnings;mkdocs --strictis clean;run_recipes.pypasses for valley.lua and terrain.lua.density = 3, maxSlope = 25placed 949 trees with the start kept clear, plus 61 small ones only on the painted dirt path. The screenshot shows a forest on the gentle ground, none on the rock faces, and the clearing round the player.🤖 Generated with Claude Code
https://claude.ai/code/session_019rkS6wq7fV9fWdiLwxyyc7
PR Type
Enhancement
Description
Adds
terrain.scatterto place trees and rocks by ruleSupports layer, slope, height, circles, and solid trunks
Scattered items move with sculpted terrain and support unscatter
Diagram Walkthrough
File Walkthrough
4 files
Adds scatter rule and placement transform methodsImplements jittered grid scattering with rulesAdds model storage and group tracking structuresRegisters scatter/unscatter Lua functions and logic2 files
Connects ScriptTerrain to ModelModule instanceAdds camera config for valley recipe1 files
Tests scatter rules and deterministic placement5 files
New recipe showing valley with day cycleDocuments scatter API and usage examplesUpdates terrain function list with scatterMarks foliage task as done with detailsReferences new valley recipe in algorithms1 files
PR Reviewer Guide 🔍
(Review updated until commit
cdbe85bda5)📋 Focus areas: 🔴 2 open · ✅ 0 handled. Every push re-checks them; a handled area moves to Resolved findings at the bottom.
PR Code Suggestions ✨
No code suggestions found for the PR.
🧹 Lint report · ❌ 38 problems in 6 checks · 🧹 3 formatting checks to tidy
Nothing here blocks the merge (report only).
MARKDOWN · markdownlint: first lines of the output
CPP · cppcheck: first lines of the output
YAML · yamllint: first lines of the output
BASH · shellcheck: first lines of the output
DOCKERFILE · hadolint: first lines of the output
REPOSITORY · trivy: first lines of the output
🧹 Formatting only (layout, no behaviour; the nightly lint-fix job applies these as a PR): YAML · prettier (57 files checked), BASH · shfmt (11 files checked), JSON · prettier (147 files checked)
✅ Clean: actionlint, git_diff, gitleaks, grype, jsonlint, secretlint, stylelint, trufflehog, xmllint
MegaLinter on soucouyant · full logs in the Actions run · comment
/improvefor AI fix suggestions