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

설치로 이동

소스 정보

저장소
Nebulavenus/forge-gpu
최근 소스 활동
2026년 3월 29일 00:35
감지된 SKILL.md 언어
영어
스타
38
포크
7

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
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.
GitHub에서 보기