Skip to main content

forge-grass-rendering

Add instanced grass rendering with segmented blades, wind animation, LOD density rings, and terrain LOD with geomorphing to an SDL GPU project

Aller à l'installation

Informations de source

Dépôt
Nebulavenus/forge-gpu
Dernière activité de la source
29 mars 2026 à 00:35
Langue détectée de SKILL.md
anglais
Étoiles
38
Forks
7

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
forge-grass-rendering
description
Add instanced grass rendering with segmented blades, wind animation, LOD density rings, and terrain LOD with geomorphing to an SDL GPU project
Add grass rendering to an SDL GPU project using `forge_scene.h`. Implements instanced segmented grass blades with wind animation, density-based LOD rings, and tile-based terrain LOD with vertex shader geomorphing. ## When to use - Adding vegetation to a 3D scene - Implementing instanced rendering with per-instance attributes - Adding LOD systems for both terrain and foliage - Split-screen or multi-viewport rendering ## Key API calls - `forge_shapes_plane()` — generate tile meshes at different resolutions - `forge_scene_upload_buffer_deferred()` — per-frame instance buffer upload - `forge_scene_create_shader()` — create custom shaders alongside forge_scene - `SDL_SetGPUViewport()` / `SDL_SetGPUScissor()` — split-screen viewports - `SDL_DrawGPUIndexedPrimitives()` — instanced draw with per-instance buffer - `forge_noise_fbm2d()` — procedural heightmap generation - `forge_hash_wang()` / `forge_hash_to_float()` — deterministic placement variation ## Correct order 1. Generate procedural heightmap via fBm noise 2. Upload heightmap as R32_FLOAT GPU texture 3. Create tile meshes at multiple LOD resolutions (both triangle and line IBs) 4. Create grass blade meshes at multiple segment counts 5. Create pipelines: terrain fill/line/shadow + grass fill/line/shadow 6. Per frame: a. Select terrain tile LODs based on camera distance b. Place grass instances with distance/frustum/slope culling c. Upload instance buffers via deferred upload d. Shadow pass: draw terrain tiles + near grass into shadow map e. Main pass: set left viewport → draw terrain + grass filled; set right viewport → draw terrain + grass wireframe f. Reset viewport for UI ## Grass blade geometry Each blade is a vertical segmented strip with `2*(N+1)` vertices and `2*N` triangles. The `height_t` attribute (0 at base, 1 at tip) controls wind weighting and tapering. ```c for (int i = 0; i <= segments; i++) { float t = (float)i / (float)segments; float half_w = 0.5f * (1.0f - t * GRASS_BLADE_TIP_TAPER); verts[2*i+0] = (GrassVertex){ {-half_w, t, 0}, t }; verts[2*i+1] = (GrassVertex){ { half_w, t, 0}, t }; } ``` ## Per-instance data ```c typedef struct { float position[3]; /* world-space base position */ float rotation; /* Y-axis rotation (radians) */ float scale[2]; /* width, height */ float color[3]; /* RGB tint */ float _pad; /* alignment to 40 bytes */ } GrassInstance; ``` ## Wind animation (vertex shader) ```hlsl float wind_weight = height_t * height_t; /* quadratic: tip bends most */ float phase = time * wind_speed + world.x * 0.7 + world.z * 0.3; float wind_offset = sin(phase) * wind_strength * wind_weight; ``` ## Terrain geomorphing (vertex shader) ```hlsl float2 snapped_uv = round(global_uv / coarse_cell_size) * coarse_cell_size; float2 morphed_uv = lerp(global_uv, snapped_uv, morph_factor); float morphed_x = lerp(world_x, snapped_x, morph_factor); float h = height_tex.SampleLevel(smp, morphed_uv, 0).r; ``` ## Common mistakes - **Forgetting half-aspect projection** — split-screen viewports are half the screen width, so the projection matrix must use `half_w / height` aspect - **Using TRIANGLELIST pipeline for wireframe** — the right viewport needs a LINELIST pipeline with a separate line index buffer (each triangle edge as two indices) - **Grass shadow without wind** — the shadow vertex shader must apply the same wind animation as the main shader, or shadows will not match blade positions - **Missing morph factor** — without geomorphing, terrain tile LOD switches cause visible popping; morph_factor must ramp 0→1 in the last 20% of each LOD distance band - **Forgetting to reset viewport for UI** — after right-viewport draws, reset viewport and scissor to full screen before forge_scene_end_main_pass ## Reference See [Lesson 50 — Grass Rendering](../../../lessons/gpu/50-grass-rendering/) for the full implementation.
Voir sur GitHub