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

Zur Installation springen

Quellinformationen

Repository
Nebulavenus/forge-gpu
Letzte Quellaktivität
29. März 2026 um 00:35
Erkannte Sprache von SKILL.md
Englisch
Sterne
38
Forks
7

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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.
Auf GitHub ansehen