Best seen in video not pictures:
https://streamable.com/hu3bzs
Grass density can be set per terrain material in Titan Editor:
AI written summary:
GPU Grass (Ghost-of-Tsushima-style) for Titan Engine — feature + tutorial
I've added a GPU-driven grass system to my Esenthel/Titan fork and wanted to share it. It generates grass entirely on the GPU each frame using Vulkan mesh shaders, writing straight into the deferred G-buffer — so the engine's normal lighting, shadows, SSR, and fog apply for free. It's a parallel path that bypasses the shader/material system (the shader compiler has no mesh/task stage), and it's purely additive — the legacy CPU GrassObj foliage still works untouched.
What it does
- Deferred, lit grass on the GPU — VK_EXT_mesh_shader; blades generated per frame, no vertex/index buffers. Vulkan-only (inert on GL/DX, which keep the legacy grass).
- Terrain-following + per-material density — a camera-centered control texture samples terrain height + a density built from terrain slope × the material's grass_density. Blades drape the heightfield, thin on slopes, and grow only where you author them.
- World-anchored + smooth LOD — blades are seeded by absolute world position (no "swim" as the field re-centers), and density fades smoothly with distance instead of popping.
- Interaction:
- trample(pos, radius, strength) — footstep flatten that springs back; a decoupled, world-anchored field uploaded dirty-region only.
- blast(pos, radius, strength) — one-shot radial knockdown shockwave that springs back.
- Exclusion zones — addZoneCircle / addZoneBox(center, half, yaw, soft) → handle, removeZone: persistent analytic CUT footprints (e.g. building placements) where grass is removed with a soft edge, plus a per-patch "fully enclosed → skip" early-out.
- Wind — analytic flow field with traveling gust fronts + a slow sway.
Opt-in by material
Grass density is a per-material attribute (Material::grass_density, 0..1) with an editor "Grass Density" slider. It defaults to 0, so GPU grass is opt-in: enabling the system on an existing world shows nothing until you raise density on the grass materials. Author it toward 1 on grass/dirt, leave it 0 on rock/sand/snow/paths. (This deliberately avoids retro-fitting grass onto every existing material.)
The demo — Tutorial_14_GpuGrass
A character standing in a GPU-grass field on real terrain. Controls:
- WSAD — walk (leaves a trample trail)
- B — blast knockdown
- G — toggle a building CUT zone at the character
- F — force full density everywhere (handy on a world whose materials aren't authored yet)
- Mouse — orbit, Wheel — zoom, Esc — quit
Note: because density is opt-in, the demo shows no grass until you either set a terrain material's Grass Density > 0 in the editor or press F — there's an on-screen hint for this.
Implementation notes / caveats
- Vulkan-only, gated on VkMeshShaderSupported.
- Shaders (grass.task/.mesh/.frag + grass_common.hlsli) are HLSL compiled to SPIR-V by the vendored DXC at engine build time — a parallel path, not via EERegen, so no shader tooling needed at build.
- Drawn from RendererClass::opaque() (RT_DEFERRED) via VkDrawGrass; its own self-contained UBO + descriptor set (not a ShaderVK); reverse-Z + negative-height viewport matched to the deferred config.
- Grass is tagged PSM_TRANSLUCENT and excluded from SSAO (tblades otherwise make screen-space AO shimmer at distance).
In this repo:
https://github.com/DrewGilpin/EsenthelEngine