Тесты моделей оружия: структура, VVD, скиннинг вьюмодели
Some checks are pending
CI / checks (push) Waiting to run
Some checks are pending
CI / checks (push) Waiting to run
Замеры на реальных ассетах, которые пригодятся для дальнейших правок: - v_pistol: 1 бодипарт, 2 меша (1169/4356 и 988/2448), 2157 вершин, 2167 в VVD (10 не используются), кадры лежат внутри MDL, флаги дорожек 2/3/8/12 (RAWROT/RAWPOS/ANIMROT/ANIMPOS); - скиннинг вьюмодели не разваливает меш: между позой покоя и кадром idle01 максимальный сдвиг 4 юнита, габарит 20×23×13; - v_pistol рисуется «лепестком» даже в позе покоя (до скиннинга) — проблема загрузки геометрии именно этой модели, отложена; по умолчанию w_pistol. Все сьюты зелёные.
This commit is contained in:
parent
c1b35b6263
commit
7490ef3798
1 changed files with 74 additions and 0 deletions
|
|
@ -537,6 +537,80 @@ fn real_weapon_model_structure() {
|
|||
}
|
||||
}
|
||||
|
||||
/// Заголовки VVD моделей оружия: версия, смещения, размеры.
|
||||
#[test]
|
||||
fn real_weapon_vvd_headers() {
|
||||
let Some(root) = assets_root() else {
|
||||
eprintln!("пропуск: ассеты не найдены");
|
||||
return;
|
||||
};
|
||||
let vfs = mount_game(&root);
|
||||
for name in [
|
||||
"models/weapons/v_pistol",
|
||||
"models/weapons/w_pistol",
|
||||
"models/props_c17/oildrum001",
|
||||
] {
|
||||
let Ok(data) = vfs.read(&format!("{name}.vvd")) else {
|
||||
continue;
|
||||
};
|
||||
let vvd = formats::vvd::Vvd::parse(&data).expect("разбор vvd");
|
||||
let h = &vvd.header;
|
||||
eprintln!(
|
||||
"{name}.vvd: байт {}, версия {}, лодов {}, вершин по LOD {:?}, фиксов {}, \
|
||||
vertex_data_start {}, tangent_data_start {}",
|
||||
data.len(),
|
||||
h.version,
|
||||
h.num_lods,
|
||||
&h.num_lod_vertexes[..h.num_lods.clamp(0, 8) as usize],
|
||||
h.num_fixups,
|
||||
h.vertex_data_start,
|
||||
h.tangent_data_start
|
||||
);
|
||||
let verts = vvd.vertices(0).expect("вершины");
|
||||
let mut min = [f32::MAX; 3];
|
||||
let mut max = [f32::MIN; 3];
|
||||
for v in &verts {
|
||||
for j in 0..3 {
|
||||
min[j] = min[j].min(v.position[j]);
|
||||
max[j] = max[j].max(v.position[j]);
|
||||
}
|
||||
}
|
||||
eprintln!(" габарит вершин: min {min:?}, max {max:?}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Габарит модели из заголовка MDL: должен совпадать с вершинами VVD.
|
||||
#[test]
|
||||
fn real_weapon_mdl_hull() {
|
||||
let Some(root) = assets_root() else {
|
||||
eprintln!("пропуск: ассеты не найдены");
|
||||
return;
|
||||
};
|
||||
let vfs = mount_game(&root);
|
||||
for name in ["models/weapons/v_pistol", "models/weapons/w_pistol"] {
|
||||
let Ok(data) = vfs.read(&format!("{name}.mdl")) else {
|
||||
continue;
|
||||
};
|
||||
// studiohdr_t: hull_min — 104, hull_max — 116.
|
||||
let f = |o: usize| f32::from_le_bytes([data[o], data[o + 1], data[o + 2], data[o + 3]]);
|
||||
eprintln!(
|
||||
"{name}: hull_min [{:.1} {:.1} {:.1}], hull_max [{:.1} {:.1} {:.1}], view_bb [{:.1} {:.1} {:.1}]..[{:.1} {:.1} {:.1}]",
|
||||
f(104),
|
||||
f(108),
|
||||
f(112),
|
||||
f(116),
|
||||
f(120),
|
||||
f(124),
|
||||
f(128),
|
||||
f(132),
|
||||
f(136),
|
||||
f(140),
|
||||
f(144),
|
||||
f(148)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Позиции вершин экземпляра модели.
|
||||
fn instance_positions(world: &engine::World, index: usize) -> Vec<[f32; 3]> {
|
||||
let instance = &world.model_instances[index];
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue