- Use glam's directx (WebGPU) projection module for both the camera
perspective and the shadow orthographic: NDC clip depth is [0,1] as
wgpu expects, instead of OpenGL's [-1,1] which clipped half the frustum
and broke depth-space consistency with the shadow map.
- Extend the shadow orthographic far plane to 2*r so the whole scene box
(and the shadow cast behind it, toward the camera) is covered.
- Switch the shadow comparison sampler to GreaterEqual so open sky is lit
and surfaces behind a blocker are shadowed (previous LessEqual inverted
the shadow, blackening the entire ground and making the cube float).
- Use the surface->light direction (+position_dir) for the directional
N*L term; the old negation darkened the cube top and lit the camera
faces, producing the inverted-pyramid appearance.
- Drop the now-redundant [0,1] depth remap in the main-pass shader.
With the shadow map cleared to 1.0 (farthest depth from light) and the
shadow pass writing smaller depths for surfaces closer to the light,
the fragment-to-light distance must be <= the stored surface depth for
lit pixels. GreaterEqual was inverted — everything appeared lit with no
shadows rendered.
Implement shadow mapping for directional lights:
- Scene::set_shadow_caster(Option<usize>) selects the shadow-casting light
by packed frame-array index (None disables; point lights rejected at render).
- Lights::get(index) resolves a packed index across the directional/point/spot lists.
- Renderer allocates a shadow depth map, comparison sampler, group-3 bind groups,
shadow uniform buffer and shadow pipeline; render_scene does a depth-only
shadow pass before the main pass; compute_shadow_light_view_proj builds an
orthographic light-space frustum from the scene radius.
- standard_shader: shadow_light_index/light_view_proj/shadow_params uniforms,
@group(3) depth map + comparison sampler, 3x3 PCF compute_shadow().
- shadow_shader: path/vertex shader with attribute layout matching the shared
vertex buffer (only position consumed).
- shadow_test example: directional shadow caster casts a PCF-softened shadow
onto a ground slab; documented in examples README.
Le test du cône comparait l (surface->lumière) à dir_angle.xyz (lumière->scène),
deux directions opposées, donc cone ≈ -1 et facteur spot = 0 : les spots
n'éclairaient rien (cube noir). On teste désormais -l (lumière->point), aligné
avec l'axe du cône. Ajout d'un test Rust qui verrouille l'invariant (alignement
+1 sur l'axe). Build/test/WGSL/fmt OK.
Implémente le plan Étape 10 (Phase 4.1 Textures), décisions D1-D4 actées :
- 10.1 : nouveau type resources::Texture (device+view+sampler), format
Rgba8UnormSrgb, sampler linear/repeat, dep 'image' (png/jpeg). Constructeurs
from_rgba8 / from_bytes / from_file / white_placeholder.
- 10.2 : create_texture_bind_group_layout (groupe 2 : sampler+texture, fragment).
build_pipeline pose désormais 3 layouts [frame, object, texture] — « un seul
layout pour tous » (D1). PipelineCache détient le layout + le placeholder blanc.
- 10.3 : shader standard — UV transmis au fragment (location 2), groupe @2
texture_sampler + diffuse_texture, échantillonnage inconditionnel
base = texel * couleur(vertex) (D2) : sans texture (placeholder blanc) pas
de régression en lit comme en unlit.
- 10.4 : Material gagne texture: Option<Arc<Texture>> + texture_bind_group,
construit dans le constructeur via le cache (layout partagé + placeholder).
- 10.5 : draw_entity bind @group(2) ; Scene : add_texture / get_texture /
add_material_texture ; init_gpu accepte la Queue pour bâtir le placeholder.
- exemple cube : géométrie avec UV [0,1]² par face + texture damier procédurale.
Validation : fmt, check 0 warning, tests verts (3 + doc), doc sans missing_docs,
cube/simple/manual lancés sans erreur backend.
Étape 2 du plan 3D+Phong : nouveau shader unifié, non encore branché à un
pipeline (Étape 3 : infra uniforms).
- shaders/standard_shader.wgsl : contrat vertex complet (position/normal/uv/color,
56 octets, corrige la défaut latente du basic) ; 2 bind groups formative frame
(view/proj/cam_pos/light_dir/light_color/options) + object (model) ; éclairage
hemisphérique ambient + diffuse directionnel; mode unlit (options.x) pour que la
2D plate soit un cas partticulier de la 3D.
- utils/conf.rs : constantes STANDARD_SHADER_PATH + STANDARD_SHADER (include_str!).
- tests/wgsl_validate.rs : validation hors-ligne naga (via wgpu::naga, aucune
nouvelle dépendance) tant que le shader n'est pas compilé par un pipeline.
- shaders/README.md : documente le contrat standard et le statut du basic.
- Erreur WGSL corrigée en validation: cast mat4x4->mat3x3 non supporte, remplacé
par construction explicite de la sous-matrice 3x3.
- Validation: cargo test (naga OK), check workspace+examples 0 warning, doc OK, fmt OK.