109 lines
3.1 KiB
Markdown
109 lines
3.1 KiB
Markdown
# Module `mesh` — Sources de géométrie
|
|
|
|
Le module `wsg::mesh` est le point d'entrée unique pour **d'où vient la géométrie** :
|
|
générateurs procéduraux ou import de fichiers.
|
|
|
|
## Primitives procédurales
|
|
|
|
Chaque famille de primitives est derrière une **feature** — vous ne compilez que ce dont vous avez besoin.
|
|
|
|
| Feature | Fonction | Description |
|
|
|---------|----------|-------------|
|
|
| `prim-cube` | `cube(size)` | Cube centré, 24 sommets, normales par face |
|
|
| `prim-plane` | `plane(w, d, seg_x, seg_z)` | Plan horizontal XZ (normale +Y), subdivisé |
|
|
| `prim-sphere` | `uv_sphere(r, sectors, stacks)` | Sphère lat/long, normales lisses |
|
|
| `prim-sphere` | `icosphere(r, subdivisions)` | Icosphère (subdiv icosahedron) |
|
|
| `prim-cylinder` | `cylinder(r, h, sectors)` | Cylindre (côté + caps), normales analytiques |
|
|
| `prim-cone` | `cone(r, h, sectors)` | Cône (apex + base fermée) |
|
|
| `prim-torus` | `torus(major, minor, seg_maj, seg_min)` | Tore, normales lisses |
|
|
|
|
### Features par défaut
|
|
|
|
```toml
|
|
# Cargo.toml de votre projet
|
|
[dependencies]
|
|
wsg-lib = { path = "../lib" }
|
|
# Default: toutes les primitives activées (all-prims)
|
|
```
|
|
|
|
```toml
|
|
# Ne compiler que le cube et la sphère :
|
|
wsg-lib = { path = "../lib", default-features = false, features = ["prim-cube", "prim-sphere"] }
|
|
```
|
|
|
|
### Usage
|
|
|
|
```rust
|
|
use wsg_lib::prelude::*;
|
|
|
|
let cube = cube(2.0);
|
|
let sphere = uv_sphere(1.0, 32, 16);
|
|
let ico = icosphere(1.0, 2);
|
|
|
|
// Tous retournent un Geometry (positions + normals + UVs + indices)
|
|
assert_eq!(cube.positions.len(), 24);
|
|
```
|
|
|
|
## Import de fichiers
|
|
|
|
| Feature | Fonction | Format |
|
|
|---------|----------|--------|
|
|
| `import-obj` | `load_obj(path)` / `parse_obj(str)` | Wavefront OBJ |
|
|
| `import-gltf` | `load_gltf(path)` | glTF 2.0 / GLB (stub) |
|
|
|
|
### Parser OBJ
|
|
|
|
Supporte : `v`, `vn`, `vt`, `f` (3-4 sommets, triangulation en éventail).
|
|
Si le fichier n'a pas de normales, elles sont **calculées** (pondération par aire).
|
|
|
|
```rust
|
|
use wsg_lib::mesh::{load_obj, parse_obj};
|
|
|
|
// Depuis un fichier
|
|
let geom = load_obj("model.obj")?;
|
|
|
|
// Depuis une string
|
|
let geom = parse_obj("v 0 0 0\nv 1 0 0\nv 0 1 0\nf 1 2 3\n")?;
|
|
```
|
|
|
|
### Erreurs
|
|
|
|
```rust
|
|
use wsg_lib::mesh::import::MeshImportError;
|
|
|
|
match load_obj("missing.obj") {
|
|
Ok(geom) => { /* … */ }
|
|
Err(MeshImportError::Io(e)) => eprintln!("fichier inaccessible: {e}"),
|
|
Err(MeshImportError::Parse(e)) => eprintln!("syntaxe invalide: {e}"),
|
|
Err(MeshImportError::Unsupported(e)) => eprintln!("feature non supportée: {e}"),
|
|
}
|
|
```
|
|
|
|
## De `Geometry` à la scène
|
|
|
|
Le module `mesh` produit des `Geometry` (données CPU). Pour les rendre,
|
|
passez par `Scene::create_mesh` qui les transfère en GPU :
|
|
|
|
```rust
|
|
use wsg_lib::prelude::*;
|
|
use wsg_lib::mesh::cube;
|
|
|
|
// Dans AppHandler::setup :
|
|
let geom = cube(1.0);
|
|
app.scene.create_mesh("my_mesh", geom, Some("my_mat"))?;
|
|
app.scene.add_entity("my_entity", "my_mesh")?;
|
|
```
|
|
|
|
## Example
|
|
|
|
```sh
|
|
cargo run -p wsg-lib --example import --features import-obj -- model.obj
|
|
```
|
|
|
|
## Convention
|
|
|
|
- **Y-up**, origine centrée (sauf `plane` : plan XZ à y=0)
|
|
- Normales **sortantes**
|
|
- UVs dans [0,1]²
|
|
- Winding **CCW** (face avant)
|