Skip to main content

forge-depth-and-3d

Set up depth buffer, 3D MVP pipeline, back-face culling, and window resize handling. Use when someone needs to render 3D geometry with correct depth ordering, perspective projection, or a view camera in SDL3 GPU.

Zur Installation springen

Quellinformationen

Repository
Nebulavenus/forge-gpu
Letzte Quellaktivität
1. März 2026 um 21:31
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-depth-and-3d
description
Set up depth buffer, 3D MVP pipeline, back-face culling, and window resize handling. Use when someone needs to render 3D geometry with correct depth ordering, perspective projection, or a view camera in SDL3 GPU.
# Depth Buffer & 3D Transforms — MVP Pipeline, Depth Testing, and Culling This skill teaches how to render 3D geometry with the full Model-View-Projection pipeline, depth testing, back-face culling, and window resize handling. It builds on the `uniforms-and-motion` skill (push uniforms) and `first-triangle` skill (vertex buffers, pipelines). ## When to use - Rendering 3D geometry (cubes, meshes, scenes) - Setting up perspective projection with a camera - Enabling depth testing so closer surfaces draw over farther ones - Adding back-face culling for closed meshes - Handling window resize for depth textures - Transitioning from 2D (float2) to 3D (float3) vertex positions ## Key API calls (ordered) 1. `SDL_CreateGPUTexture` — create depth texture with `DEPTH_STENCIL_TARGET` usage 2. `SDL_CreateGPUGraphicsPipeline` — with depth stencil state and back-face culling 3. `mat4_look_at` / `mat4_perspective` / `mat4_multiply` — build MVP matrix per frame 4. `SDL_PushGPUVertexUniformData` — push MVP matrix to vertex shader 5. `SDL_BeginGPURenderPass` — with both color target AND depth target 6. `SDL_DrawGPUIndexedPrimitives` — draw 3D geometry ## Code template ### Depth texture creation ```c static SDL_GPUTexture *create_depth_texture(SDL_GPUDevice *device, Uint32 w, Uint32 h) { SDL_GPUTextureCreateInfo info; SDL_zero(info); info.type = SDL_GPU_TEXTURETYPE_2D; info.format = SDL_GPU_TEXTUREFORMAT_D16_UNORM; info.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; info.width = w; info.height = h; info.layer_count_or_depth = 1; info.num_levels = 1; SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &info); if (!texture) { SDL_Log("Failed to create depth texture: %s", SDL_GetError()); } return texture; } ``` ### Pipeline setup with depth and culling ```c SDL_GPUGraphicsPipelineCreateInfo pipeline_info; SDL_zero(pipeline_info); /* ... vertex input, shaders, etc. ... */ /* Back-face culling — skip faces pointing away from camera */ pipeline_info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_BACK; pipeline_info.rasterizer_state.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE; /* Depth testing — closer fragments win */ pipeline_info.depth_stencil_state.enable_depth_test = true; pipeline_info.depth_stencil_state.enable_depth_write = true; pipeline_info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; /* Color target */ SDL_GPUColorTargetDescription color_desc; SDL_zero(color_desc); color_desc.format = SDL_GetGPUSwapchainTextureFormat(device, window); pipeline_info.target_info.color_target_descriptions = &color_desc; pipeline_info.target_info.num_color_targets = 1; /* Depth target — MUST declare format in pipeline */ pipeline_info.target_info.has_depth_stencil_target = true; pipeline_info.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM; ``` ### MVP matrix computation ```c #include "math/forge_math.h" /* Model: position and orient the object */ mat4 model = mat4_multiply( mat4_translate(vec3_create(0.0f, 0.0f, 0.0f)), mat4_multiply(mat4_rotate_y(angle_y), mat4_rotate_x(angle_x)) ); /* View: position and orient the camera */ mat4 view = mat4_look_at( vec3_create(0.0f, 1.5f, 3.0f), /* eye position */ vec3_create(0.0f, 0.0f, 0.0f), /* look-at target */ vec3_create(0.0f, 1.0f, 0.0f) /* world up */ ); /* Projection: perspective with correct aspect ratio */ float fov = 60.0f * FORGE_DEG2RAD; float aspect = (float)window_w / (float)window_h; mat4 proj = mat4_perspective(fov, aspect, 0.1f, 100.0f); /* Compose: MVP = Projection * View * Model */ mat4 mvp = mat4_multiply(mat4_multiply(proj, view), model); ``` ### Render pass with depth target ```c SDL_GPUColorTargetInfo color_target; SDL_zero(color_target); color_target.texture = swapchain; color_target.load_op = SDL_GPU_LOADOP_CLEAR; color_target.store_op = SDL_GPU_STOREOP_STORE; color_target.clear_color = (SDL_FColor){ 0.02f, 0.02f, 0.04f, 1.0f }; SDL_GPUDepthStencilTargetInfo depth_target; SDL_zero(depth_target); depth_target.texture = depth_texture; depth_target.load_op = SDL_GPU_LOADOP_CLEAR; depth_target.store_op = SDL_GPU_STOREOP_DONT_CARE; depth_target.stencil_load_op = SDL_GPU_LOADOP_DONT_CARE; depth_target.stencil_store_op = SDL_GPU_STOREOP_DONT_CARE; depth_target.clear_depth = 1.0f; /* far plane */ SDL_GPURenderPass *pass = SDL_BeginGPURenderPass( cmd, &color_target, 1, &depth_target); ``` ### Window resize handling ```c /* Check each frame — recreate depth texture if window size changed */ int w, h; SDL_GetWindowSizeInPixels(window, &w, &h); if ((Uint32)w != depth_width || (Uint32)h != depth_height) { SDL_ReleaseGPUTexture(device, depth_texture); depth_texture = create_depth_texture(device, (Uint32)w, (Uint32)h); depth_width = (Uint32)w; depth_height = (Uint32)h; } ``` ### Vertex shader (HLSL) ```hlsl cbuffer Uniforms : register(b0, space1) { column_major float4x4 mvp; }; struct VSInput { float3 position : TEXCOORD0; float3 color : TEXCOORD1; }; struct VSOutput { float4 position : SV_Position; float4 color : TEXCOORD0; }; VSOutput main(VSInput input) { VSOutput output; output.position = mul(mvp, float4(input.position, 1.0)); output.color = float4(input.color, 1.0); return output; } ``` ## Vertex format for 3D ```c typedef struct Vertex { vec3 position; /* 3D model-space position (FLOAT3) */ vec3 color; /* RGB per-vertex color (FLOAT3) */ } Vertex; /* Vertex attributes */ attrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3; /* position */ attrs[0].offset = offsetof(Vertex, position); attrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3; /* color */ attrs[1].offset = offsetof(Vertex, color); ``` ## Uniform struct ```c typedef struct Uniforms { mat4 mvp; /* 64 bytes — naturally 16-byte aligned */ } Uniforms; ``` A single `mat4` is exactly 64 bytes and naturally 16-byte aligned, so no padding is needed (unlike the `time + aspect + pad` structs from earlier lessons). ## HLSL column-major compatibility forge_math.h stores matrices column-major. HLSL defaults to `column_major` for `float4x4`. Use `mul(mvp, float4(pos, 1.0))` — no transpose needed. If you accidentally see an inside-out or mirrored cube, check: 1. Matrix storage order matches shader declaration 2. `mul(matrix, vector)` not `mul(vector, matrix)` 3. Winding order matches `front_face` setting ## Depth format choices | Format | Bits | Precision | Use case | |--------|------|-----------|----------| | `D16_UNORM` | 16 | Low | Simple scenes, universally supported | | `D24_UNORM` | 24 | Medium | Most 3D games | | `D32_FLOAT` | 32 | High | Large worlds, reverse-Z | For learning and simple scenes, `D16_UNORM` is sufficient and universally supported. ## Common mistakes | Mistake | Fix | |---------|-----| | Cube looks inside-out | Enable depth testing (`enable_depth_test = true`) | | No depth target in pipeline | Set `has_depth_stencil_target = true` and `depth_stencil_format` | | Crash on window resize | Recreate depth texture when window size changes | | Cube appears mirrored | Check `mul(mvp, vertex)` order matches column-major storage | | Back faces visible | Set `cull_mode = CULLMODE_BACK` with correct `front_face` | | Depth buffer not clearing | Set `load_op = LOADOP_CLEAR` and `clear_depth = 1.0f` | | Missing perspective | Use `mat4_perspective` not `mat4_orthographic` | ## Cleanup ```c SDL_ReleaseGPUTexture(device, depth_texture); SDL_ReleaseGPUBuffer(device, index_buffer); SDL_ReleaseGPUBuffer(device, vertex_buffer); SDL_ReleaseGPUGraphicsPipeline(device, pipeline); ``` ## Reference - [GPU Lesson 06 — Depth Buffer & 3D Transforms](../../../lessons/gpu/06-depth-and-3d/) — full implementation - [Math Lesson 05 — Matrices](../../../lessons/math/05-matrices/) — transform theory - [uniforms-and-motion skill](../forge-uniforms-and-motion/SKILL.md) — push uniforms - [first-triangle skill](../forge-first-triangle/SKILL.md) — vertex buffers, pipelines - `mat4_perspective()`, `mat4_look_at()` in `common/math/forge_math.h`
Auf GitHub ansehen