Skip to main content

forge-edge-detection

Add Sobel edge detection on G-buffer data (depth + normals via MRT), stencil-based X-ray vision with depth_fail_op, and Fresnel ghost silhouettes with additive blending to an SDL GPU project.

설치로 이동

소스 정보

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

설치 방법

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

소스 파일 검토

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

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
forge-edge-detection
description
Add Sobel edge detection on G-buffer data (depth + normals via MRT), stencil-based X-ray vision with depth_fail_op, and Fresnel ghost silhouettes with additive blending to an SDL GPU project.
triggers
["edge detection","sobel filter","x-ray vision","ghost silhouette","post-process outline","depth_fail_op","fresnel outline"]
# Edge Detection Add post-process edge detection, stencil X-ray vision, and Fresnel ghost silhouettes to an SDL GPU project. Uses G-buffer MRT output (depth + normals) for Sobel edge detection, `depth_fail_op` for occluded-object marking, and additive blending for translucent ghost rendering. Based on [GPU Lesson 36](../../../lessons/gpu/36-edge-detection/). ## When to use - You want post-process outlines from depth/normal discontinuities - You need X-ray vision to reveal occluded objects behind walls - You want ghostly translucent silhouettes for hidden geometry - You need an alternative to L34's stencil-expansion outlines ## Pipeline overview (6 pipelines) 1. **Shadow pipeline** — Depth-only pass for shadow mapping 2. **Scene pipeline (MRT)** — Renders lit scene to two color targets: color (RT0) and view-space normals (RT1), plus depth-stencil 3. **Grid pipeline (MRT)** — Same MRT layout for the floor grid 4. **Edge composite pipeline** — Full-screen quad, samples depth + normal textures, runs Sobel filter, composites edges onto the scene 5. **X-ray mark pipeline** — Draws occluded objects with `depth_fail_op = INCREMENT_AND_WRAP`, `color_write_mask = 0`, writing only to stencil where fragments fail the depth test 6. **Ghost pipeline** — Draws the same objects again with stencil test `NOT_EQUAL` ref=0 and additive blending for Fresnel ghost silhouettes ## G-buffer setup (MRT) The scene pass renders to two color targets simultaneously: ```c /* RT0: scene color (RGBA8) */ /* RT1: view-space normals (RGBA16_FLOAT or RGBA8_SNORM) */ SDL_GPUColorTargetInfo color_targets[2] = { { .texture = scene_color_tex, .load_op = SDL_GPU_LOADOP_CLEAR }, { .texture = normal_tex, .load_op = SDL_GPU_LOADOP_CLEAR }, }; ``` The fragment shader outputs to both targets: ```hlsl struct PSOutput { float4 color : SV_Target0; float4 normal : SV_Target1; }; ``` Pipeline must declare two color target descriptions to match. ## Sobel edge detection Sample depth and normal textures in a 3x3 neighborhood. Apply Sobel operators (horizontal Gx and vertical Gy kernels) separately to depth and to each normal component. Combine magnitudes: ```hlsl /* Sobel kernels */ /* Gx = [-1 0 1; -2 0 2; -1 0 1] */ /* Gy = [-1 -2 -1; 0 0 0; 1 2 1] */ float depth_edge = sqrt(gx_depth * gx_depth + gy_depth * gy_depth); float normal_edge = sqrt(gx_nx*gx_nx + gy_nx*gy_nx + gx_ny*gx_ny + gy_ny*gy_ny + gx_nz*gx_nz + gy_nz*gy_nz); float edge = saturate(depth_edge * depth_scale + normal_edge * normal_scale); ``` Threshold and composite: `final_color = lerp(scene_color, edge_color, edge)`. ## X-ray mark technique (depth_fail_op) The key insight: `depth_fail_op` fires when a fragment is behind existing geometry. By drawing the target object with this operation, we mark exactly the pixels where it is occluded. ```c /* X-ray mark pipeline stencil state */ SDL_GPUStencilOpState xray_stencil = { .fail_op = SDL_GPU_STENCILOP_KEEP, .pass_op = SDL_GPU_STENCILOP_KEEP, /* visible parts: no mark */ .depth_fail_op = SDL_GPU_STENCILOP_INCREMENT_AND_WRAP, /* occluded: mark */ .compare_op = SDL_GPU_COMPAREOP_ALWAYS, }; ``` Color write mask = 0 and depth write = false. This pass is invisible — it only writes stencil values where the object is hidden behind other geometry. ## Ghost silhouette technique After the X-ray mark pass, draw the object again with: - Stencil test: `compare_op = NOT_EQUAL`, reference = 0 (draw only where marked) - Additive blending: `src_color_blendfactor = ONE`, `dst = ONE` - Fresnel-based opacity: brighter at edges where `dot(N, V)` is low ```hlsl /* Fresnel ghost effect */ float fresnel = 1.0 - saturate(dot(normal, view_dir)); fresnel = pow(fresnel, fresnel_power); return float4(ghost_color * fresnel * intensity, 0.0); ``` The additive blend makes the ghost glow through geometry without needing alpha sorting. ## Clearing stencil Clear stencil alongside depth at the start of the render pass: ```c SDL_GPUDepthStencilTargetInfo ds_target = { .texture = depth_stencil_texture, .load_op = SDL_GPU_LOADOP_CLEAR, .store_op = SDL_GPU_STOREOP_STORE, .clear_depth = 1.0f, .clear_stencil = 0, .stencil_load_op = SDL_GPU_LOADOP_CLEAR, .stencil_store_op = SDL_GPU_STOREOP_STORE, }; ``` ## Key patterns | Pattern | Value | |---------|-------| | `depth_fail_op` | `SDL_GPU_STENCILOP_INCREMENT_AND_WRAP` | | X-ray mark `color_write_mask` | `0` (invisible pass) | | X-ray mark `depth_write` | `false` | | Ghost stencil `compare_op` | `SDL_GPU_COMPAREOP_NOT_EQUAL` | | Ghost stencil `reference` | `0` | | Ghost blend | Additive (`SRC=ONE`, `DST=ONE`) | | MRT count | 2 (color + normals) | ## Key API calls - `SDL_BeginGPURenderPass(cmd, color_targets, 2, &ds)` — MRT with 2 color targets - `SDL_SetGPUStencilReference(pass, ref)` — set stencil compare reference value - `SDL_DrawGPUPrimitives(pass, 3, 1, 0, 0)` — fullscreen triangle (no vertex buffer) - `SDL_GPU_STENCILOP_INCREMENT_AND_WRAP` — depth_fail_op for X-ray marking - `SDL_GPU_COMPAREOP_NOT_EQUAL` — stencil test for ghost pass (ref=0, pass where >0) - `SDL_GPU_BLENDFACTOR_ONE` (src + dst) — additive blending for ghost glow - `SDL_GPUTextureSupportsFormat` — negotiate D24S8 with SAMPLER usage ## Common mistakes - **Forgetting MRT pipeline color target count** — The pipeline must declare the same number of color target descriptions as render pass color targets. Mismatched counts cause validation errors or undefined behavior. - **Wrong depth_fail_op direction** — `depth_fail_op` fires when the fragment is behind existing depth. Make sure the scene depth is already established before the X-ray mark pass. - **Not disabling depth writes for X-ray mark** — If the mark pass writes depth, it corrupts the depth buffer and prevents the ghost pass from rendering correctly. - **Missing stencil clear** — Stale stencil values from the previous frame cause ghost artifacts everywhere. Always clear stencil at pass start. - **Sobel on linear depth vs hyperbolic depth** — Raw depth buffer values are hyperbolic (non-linear). For better edge detection, linearize depth first or adjust the depth scale threshold. ## Cross-references - [GPU Lesson 36 — Edge Detection](../../../lessons/gpu/36-edge-detection/) for the full walkthrough - [GPU Lesson 34 — Stencil Testing](../../../lessons/gpu/34-stencil-testing/) for stencil buffer fundamentals and stencil-expansion outlines - [GPU Lesson 27 — SSAO](../../../lessons/gpu/27-ssao/) for G-buffer and view-space normal techniques - [GPU Lesson 15 — Cascaded Shadow Maps](../../../lessons/gpu/15-cascaded-shadow-maps/) for depth-only render passes - [GPU Lesson 16 — Blending](../../../lessons/gpu/16-blending/) for blend state configuration (additive blending)
GitHub에서 보기