feat(math): Étape 15.A primitives — cube, plane, uv_sphere, icosphere, cylinder, cone, torus + tests ; factorisation cube_geometry (cube, spot_test)
This commit is contained in:
+3
-64
@@ -13,7 +13,8 @@
|
||||
use glam::{Quat, Vec3};
|
||||
use wsg_lib::AppHandler;
|
||||
use wsg_lib::app::AppBuilder;
|
||||
use wsg_lib::resources::{Geometry, Texture};
|
||||
use wsg_lib::math::cube;
|
||||
use wsg_lib::resources::Texture;
|
||||
use wsg_lib::utils::WsgError;
|
||||
|
||||
/// Handler de démonstration : fait tourner le cube texturé dans `update`.
|
||||
@@ -22,68 +23,6 @@ struct Cube {
|
||||
angle: f32,
|
||||
}
|
||||
|
||||
/// Construit la `Geometry` d'un cube unitaire centré à l'origine (arête de 1), une normale et des
|
||||
/// coordonnées UV par face. 24 sommets (4 par face) + 36 indices ; la couleur est absente (défaut
|
||||
/// blanc opaque via `Geometry::to_vertices`). Depuis l'Étape 10, chaque face reçoit des UV [0,1]² pour
|
||||
/// que la texture diffuse soit proprement projetée sur le cube.
|
||||
fn cube_geometry() -> Geometry {
|
||||
let s = 0.5; // demi-arête
|
||||
// Chaque face : (normale sortante, 4 coins). Le culling est désactivé par défaut (PrimitiveState
|
||||
// par défaut), donc l'ordre d'enroulement n'affecte pas la visibilité ; seules les normales comptent
|
||||
// pour l'éclairage.
|
||||
let faces: [([f32; 3], [[f32; 3]; 4]); 6] = [
|
||||
(
|
||||
[0.0, 0.0, 1.0],
|
||||
[[-s, -s, s], [s, -s, s], [s, s, s], [-s, s, s]],
|
||||
), // +Z
|
||||
(
|
||||
[0.0, 0.0, -1.0],
|
||||
[[s, -s, -s], [-s, -s, -s], [-s, s, -s], [s, s, -s]],
|
||||
), // -Z
|
||||
(
|
||||
[1.0, 0.0, 0.0],
|
||||
[[s, -s, -s], [s, s, -s], [s, s, s], [s, -s, s]],
|
||||
), // +X
|
||||
(
|
||||
[-1.0, 0.0, 0.0],
|
||||
[[-s, -s, s], [-s, s, s], [-s, s, -s], [-s, -s, -s]],
|
||||
), // -X
|
||||
(
|
||||
[0.0, 1.0, 0.0],
|
||||
[[-s, s, -s], [s, s, -s], [s, s, s], [-s, s, s]],
|
||||
), // +Y
|
||||
(
|
||||
[0.0, -1.0, 0.0],
|
||||
[[-s, -s, s], [s, -s, s], [s, -s, -s], [-s, -s, -s]],
|
||||
), // -Y
|
||||
];
|
||||
|
||||
let mut positions = Vec::with_capacity(24);
|
||||
let mut normals = Vec::with_capacity(24);
|
||||
let mut uvs = Vec::with_capacity(24);
|
||||
// Mapping UV canonique d'un carré : BL(0,0) BR(1,0) TR(1,1) TL(0,1).
|
||||
let quad_uvs = [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
|
||||
for (normal, corners) in faces {
|
||||
for (i, corner) in corners.iter().enumerate() {
|
||||
positions.push(*corner);
|
||||
normals.push(normal);
|
||||
uvs.push(quad_uvs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 2 triangles par face, 36 indices.
|
||||
let mut indices = Vec::with_capacity(36);
|
||||
for face in 0..6u16 {
|
||||
let b = face * 4;
|
||||
indices.extend_from_slice(&[b, b + 1, b + 2, b, b + 2, b + 3]);
|
||||
}
|
||||
|
||||
Geometry::new(positions)
|
||||
.with_normals(normals)
|
||||
.with_uvs(uvs)
|
||||
.with_indices(indices)
|
||||
}
|
||||
|
||||
/// Génère un damier RGBA 8×8 (blanc/brique) *procédural*, sans asset sur disque, pour texturer le
|
||||
/// cube (Étape 10, D3/D4). Renvoyé en `Vec<u8>` brut RGBA8, chargeable via `Texture::from_rgba8`.
|
||||
fn checkerboard_rgba() -> Vec<u8> {
|
||||
@@ -120,7 +59,7 @@ impl AppHandler for Cube {
|
||||
.unwrap();
|
||||
|
||||
app.scene
|
||||
.create_mesh("cube_mesh", cube_geometry(), Some("cube_material"))
|
||||
.create_mesh("cube_mesh", cube(1.0), Some("cube_material"))
|
||||
.unwrap();
|
||||
app.scene.add_entity("cube", "cube_mesh").unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user