refactor(resources): activate diffuse textures on all render paths (Étape 10)
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.
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
//! # Standard Shader Module (Phong)
|
||||
//! # Standard Shader Module (Phong + diffuse texture)
|
||||
//!
|
||||
//! Default lit shading pipeline for WSG. Implements an ambient + directional-diffuse
|
||||
//! (Phong-style) lighting model with an explicit "unlit" mode so that flat 2D rendering
|
||||
//! is a special case of the 3D path (see DRAFT décision actée : « 2D ⊂ 3D »).
|
||||
//! Since Étape 10 (DRAFT D2) the fragment can also sample a diffuse texture whose texel
|
||||
//! modulates the vertex color (`texel.rgb * in.color.rgb`).
|
||||
//!
|
||||
//! ## Uniform Contract
|
||||
//! Two bind groups, shared by every material (one single pipeline layout — voir Étape 3) :
|
||||
//! Three bind groups, shared by every material (one single pipeline layout — voir Étape 3) :
|
||||
//! - `@group(0) @binding(0)` : `FrameUniforms` (per-frame, camera + lights) [192 bytes]
|
||||
//! - `@group(1) @binding(0)` : `ObjectUniform` (per-entity model matrix) [64 bytes]
|
||||
//! - `@group(2) @binding(0)` : `texture_sampler` (sampler) — diffuse (Étape 10)
|
||||
//! - `@group(2) @binding(1)` : `diffuse_texture` (texture_2d<f32>) (Étape 10)
|
||||
//!
|
||||
//! `FrameUniforms` layout (std140 — each element 16-byte aligned, no padding) :
|
||||
//! | Offset | Field | Type | Meaning |
|
||||
@@ -23,6 +27,12 @@
|
||||
//! `light_dir` convention : vector pointing **from the surface toward the light**.
|
||||
//! The fragment shader negates it to obtain the light direction for the N·L term.
|
||||
//!
|
||||
//! ## Texturing (Étape 10, D2)
|
||||
//! The fragment samples `diffuse_texture` **unconditionally**. A texture-less `Material` binds the
|
||||
//! white 1×1 placeholder (texel = `[1,1,1]`), which is the multiplicative identity: `texel * color`
|
||||
//! leaves the vertex color unchanged, exactly reproducing the pre-Étape-10 look in both lit and
|
||||
//! unlit modes. A real texture tints/multiplies the vertex color.
|
||||
//!
|
||||
//! ## Vertex Input Layout (matches the full `resources::Vertex` struct, 56-byte stride)
|
||||
//! | Location | Attribute | Type | Offset (bytes) |
|
||||
//! |----------|-----------|----------|----------------|
|
||||
@@ -33,7 +43,7 @@
|
||||
//!
|
||||
//! ## Entry Points
|
||||
//! - `@vertex vs_main` : world = model * position ; clip = proj * view * world.
|
||||
//! - `@fragment fs_main` : ambient (hemispheric) + directional diffuse, or flat color when unlit.
|
||||
//! - `@fragment fs_main` : base = texel * vertex color; × (ambient + diffuse) when lit, or base when unlit.
|
||||
|
||||
struct VertexInput {
|
||||
@location(0) position: vec3<f32>,
|
||||
@@ -57,12 +67,17 @@ struct ObjectUniform {
|
||||
|
||||
@group(0) @binding(0) var<uniform> frame: FrameUniforms;
|
||||
@group(1) @binding(0) var<uniform> object: ObjectUniform;
|
||||
// Étape 10 (DRAFT D1) : groupe texture — sampler (0) + texture diffuse (1). Un matériau sans
|
||||
// texture lie le placeholder blanc 1×1 (D2), d'où l'échantillonnage inconditionnel.
|
||||
@group(2) @binding(0) var texture_sampler: sampler;
|
||||
@group(2) @binding(1) var diffuse_texture: texture_2d<f32>;
|
||||
|
||||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
@location(0) world_pos: vec3<f32>,
|
||||
@location(1) normal: vec3<f32>,
|
||||
@location(2) color: vec4<f32>,
|
||||
@location(2) uv: vec2<f32>,
|
||||
@location(3) color: vec4<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
@@ -81,15 +96,22 @@ fn vs_main(input: VertexInput) -> VertexOutput {
|
||||
object.model[2].xyz,
|
||||
);
|
||||
out.normal = normal_matrix * input.normal;
|
||||
out.uv = input.uv;
|
||||
out.color = input.color;
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
// Flat (unlit) mode : pas d'éclairage, couleur du vertex telle quelle.
|
||||
// Étape 10 (D2) : échantillonnage inconditionnel. Le texel module la couleur du vertex
|
||||
// (base = texel * color). Avec le placeholder blanc (texel = 1), base == vertex color :
|
||||
// aucune régression pour les matériaux sans texture, en lit comme en unlit.
|
||||
let texel = textureSample(diffuse_texture, texture_sampler, in.uv);
|
||||
let base = texel.rgb * in.color.rgb;
|
||||
|
||||
// Flat (unlit) mode : pas d'éclairage, texel * couleur du vertex telle quelle.
|
||||
if (frame.options.x != 0u) {
|
||||
return in.color;
|
||||
return vec4<f32>(base, in.color.a);
|
||||
}
|
||||
|
||||
let n = normalize(in.normal);
|
||||
@@ -104,6 +126,6 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
// Diffuse directionnel classique.
|
||||
let diffuse = frame.light_color.rgb * ndotl;
|
||||
|
||||
let lit = in.color.rgb * (ambient + diffuse);
|
||||
let lit = base * (ambient + diffuse);
|
||||
return vec4<f32>(lit, in.color.a);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user