Authoring
Artist control
Paint density, height, dryness, and wind response or add local influence volumes.
Artist Control adds deterministic per-terrain authoring. A renderer can use one RGBA control map, any number of transformable influence volumes, or both. Dryness painting also keeps the dedicated dead-lawn TerrainLayer synchronized beneath the blades; its muted compact-thatch surface uses warm lifted midtones while remaining slightly darker, flatter, and lower contrast than the blades so it reads as their root bed without forming muddy holes. Other channels leave TerrainLayer paint unchanged. Transient stomp sources remain a separate system and never become authoring volumes.
control map contract
The control map covers the Terrain's local XZ footprint from (0, 0) to (1, 1). Terrain translation is included through the baked terrain origin. Sampling clamps at the map edge and is bilinear on both CPU placement jobs and the grass shader.
| channel | meaning | decoded range | neutral |
|---|---|---|---|
| R | placement density | 0 to 1 | 1 |
| G | blade height multiplier | 0 to 2 | 0.5, decoded as 1 |
| B | blend to the material's shaded dry palette and flat dead-lawn shape | 0 to 1 | 0 |
| A | wind-response multiplier | 0 to 2 | 0.5, decoded as 1 |
A missing map uses (1, 0.5, 0, 0.5), so existing renderers preserve density, height, colour, and wind. Final height and wind response are conservatively limited to 0 through 2 after map and volume blending.
Use Create & Paint Control Map on the Terrain Grass Renderer to create a project-local 512 x 512 linear RGBA32 asset and enter Terrain paint mode immediately. The texture is embedded in the map asset, readable, bilinear, and clamped. Keep the renderer selected, choose Density, Height, Dryness, or Wind in its compact Terrain Brush controls, then drag directly across the Terrain in the Scene view. Colour follows every brush dab; Density, Height, and Dryness publish accumulated dirty regions at a bounded live cadence so affected blade records patch while the stroke is still moving without turning each dab into a global rebuild. Dryness uses that same cadence to redistribute only existing grass coverage between the Living Grass and Dead Grass TerrainLayers. The No Grass layer and every unrelated terrain layer remain unchanged, and map plus terrain paint undo together.
The Scene brush uses a soft circular falloff and fills the space between mouse events for a continuous stroke:
- Ctrl/Cmd + scroll wheel changes brush size in terrain metres.
- Alt + scroll wheel changes brush strength.
- Shift + scroll wheel changes the selected channel's paint value.
- Hold Z + paint restores the selected channel to its neutral value. While Kiwi Grass paint mode owns the Scene view, this contextual shortcut takes priority over Unity's pivot/centre toggle; Z keeps its normal Unity behavior everywhere else.
- Esc or Stop Painting returns to the previously selected Unity tool.
Height and Wind values are displayed as their decoded 0x through 2x multipliers. Density and Dryness use direct 0 through 1 values. The Open 2D Map button remains a secondary precision view and uses the same soft brush behavior; ordinary authoring should happen directly on the Terrain.
Imported textures must meet the same data contract:
- Read/Write enabled.
- sRGB disabled so values remain linear data.
- Bilinear filtering.
- Clamp wrapping.
- Four usable channels. Mipmaps are not required because the shader samples mip zero.
Reimporting an external texture referenced by a control map advances both channel revisions and safely invalidates the full mapped terrain because the importer cannot know which channels changed. Imported textures remain data inputs rather than destructively editable source files; use New Editable Map for durable Scene painting. Painter strokes retain their precise channel and texel-region invalidation. Duplicated control-map assets receive a new stable ID while the existing source asset retains its identity.
Resolution is independent from terrain alphamap and heightmap resolution. The creator's 512 x 512 default is suitable for broad roads and field regions. Use a higher project-local resolution only when the required edge detail justifies its CPU copy and texture memory. Placement edits expand the painted region by the bilinear support texel and one candidate-cell footprint before mapping it to chunks.
influence volumes
Add Artist Control Volume from the Kiwi Grass component menu. Box, sphere, and vertical capsule shapes use the GameObject transform plus their local size. Blend Distance fades inward from the shape boundary; zero gives a hard boundary. Selected volumes draw their shape and local wind direction in the Scene view.
Volumes are sorted by ascending Priority, then by their serialized stable ID. They are applied sequentially in that deterministic order:
- Multiply scales the current Density, Height, or Wind Response by the authored value. Dryness has a zero neutral, so its multiply factor is
1 + authored dryness. - Additive adds
authored value - channel neutralat the blended weight. - Override interpolates the current value toward the authored value.
- Local Wind Direction blends toward the volume's transformed normalized direction. It uses shape weight and deterministic volume order; numeric blend mode does not alter direction blending.
Each terrain snapshot builds a compact list of intersecting volumes and a range of volume indices per grass chunk. Placement and shader evaluation visit only the range belonging to the blade's source chunk. Volumes do not enter the stomp registry, stomp texture, or recovery lifecycle.
updates and persistence
Density, Height, and Dryness alter baked blade records. Painting any of these channels copies only the changed control-map texels into the placement cache, preserves the existing volume index, marks only affected chunks, and runs the dirty-chunk placement path. Dryness additionally updates the corresponding terrain alphamap rectangle and conserves the summed grass coverage while blending between living and dead ground. If a patch job is already reading the cache, newer brush rectangles merge and apply immediately after it finishes instead of blocking input or writing into job-owned memory. Live artist-control jobs complete across editor frames instead of blocking the brush event. The existing chunk stays rendered during that work, then its GPU blade range is replaced when the patch is ready instead of despawning and respawning the chunk. The full texture and TerrainData Undo snapshot is captured once when paint mode starts, and map serialization is batched after a short idle period instead of running on mouse release. If the active data came from an assigned persistent bake, the bounded dirty writer patches those chunks and updates the saved placement fingerprint.
If bounded dirty persistence cannot update the assigned payload, the renderer warns, requests one full regeneration, and rewrites the persistent bake instead of treating the unsaved runtime patch as durable.
Wind Response and Local Wind Direction are evaluated in the shared deformation include used by Forward, Shadow, Depth, DepthNormals, and MotionVectors so geometry stays identical. Dryness shapes placement records and also uses separate Forward-only colour variants. At 1, deterministic per-blade variation reduces authored height to 34% through 52%, retains 80% through 98% of authored width, and lays blades over by 45 through 58 degrees. A continuous seeded direction field at roughly 3 m scale rotates the local matting organically across the dry patch while each blade adds at most 6 degrees of variation. Partial values use a smooth response from the byte-for-byte neutral natural shape. Because the resulting height, width, and growth normal live in the normal packed blade record, Forward, Shadow, Depth, DepthNormals, and MotionVectors share the same low dense silhouette without sampling the control map per vertex. A map-only dry zone keeps one fragment sample from the stable blade root for colour; a Dryness volume retains Forward vertex evaluation for its chunk-indexed colour blend. Both use pale beige straw, subtle tip variation, and brighter related roots while retaining root occlusion, scene lighting, shadows, wind, and motion.
Stable map identity, dimensions, serialized channel revisions, and intersecting placement-volume identity are part of deterministic placement fingerprints. Dryness participates in both placement and rendering revisions because it controls both shape and colour. Shader revisions and shader-volume identity remain part of rendering fingerprints. Duplicated active volumes receive a new stable ID. The packed 32-byte blade payload and persistent bake format 2 remain unchanged. Placement-algorithm fingerprint 5 causes older colour-only, wiry, and uniformly combed dry bakes to regenerate once without changing their file format.
Steady rendering reuses the control texture and bounded volume buffers. The normal draw path retains its 16-byte visible-chunk and 8-byte LOD3-batch records. Parallel chunk-identity buffers upload and fetch only when shader-control volumes intersect the terrain; Metal still receives valid bindings for every declared buffer. Dryness and wind enable separate local variants. A map-only Dryness zone performs one Forward-fragment map sample from the blade root for colour; its flat-lawn geometry and coherent direction are resolved once during placement into the baseline blade record used by every vertex pass. Dryness volumes retain Forward vertex evaluation for chunk-indexed colour blending. Alpha values 127-129 are treated as neutral wind-response byte quantization; an intentional painted response outside that range enables wind deformation. A map whose Dryness and Wind Response channels are entirely neutral, with no shader-control volumes intersecting the terrain, performs no artist-control texture, volume, side-buffer, or expanded-record work per grass vertex. Scene painting repaints for brush input and live grass changes without running a continuous idle repaint loop. No managed containers are created while their revisions remain unchanged. Editor channel-state scans use the editable RGBA32 texture's existing raw data without allocating a full managed pixel copy. Map copies and previews remain bounded by the selected map resolution; the built-in preview is downsampled to 128 x 128 per channel.
Still stuck?
Bring the renderer status with you.
Include the Kiwi Grass version, Unity and URP versions, operating system, graphics API, renderer status, Player log, and a minimal reproduction.