re: control the range, segment the frames — f105/e105/e106 all match static assembly
A capture at controlled range (ship_capture_close.sh: lock a capital ship, close on it, F10 per range band) finally draws capital-ship hulls at full detail. Two correctness fixes were needed before the numbers meant anything: * one F10 log is ~14 frames with no delimiter, and WV_ref^-1 . WV_p only cancels the camera within one frame — segment_frames splits on vertex-buffer recurrence, and correlate_frames cross-checks the blocks against each other instead of trusting a single shot; * aggregate by consensus, not median: a stage holds several ships of one class sharing vertex buffers, so a block can mix two instances. Result: f105, e105 and e106 reproduce assemble_ship to <=0.43 units in translation and 0.000 in rotation for every part that does not move. The e106 rules generalise, and the viewer bug report now points at the viewer. Narrow leftovers: e105_brg is missing from assemble_ship, e105_eng_01 rotation differs by 1.711. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -183,6 +183,41 @@ pub const SHIP_VS_HASH: &str = "0xC7F781F4C1D58054";
|
||||
/// with `vs=`[`SHIP_VS_HASH`] are kept (the ship shader), so HUD/skybox draws are
|
||||
/// ignored. (The player fighter shares ONE buffer across its fin draws and so
|
||||
/// collapses to a single entry here — fine, capital ships are the target.)
|
||||
/// Split a capture into blocks that are guaranteed to share one camera.
|
||||
///
|
||||
/// **Why this is not optional.** One F10 press dumps a flat list of draws with
|
||||
/// no frame delimiter, and it spans ~14 frames (the same vertex buffer recurs
|
||||
/// that many times). The placement math is `WV_ref⁻¹ · WV_p`, which cancels the
|
||||
/// camera **only when both draws come from the same frame** — mix frames and
|
||||
/// the residual is the camera's motion between them. With a static ship and a
|
||||
/// static camera that error is invisible, which is how the single validated
|
||||
/// `e106` capture passed; closing on a cruiser at ~760 u/s it is hundreds of
|
||||
/// units, and two frames of the same ship then disagree about where its parts
|
||||
/// are (measured 2026-08-10: `f105_bdy_02` at `[488, 736, -620]` vs
|
||||
/// `[0, 0, -1090]`).
|
||||
///
|
||||
/// The split rule is the recurrence itself: a vertex buffer that appears again
|
||||
/// starts a new block. Splitting too eagerly is harmless (a block is still one
|
||||
/// camera, just with fewer parts in it) and it separates two instances of the
|
||||
/// same class as a bonus; failing to split is what corrupts the result.
|
||||
pub fn segment_frames(draws: &[CapturedDraw]) -> Vec<Vec<CapturedDraw>> {
|
||||
let mut out: Vec<Vec<CapturedDraw>> = Vec::new();
|
||||
let mut cur: Vec<CapturedDraw> = Vec::new();
|
||||
let mut seen: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
for d in draws {
|
||||
if !seen.insert(d.vbase) {
|
||||
out.push(std::mem::take(&mut cur));
|
||||
seen.clear();
|
||||
seen.insert(d.vbase);
|
||||
}
|
||||
cur.push(d.clone());
|
||||
}
|
||||
if !cur.is_empty() {
|
||||
out.push(cur);
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub fn parse_drawlog(text: &str) -> Vec<CapturedDraw> {
|
||||
let mut out = Vec::new();
|
||||
let mut seen: std::collections::HashSet<u32> = std::collections::HashSet::new();
|
||||
|
||||
Reference in New Issue
Block a user