Map-Loader entfernt: glTF ist das einzige 3D-Format
engine/map.rs + render/brush.rs raus, Welt kommt komplett aus .glb. Spawn via Empty mit role=spawn statt info_player_start; testscene.glb (Boden, Wände, Spawn) ersetzt test.map. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+12
-68
@@ -1,9 +1,6 @@
|
||||
//! Brush-Collision: Swept-AABB-Trace gegen konvexe Brushes (Quake-Hull-Idee).
|
||||
//!
|
||||
//! Ein Brush ist der Schnitt seiner Halbräume `{ n·x ≤ d }` (n nach außen) —
|
||||
//! genau die Ebenen, die auch render::brush rekonstruiert, hier aber in
|
||||
//! **Engine-Koords** und **vollständig** (keine Koplanar-Elimination, kein
|
||||
//! Culling: für Collision zählt das ganze solide Volumen).
|
||||
//! Collision: Swept-AABB-Trace gegen konvexe Volumen (Quake-Hull-Idee —
|
||||
//! „Brush" heißt hier: der Schnitt seiner Halbräume `{ n·x ≤ d }`,
|
||||
//! n nach außen).
|
||||
//!
|
||||
//! Die Box wird nicht selbst getract, sondern per Minkowski-Aufblasung in den
|
||||
//! Ebenen versenkt: jede Ebene rückt um die auf ihre Normale projizierte
|
||||
@@ -13,21 +10,18 @@
|
||||
//! den Mittelpunkt eine Haaresbreite vor der Fläche, damit der Folgeframe nicht
|
||||
//! sofort wieder im Kontakt steckt.
|
||||
//!
|
||||
//! Zwei Quellen füllen die Welt: Quake-Brushes aus der `.map` ([`build`])
|
||||
//! und Collider-Objekte (`collide`-Property) aus Blender-Modellen
|
||||
//! ([`add_model`]). Beide enden als dasselbe Ebenen-Set — die Trace kennt
|
||||
//! keine Herkunft. Modell-Ebenen sind die **konvexe Hülle** der Vertices
|
||||
//! Gefüllt wird die Welt aus Blender-Modellen ([`add_model`]): jedes Objekt
|
||||
//! mit `collide`-Property wird zur **konvexen Hülle** seiner Vertices
|
||||
//! ([`hull_planes`], inkrementeller Quickhull) — das Mesh selbst darf also
|
||||
//! konkav sein, kollidiert wird gegen seine Hülle. Ergänzt um die sechs
|
||||
//! achsparallelen AABB-Ebenen (Quake-„Bevel planes"): die `|n|·half`-
|
||||
//! Aufblasung ist nur eine konservative Näherung der Minkowski-Summe; die
|
||||
//! Axial-Ebenen ziehen sie an Kanten schräger Hüllen wieder stramm.
|
||||
//!
|
||||
//! Headless wie der Rest von `engine`: hängt nur an `map`/`model` (Quellen
|
||||
//! der Ebenen). Der Player ruft `trace` in `player::step`; gebaut wird die
|
||||
//! Welt einmal vom Frontend aus Map und Modellen.
|
||||
//! Headless wie der Rest von `engine`: hängt nur an `model` (Quelle der
|
||||
//! Ebenen). Der Player ruft `trace` in `player::step`; gebaut wird die
|
||||
//! Welt einmal vom Frontend aus den Modellen.
|
||||
|
||||
use crate::engine::map::{self, Map};
|
||||
use crate::engine::model::{Model, Object};
|
||||
|
||||
/// Mindestabstand (units), den der Box-Mittelpunkt vor einer Fläche hält —
|
||||
@@ -45,7 +39,7 @@ struct ConvexBrush {
|
||||
planes: Vec<Plane>,
|
||||
}
|
||||
|
||||
/// Die statische Kollisionswelt: alle soliden Brushes der Map.
|
||||
/// Die statische Kollisionswelt: alle soliden Volumen der geladenen Modelle.
|
||||
pub struct CollisionWorld {
|
||||
brushes: Vec<ConvexBrush>,
|
||||
}
|
||||
@@ -58,21 +52,7 @@ pub struct Hit {
|
||||
}
|
||||
|
||||
impl CollisionWorld {
|
||||
/// Kollisionswelt aus allen Brushes der Map bauen. Jede Brush-Face liefert
|
||||
/// eine Ebene (aus drei Punkten, nach Engine-Koords gedreht).
|
||||
pub fn build(world: &Map) -> Self {
|
||||
let mut brushes = Vec::new();
|
||||
for ent in &world.entities {
|
||||
for b in &ent.brushes {
|
||||
if b.faces.len() < 4 { continue; } // kein geschlossenes Volumen
|
||||
let planes = b.faces.iter().map(|f| plane_from(&f.plane)).collect();
|
||||
brushes.push(ConvexBrush { planes });
|
||||
}
|
||||
}
|
||||
Self { brushes }
|
||||
}
|
||||
|
||||
/// Leere Welt (keine Brushes) — Default, bis eine Map geladen ist.
|
||||
/// Leere Welt — Ausgangszustand, bis Modelle geladen sind.
|
||||
pub fn empty() -> Self {
|
||||
Self { brushes: Vec::new() }
|
||||
}
|
||||
@@ -325,19 +305,8 @@ pub(crate) fn trace_planes(planes: &[Plane], start: [f32; 3], end: [f32; 3], hal
|
||||
}
|
||||
}
|
||||
|
||||
/// Ebene aus drei Face-Punkten (Quake-Reihenfolge), gedreht nach Engine-Koords.
|
||||
/// Wie render::brush::plane, aber direkt im Engine-System: weil `to_engine` die
|
||||
/// Orientierung erhält (det +1), zeigt `cross(c−a, b−a)` weiter nach außen.
|
||||
fn plane_from(p: &[[f32; 3]; 3]) -> Plane {
|
||||
let a = map::to_engine(p[0]);
|
||||
let b = map::to_engine(p[1]);
|
||||
let c = map::to_engine(p[2]);
|
||||
let n = normalize(cross(sub(c, a), sub(b, a)));
|
||||
Plane { n, d: dot(n, a) }
|
||||
}
|
||||
|
||||
// --- kleine Vektor-Helfer (privat, wie render::brush; ein gemeinsames
|
||||
// engine::vec3 lohnt erst, falls ein dritter Nutzer auftaucht) ---------------
|
||||
// --- kleine Vektor-Helfer (privat; ein gemeinsames engine::vec3 lohnt
|
||||
// erst, falls ein dritter Nutzer auftaucht) ----------------------------------
|
||||
|
||||
fn sub(a: [f32; 3], b: [f32; 3]) -> [f32; 3] { [a[0] - b[0], a[1] - b[1], a[2] - b[2]] }
|
||||
fn dot(a: [f32; 3], b: [f32; 3]) -> f32 { a[0] * b[0] + a[1] * b[1] + a[2] * b[2] }
|
||||
@@ -483,29 +452,4 @@ mod tests {
|
||||
assert!(object_planes(&empty).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builds_brushes_from_map() {
|
||||
// Ein achsenparalleler Quader-Brush (Quake-Koords).
|
||||
let src = r#"
|
||||
{
|
||||
"classname" "worldspawn"
|
||||
{
|
||||
( 0 0 0 ) ( 0 1 0 ) ( 0 0 1 ) t 0 0 0 1 1
|
||||
( 0 0 0 ) ( 0 0 1 ) ( 1 0 0 ) t 0 0 0 1 1
|
||||
( 0 0 0 ) ( 1 0 0 ) ( 0 1 0 ) t 0 0 0 1 1
|
||||
( 64 64 64 ) ( 64 65 64 ) ( 65 64 64 ) t 0 0 0 1 1
|
||||
( 64 64 64 ) ( 65 64 64 ) ( 64 64 65 ) t 0 0 0 1 1
|
||||
( 64 64 64 ) ( 64 64 65 ) ( 64 65 64 ) t 0 0 0 1 1
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let m = map::parse(src);
|
||||
let w = CollisionWorld::build(&m);
|
||||
assert_eq!(w.brushes.len(), 1);
|
||||
assert_eq!(w.brushes[0].planes.len(), 6);
|
||||
// Engine-Koords des Quake-Würfels [0,64]³: x[0,2], y[0,2], z[-2,0]
|
||||
// (Drehung (x,z,−y)·1/32). Strahl von außerhalb (−X) hindurch.
|
||||
let h = w.trace([-1.0, 1.0, -1.0], [3.0, 1.0, -1.0], PT);
|
||||
assert!(h.is_some(), "Strahl sollte den Brush treffen");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user