skatemakerpro/docs/GRASS.md
type-two a5c8765776 GODVERSE grass system + test-ride grinds
js/grass.js: reusable single-file grass module for all our games — GPU-instanced
blades (33k+ in one draw call), vertex-shader wind hashed per blade, root->tip
fake-AO gradient x per-instance tint, alpha-test pixel style (nearest-filter
16x24 canvas cards, stepped sway), deterministic seed, player-push uniform.
docs/GRASS.md records the technique ladder (clump maps, shell texturing,
billboard LOD, MB atlas gen) for future tiers. Auto-grows on parkland + islands,
PARK panel style/density, included in exported levels via buildParkScene.

Test ride: grind physics — falling onto any flattened steel (rails, ledge caps,
pool coping) locks a slide along the segment, pop off with Space or ride off the
end; grass parts around the rider.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 20:39:45 +10:00

60 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# GODVERSE grass — the module and the tricks
`js/grass.js` is the canonical grass system for all our games. It's a **system, not a
mesh** — that's why it lives as a code module with style presets, not as GLBs on the
farm. Lift the single file into any three.js project:
```js
import { makeGrass } from './grass.js';
const grass = makeGrass({ heightAt, areas, style: 'lush', density: 8 });
scene.add(grass); // self-ticking wind; add and forget
grass.userData.setPlayer(x, z); // optional: grass parts around the player
```
Styles: `lush` (tapered instanced blades), `dry` (same, straw palette),
`pixel` (crossed alpha-test cards, 16×24 nearest-filter canvas texture, banded
palette, stepped sway — PS1/N64 vibe).
## The tricks it uses (why it's fast)
1. **GPU instancing** — one `InstancedMesh` = one draw call for up to 40k blades.
Per-blade cost after spawn is zero on the CPU.
2. **Vertex-shader wind**`sin(time + hash(blade origin))`, bend scaled by
`uv.y²` so roots stay planted, tips fly. Two frequencies layered so it doesn't
look like a metronome. Pixel style floors the sway to 3 steps.
3. **Root→tip gradient with darkened base** — geometry vertex colors (0.35 at the
root → 1.15 at the tip) multiply with a per-instance tip tint. Reads as ambient
occlusion without any lighting cost. *The single biggest visual win.*
4. **Per-instance jitter** — scale, rotation, lean, hue offset. Uniformity is what
makes cheap grass look cheap.
5. **alphaTest, never alpha-blend** — no depth sorting, no overdraw melt.
6. **No per-blade shadows** — the base darkening does that job.
7. **Deterministic seed** (mulberry32) — same park, same lawn, every load.
8. **Player-push uniform** — blades within 1.2m bend away from the rider. Sells
physicality for one uniform update per frame.
## The next tiers (when a game needs bigger fields)
- **Chunked frustum culling** — split into 16m tiles, cull per-tile. Needed beyond
~100m fields; our parks don't need it yet.
- **Far-field billboard cards** — crossed quads with a grass-clump texture past
~40m, instanced blades near. Classic LOD split.
- **Clump maps** (Ghost of Tsushima GDC 2021, "Procedural Grass in Ghost of
Tsushima") — sample a Voronoi clump texture: blades in a clump share lean/height,
clump centers get taller blades. Breaks the "even lawn" look at scale.
- **Shell texturing** (Acerola's "How Do Games Render So Much Grass?") — N stacked
transparent shells; dot patterns at increasing height thresholds. Ultra cheap
retro turf/fur; a natural fourth style for the pixel games.
- **Bezier blades + tessellation** for hero close-ups (Sucker Punch use 3-4 verts
per blade too — verts are not where the money is; shading is).
- **MODELBEAST atlas textures** — flux_local can generate blade/clump atlases for
the billboard tiers (`grass blade atlas, alpha background, hand-painted style`),
then `bg_remove_local` for clean alpha.
## In SKATEMAKER PRO
Grass auto-grows on the parkland ring outside the slab and on ISLAND pads, from
`park.grass` (`{style, density}` — PARK panel when nothing is selected). Exported
levels include it via `buildParkScene`; the editor rebuilds it on committed ground
changes only (never mid-drag).