Merge feature/hair-defaults (Tim t1023u)
The contents of this binary file are not shown.
@@ -117,6 +117,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
117
117
.position(|n| n == &body.joint_names[head])
118
118
.ok_or("head missing in edited body")?;
119
119
preset.bind(1, &edited, part, head_edited)?;
120
// Tim t1023u defaults: position relative to the bone, rotation, gloss.
121
preset.attachments[part].translation = [0.0, -0.370, 0.0];
122
preset.attachments[part].rotation_deg = [0.0, 0.0, 0.0];
123
preset.attachments[part].specular = 0.62;
120
124
std::fs::write(&a[3], preset.encode()?)?;
121
125
println!(
122
126
"hair: {} vertices, {} triangles, bound to {}",
@@ -117,6 +117,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {117
.position(|n| n == &body.joint_names[head])117
.position(|n| n == &body.joint_names[head])118
.ok_or("head missing in edited body")?;118
.ok_or("head missing in edited body")?;119
preset.bind(1, &edited, part, head_edited)?;119
preset.bind(1, &edited, part, head_edited)?;120
// Tim t1023u defaults: position relative to the bone, rotation, gloss.121
preset.attachments[part].translation = [0.0, -0.370, 0.0];122
preset.attachments[part].rotation_deg = [0.0, 0.0, 0.0];123
preset.attachments[part].specular = 0.62;120
std::fs::write(&a[3], preset.encode()?)?;124
std::fs::write(&a[3], preset.encode()?)?;121
println!(125
println!(122
"hair: {} vertices, {} triangles, bound to {}",126
"hair: {} vertices, {} triangles, bound to {}",@@ -923,55 +923,14 @@ mod tests {
923
923
clip_name: String::new(),
924
924
..Default::default()
925
925
};
926
// Tim t1023u defaults for the bundled hair.
927
let part = &hair.attachments[0];
928
assert_eq!(part.translation, [0.0, -0.370, 0.0]);
929
assert_eq!(part.rotation_deg, [0.0, 0.0, 0.0]);
930
assert_eq!(part.specular, 0.62);
926
931
let layers = crate::equipment::layers(hair, 1, &female, &controls).unwrap();
927
932
assert_eq!(layers.len(), 1);
928
let (mut lo, mut hi) = (f32::MAX, f32::MIN);
929
for p in &layers[0].mesh.positions {
930
let m = &layers[0].model;
931
let y = m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13];
932
lo = lo.min(y);
933
hi = hi.max(y);
934
}
935
// Tim's original female with hair has rest top Y 1.621 m (the hair);
936
// the baked rigid hair must reach exactly that, the ponytail ~1.27 m.
937
assert!(
938
(hi - 1.621).abs() < 0.002 && (1.2..1.35).contains(&lo),
939
"hair Y {lo}..{hi}"
940
);
941
// Defaults (t1022u) and Fit animations already applied per sex.
942
let render = &document.render;
943
assert_eq!(
944
(render.target_width, render.target_height, render.fps),
945
(92, 128, 8)
946
);
947
for (index, model) in [
948
crate::default_bodies::MALE_MODEL,
949
crate::default_bodies::FEMALE_MODEL,
950
]
951
.into_iter()
952
.enumerate()
953
{
954
let body = crate::preview::load_body_file(&root.join(model)).unwrap();
955
let fitted = crate::camera::animation_envelope(
956
&body,
957
crate::project::CameraFraming::default(),
958
92. / 128.,
959
8,
960
0.05,
961
0.,
962
)
963
.unwrap();
964
let stored = render.framing[index];
965
assert_eq!(
966
(stored.height_milli, stored.center_y_milli),
967
fitted,
968
"{model}"
969
);
970
assert!(
971
(1500..2300).contains(&stored.height_milli),
972
"{model} {stored:?}"
973
);
974
}
933
assert_eq!(layers[0].specular, 0.62);
975
934
// The saved manifest reopens with the same bodies.
976
935
let reopened = crate::project::open_project(&root.join("character.ppd")).unwrap();
977
936
assert_eq!(
@@ -923,55 +923,14 @@ mod tests {923
clip_name: String::new(),923
clip_name: String::new(),924
..Default::default()924
..Default::default()925
};925
};926
// Tim t1023u defaults for the bundled hair.927
let part = &hair.attachments[0];928
assert_eq!(part.translation, [0.0, -0.370, 0.0]);929
assert_eq!(part.rotation_deg, [0.0, 0.0, 0.0]);930
assert_eq!(part.specular, 0.62);926
let layers = crate::equipment::layers(hair, 1, &female, &controls).unwrap();931
let layers = crate::equipment::layers(hair, 1, &female, &controls).unwrap();927
assert_eq!(layers.len(), 1);932
assert_eq!(layers.len(), 1);928
let (mut lo, mut hi) = (f32::MAX, f32::MIN);933
assert_eq!(layers[0].specular, 0.62);929
for p in &layers[0].mesh.positions {930
let m = &layers[0].model;931
let y = m[1] * p[0] + m[5] * p[1] + m[9] * p[2] + m[13];932
lo = lo.min(y);933
hi = hi.max(y);934
}935
// Tim's original female with hair has rest top Y 1.621 m (the hair);936
// the baked rigid hair must reach exactly that, the ponytail ~1.27 m.937
assert!(938
(hi - 1.621).abs() < 0.002 && (1.2..1.35).contains(&lo),939
"hair Y {lo}..{hi}"940
);941
// Defaults (t1022u) and Fit animations already applied per sex.942
let render = &document.render;943
assert_eq!(944
(render.target_width, render.target_height, render.fps),945
(92, 128, 8)946
);947
for (index, model) in [948
crate::default_bodies::MALE_MODEL,949
crate::default_bodies::FEMALE_MODEL,950
]951
.into_iter()952
.enumerate()953
{954
let body = crate::preview::load_body_file(&root.join(model)).unwrap();955
let fitted = crate::camera::animation_envelope(956
&body,957
crate::project::CameraFraming::default(),958
92. / 128.,959
8,960
0.05,961
0.,962
)963
.unwrap();964
let stored = render.framing[index];965
assert_eq!(966
(stored.height_milli, stored.center_y_milli),967
fitted,968
"{model}"969
);970
assert!(971
(1500..2300).contains(&stored.height_milli),972
"{model} {stored:?}"973
);974
}975
// The saved manifest reopens with the same bodies.934
// The saved manifest reopens with the same bodies.976
let reopened = crate::project::open_project(&root.join("character.ppd")).unwrap();935
let reopened = crate::project::open_project(&root.join("character.ppd")).unwrap();977
assert_eq!(936
assert_eq!(