# Materials & textures A **`Material`** describes a mesh's appearance: it references a shader (by id) and optionally a **diffuse texture**. Several materials pointing at the same shader share the same compiled GPU pipeline (the `PipelineCache` held by the scene). The engine ships a single shader: **`standard`** — multi-light Phong lighting (see [Lights](lights.md)), with an **unlit** mode for flat rendering. ## 1. Registering the shader ```rust app.scene .register_shader("standard", wsg_lib::utils::STANDARD_SHADER_PATH) .unwrap(); ``` > **Note**: `STANDARD_SHADER_PATH` points to an optional file on disk; if it is missing > (the normal case for the embedded library), loading falls back to the shader **embedded at > compile time** (`include_str!`, byte-identical). The fallback message you may see is > therefore **expected and harmless**. For a custom shader: register your `.wgsl` file path under an id of your choice (it must expose the same bind groups as `standard` — frame @0, object @1, texture @2, shadow @3 — see [ARCHI_RENDU](../tech/ARCHI_RENDU.md) and the [`shaders/standard_shader.wgsl`](../../lib/src/shaders/standard_shader.wgsl) file). ## 2. Creating materials ```rust // Textureless material: the color comes from per-vertex colors (or white by default). app.scene.add_material_shader("mat", "standard").unwrap(); // Textured material: the texture must first be registered in the scene (below). app.scene.add_material_texture("mat_textured", "standard", "my_texture").unwrap(); ``` Binding a material to a mesh happens at mesh creation (see [Meshes](meshes.md)): ```rust app.scene.create_mesh("cube_mesh", cube(1.0), Some("mat_textured")).unwrap(); ``` A mesh created with `material = None` is rendered with the scene's **default material** (`standard`, built once then cached) — that is the behavior of the [`simple`](../../lib/examples/simple.rs) example. ## 3. Diffuse textures `Texture` is a GPU image in `Rgba8UnormSrgb` (linear sampler, repeat addressing). Four constructors: | Constructor | Usage | |--------------|-------| | `Texture::from_rgba8(device, queue, w, h, rgba, label)` | raw RGBA8 bytes (procedural) | | `Texture::from_bytes(device, queue, label, bytes)` | encoded data (PNG/JPEG… via the `image` crate) | | `Texture::from_file(device, queue, label, path)` | image file on disk | | `Texture::white_placeholder(device, queue)` | 1×1 white — used internally when a material has no texture | You get `device`/`queue` in `setup()` via `app.context()`: ```rust let (device, queue) = { let ctx = app.context(); (ctx.device.clone(), ctx.queue.clone()) }; let texture = Texture::from_rgba8(&device, &queue, 8, 8, &my_rgba, "checker").unwrap(); app.scene.add_texture("checker_texture", texture).unwrap(); app.scene.add_material_texture("ground_mat", "standard", "checker_texture").unwrap(); ``` The exact snippet (8×8 checkerboard + stripes generation) is in [`demo.rs`](../../lib/examples/demo.rs) and [`cube.rs`](../../lib/examples/cube.rs). Two conditions for a texture to show up: 1. the material is created via `add_material_texture` (otherwise the 1×1 white placeholder is bound — no visual effect, no regression); 2. the `Geometry` carries **UVs** (`.with_uvs(…)`). Without UVs, sampling is constant. The procedural primitives (`uv_sphere`, `cube`, …) already provide them. ## 4. Unlit mode (flat / 2D rendering) "Flat" rendering (vertex colors as-is, no lighting) is a **renderer switch**, not a material: ```rust app.renderer_mut().set_unlit(true); // in setup() ``` This is the mode of the `simple` example (2D quad). In this mode the scene's lights are ignored; per-vertex colors (or white) are rendered directly. 2D is a special case of 3D: the single `standard` pipeline serves both. > `clear_lights()` (see [Lights](lights.md)) gives a similar result but keeps the lit > pipeline: only ambient stays active. Use it when you want to "turn off the lights" without > switching to unlit. ## Links - [User README](README.md) · [Meshes](meshes.md) · [Lights](lights.md) · [Examples](examples.md) - [Root README](../../README.md) · [ARCHI_RENDU](../tech/ARCHI_RENDU.md)