Skip to main content

forge-environment-mapping

Add cube map environment mapping with a skybox and reflective surfaces. Use when someone needs a 360-degree background, reflection mapping, or cube map textures 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-environment-mapping
description
Add cube map environment mapping with a skybox and reflective surfaces. Use when someone needs a 360-degree background, reflection mapping, or cube map textures in SDL3 GPU.
# Environment Mapping — SDL3 GPU Skill Add a cube map skybox and environment reflections to a 3D scene. ## When to use this skill - Rendering a 360-degree background (space, sky, indoor environment) - Adding reflections to metallic or glossy surfaces - Working with `SDL_GPU_TEXTURETYPE_CUBE` textures - Combining multiple graphics pipelines in one render pass ## Cube map texture creation ```c /* Create a cube map texture with 6 faces. */ SDL_GPUTextureCreateInfo tex_info; SDL_zero(tex_info); tex_info.type = SDL_GPU_TEXTURETYPE_CUBE; tex_info.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB; tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER; tex_info.width = face_size; tex_info.height = face_size; tex_info.layer_count_or_depth = 6; /* MUST be 6 for cube maps */ tex_info.num_levels = 1; SDL_GPUTexture *cubemap = SDL_CreateGPUTexture(device, &tex_info); /* Upload each face as a separate layer (0=+X, 1=-X, 2=+Y, 3=-Y, 4=+Z, 5=-Z). */ for (int face = 0; face < 6; face++) { /* Load face image, convert to ABGR8888, map transfer buffer... */ SDL_GPUTextureRegion dst; SDL_zero(dst); dst.texture = cubemap; dst.layer = (Uint32)face; /* Face index = layer index */ dst.w = face_size; dst.h = face_size; dst.d = 1; SDL_UploadToGPUTexture(copy_pass, &src, &dst, false); } ``` ## Skybox rendering pattern ### Vertex shader — depth = 1.0 ```hlsl cbuffer VertUniforms : register(b0, space1) { column_major float4x4 vp_no_translation; }; struct VSOutput { float4 clip_pos : SV_Position; float3 direction : TEXCOORD0; }; VSOutput main(VSInput input) { VSOutput output; output.direction = input.position; float4 pos = mul(vp_no_translation, float4(input.position, 1.0)); output.clip_pos = pos.xyww; /* z = w → depth = 1.0 after divide */ return output; } ``` ### Fragment shader — sample cube map ```hlsl TextureCube skybox_tex : register(t0, space2); SamplerState smp : register(s0, space2); float4 main(PSInput input) : SV_Target { return skybox_tex.Sample(smp, input.direction); } ``` ### Pipeline settings ```c /* Cull FRONT faces — we're inside the cube. */ pipe_info.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_FRONT; /* Depth test LESS_OR_EQUAL to pass at depth=1.0. * Depth write DISABLED — skybox should never occlude anything. */ pipe_info.depth_stencil_state.enable_depth_test = true; pipe_info.depth_stencil_state.enable_depth_write = false; pipe_info.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL; ``` ### Rotation-only view matrix ```c /* Strip translation so the skybox always surrounds the camera. */ mat4 view_rot = view; view_rot.m[12] = 0.0f; view_rot.m[13] = 0.0f; view_rot.m[14] = 0.0f; mat4 vp_sky = mat4_multiply(proj, view_rot); ``` ## Reflection mapping pattern ### Fragment shader with reflections ```hlsl TextureCube env_tex : register(t1, space2); /* Compute reflection direction */ float3 V = normalize(eye_pos.xyz - world_pos); float3 R = reflect(-V, N); float3 env_color = env_tex.Sample(env_smp, R).rgb; /* Blend diffuse with environment reflection */ float3 blended = lerp(surface_color.rgb, env_color, reflectivity); ``` ## Render order 1. Clear depth to 1.0 2. Draw skybox (depth write off, passes at depth=1.0) 3. Draw objects (depth write on, depth < 1.0 always passes) ## Common mistakes 1. **Forgetting `layer_count_or_depth = 6`** — cube maps require exactly 6 layers. Without this, texture creation fails silently or renders black. 2. **Wrong face order** — `SDL_GPUCubeMapFace` enum order is +X, -X, +Y, -Y, +Z, -Z. Mixing up faces produces seams or incorrect reflections. 3. **Depth write enabled on skybox** — the skybox writes depth=1.0 everywhere, occluding all subsequent geometry. Always disable depth write for the skybox. 4. **Using full view matrix for skybox** — includes camera translation, causing visible parallax when moving. Strip translation columns (m[12], m[13], m[14]). 5. **Wrong cull mode for skybox** — the camera is inside the cube, so front faces point inward (toward the camera). Cull front faces, not back faces. 6. **Not negating V in reflect()** — `reflect()` expects the incident vector pointing toward the surface. The view direction V points away from the surface, so pass `-V`. ## File layout ```text shaders/ ├── skybox.vert.hlsl # Unit cube → clip space with depth=1.0 ├── skybox.frag.hlsl # Sample TextureCube ├── object.vert.hlsl # Standard MVP + model (same as lighting) └── object.frag.hlsl # Blinn-Phong + reflect() + cube map sample ``` ## References - [Lesson 14 — Environment Mapping](../../../lessons/gpu/14-environment-mapping/) - [Lesson 10 — Basic Lighting](../../../lessons/gpu/10-basic-lighting/) (Blinn-Phong) - [Math Lesson 01 — Vectors](../../../lessons/math/01-vectors/) (dot product, reflection)
Auf GitHub ansehen