doc
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user