بنقرة واحدة
forge-cascaded-shadow-maps
Add cascaded shadow maps with PCF soft shadows to an SDL GPU project
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Add cascaded shadow maps with PCF soft shadows to an SDL GPU project
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Add PBR texture loading with separate roughness/metallic support to an SDL GPU project using forge_scene.h
Add Cook-Torrance PBR shading with GGX, Schlick-GGX, and Schlick Fresnel to an SDL GPU project alongside forge_scene.h
Add instanced grass rendering with segmented blades, wind animation, LOD density rings, and terrain LOD with geomorphing to an SDL GPU project
Add procedural noise texture generation to the asset pipeline — C tool, Python plugin, web UI with live preview
Add an asset pipeline lesson — hybrid Python + C track for asset processing, procedural geometry, and web frontend
Add an audio lesson — sound playback, mixing, spatial audio, DSP effects, with SDL GPU scenes and forge UI
| name | forge-cascaded-shadow-maps |
| description | Add cascaded shadow maps with PCF soft shadows to an SDL GPU project |
Add directional-light cascaded shadow maps (CSM) with 3x3 PCF soft shadows to an SDL3 GPU application. Based on Lesson 15.
SDL_CreateGPUTexture — shadow map textures (D32_FLOAT, DEPTH_STENCIL_TARGET | SAMPLER)SDL_CreateGPUSampler — NEAREST filter, CLAMP_TO_EDGE for shadow map samplingSDL_CreateGPUGraphicsPipeline — shadow pipeline (depth-only, front-face cull, depth bias)SDL_BeginGPURenderPass / SDL_EndGPURenderPass — one pass per cascade (depth only)SDL_BindGPUFragmentSamplers — bind shadow maps + sampler for scene passSDL_PushGPUVertexUniformData / SDL_PushGPUFragmentUniformData — per-draw uniformsSDL_AppInit)DEPTH_STENCIL_TARGET | SAMPLER usage flags/* No color targets — depth only */
pipe.target_info.num_color_targets = 0;
pipe.target_info.has_depth_stencil_target = true;
pipe.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT;
/* Front-face culling reduces peter-panning */
pipe.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_FRONT;
/* Depth bias reduces shadow acne */
pipe.rasterizer_state.depth_bias_constant_factor = 2;
pipe.rasterizer_state.depth_bias_slope_factor = 2.0f;
SDL_GPUTextureCreateInfo info;
SDL_zero(info);
info.type = SDL_GPU_TEXTURETYPE_2D;
info.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT;
info.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET |
SDL_GPU_TEXTUREUSAGE_SAMPLER; /* key: both flags */
info.width = 2048;
info.height = 2048;
info.layer_count_or_depth = 1;
info.num_levels = 1;
SDL_GPUSamplerCreateInfo smp;
SDL_zero(smp);
smp.min_filter = SDL_GPU_FILTER_NEAREST;
smp.mag_filter = SDL_GPU_FILTER_NEAREST;
smp.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
smp.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
/* Lengyel's logarithmic-linear blend */
for (int i = 0; i < NUM_CASCADES; i++) {
float p = (float)(i + 1) / (float)NUM_CASCADES;
float log_split = near * SDL_powf(far / near, p);
float lin_split = near + (far - near) * p;
splits[i] = lambda * log_split + (1.0f - lambda) * lin_split;
}
mat4 light_view = mat4_look_at(light_pos, center, up);
/* Transform corners to light space → compute AABB */
mat4 light_proj = mat4_orthographic(min_x, max_x, min_y, max_y,
-max_z, -min_z);
mat4 light_vp = mat4_multiply(light_proj, light_view);
for (int ci = 0; ci < NUM_CASCADES; ci++) {
SDL_GPUDepthStencilTargetInfo depth;
SDL_zero(depth);
depth.texture = shadow_maps[ci];
depth.load_op = SDL_GPU_LOADOP_CLEAR;
depth.store_op = SDL_GPU_STOREOP_STORE; /* MUST store */
depth.clear_depth = 1.0f;
SDL_GPURenderPass *pass = SDL_BeginGPURenderPass(cmd, NULL, 0, &depth);
SDL_BindGPUGraphicsPipeline(pass, shadow_pipeline);
/* Draw all shadow casters with light_vp[ci] * model */
/* ... */
SDL_EndGPURenderPass(pass);
}
float sample_shadow_pcf(Texture2D shadow_map, SamplerState smp,
float2 shadow_uv, float current_depth) {
float shadow = 0.0;
[unroll]
for (int y = -1; y <= 1; y++) {
[unroll]
for (int x = -1; x <= 1; x++) {
float2 offset = float2(x, y) * texel_size;
float map_depth = shadow_map.Sample(smp, shadow_uv + offset).r;
shadow += (map_depth >= current_depth - bias) ? 1.0 : 0.0;
}
}
return shadow / 9.0;
}
shadow_uv.y = 1.0 - shadow_uv.yVertex uniform slot 0 → register(b0, space1)
Vertex uniform slot 1 → register(b1, space1)
Fragment sampler slot N → register(tN, space2) + register(sN, space2)
Fragment uniform slot 0 → register(b0, space3)