Rename neck_pivot_probe to auto_pivot_probe (pivot is the rest-pose centre)
@@ -1,5 +1,5 @@
1
//! Real Mesa/Xvfb proof that neck pivot differs from center-only orbit at pitched yaw.
2
//! Usage: OUTDIR=... xvfb-run -a cargo run --example neck_pivot_probe --locked
1
//! Real Mesa/Xvfb proof that the automatic (rest-pose centre) pivot differs from a center-only orbit at pitched yaw.
2
//! Usage: OUTDIR=... xvfb-run -a cargo run --example auto_pivot_probe --locked
3
3
use paperdoll_renderer::{camera, preview, production, project::CameraFraming};
4
4
use std::{
5
5
path::{Path, PathBuf},
@@ -41,7 +41,7 @@ fn downsample(src: &[u8], sw: u32, sh: u32, dw: u32, dh: u32) -> Vec<u8> {
41
41
42
42
fn main() -> Result<(), Box<dyn std::error::Error>> {
43
43
let out = PathBuf::from(
44
std::env::var("OUTDIR").unwrap_or_else(|_| "/workspace/paperdoll-neck-artifacts".into()),
44
std::env::var("OUTDIR").unwrap_or_else(|_| "/workspace/paperdoll-pivot-artifacts".into()),
45
45
);
46
46
std::fs::create_dir_all(&out)?;
47
47
let outcome = Arc::new(Mutex::new(None));
@@ -51,7 +51,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
51
51
..paperdoll_renderer::preview_gl::native_options()
52
52
};
53
53
eframe::run_native(
54
"Paperdoll neck pivot probe",
54
"Paperdoll auto pivot probe",
55
55
options,
56
56
Box::new(move |creation| {
57
57
let test = (|| -> Result<serde_json::Value, String> {
@@ -64,9 +64,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
64
64
.join("tests/fixtures/bodies/test-body-male.glb"),
65
65
)?;
66
66
let resolved = camera::resolve(&body, CameraFraming::default());
67
let neck_y = resolved.framing.pivot_y_milli.ok_or("nekpivot ontbreekt")?;
68
if neck_y == CameraFraming::default().center_y_milli {
69
return Err("nekpivot mag niet gelijk zijn aan default centrum".into());
67
let pivot_y = resolved
68
.framing
69
.pivot_y_milli
70
.ok_or("automatische pivot ontbreekt")?;
71
if pivot_y == CameraFraming::default().center_y_milli {
72
return Err(
73
"automatische pivot mag niet gelijk zijn aan default centrum".into(),
74
);
70
75
}
71
76
let mut renderer = production::GpuRenderer::default();
72
77
let mut cache = paperdoll_renderer::equipment::TextureCache::default();
@@ -87,26 +92,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
87
92
depth_range_milli: None,
88
93
},
89
94
output: out.clone(),
90
project_id: "neck-probe".into(),
95
project_id: "auto-pivot-probe".into(),
91
96
project_name: "Neck probe".into(),
92
97
body_model: production::SourceFingerprint {
93
98
path: "assets/body/test-body-male.glb".into(),
94
sha256: paperdoll_renderer::digest::sha256_hex(b"neck-probe-body"),
99
sha256: paperdoll_renderer::digest::sha256_hex(b"auto-pivot-probe-body"),
95
100
},
96
101
preset_sha256: None,
97
102
};
98
103
let old_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;
99
104
let old = unsafe { renderer.render(gl, &old_scene) }?;
100
105
job.framing.pivot_y_milli = None;
101
let neck_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;
102
let neck = unsafe { renderer.render(gl, &neck_scene) }?;
106
let pivot_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;
107
let pivoted = unsafe { renderer.render(gl, &pivot_scene) }?;
103
108
unsafe { renderer.destroy(gl) };
104
assert_eq!((old.width, old.height), (neck.width, neck.height));
109
assert_eq!((old.width, old.height), (pivoted.width, pivoted.height));
105
110
let mut changed = 0usize;
106
111
for (a, b) in old
107
112
.diffuse
108
113
.chunks_exact(4)
109
.zip(neck.diffuse.chunks_exact(4))
114
.zip(pivoted.diffuse.chunks_exact(4))
110
115
{
111
116
if a != b {
112
117
changed += 1;
@@ -114,23 +119,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
114
119
}
115
120
if changed < 200 {
116
121
return Err(format!(
117
"te weinig pixelverschil tussen centrum-pivot en nekpivot: {changed}"
122
"te weinig pixelverschil tussen centrum-pivot en automatische pivot: {changed}"
118
123
));
119
124
}
120
125
// Zero-pitch image center / feet framing must stay close after raising pivot.
121
126
job.framing.pivot_y_milli = Some(1000);
122
127
let old0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;
123
128
job.framing.pivot_y_milli = None;
124
let neck0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;
129
let pivot0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;
125
130
let old0b = unsafe {
126
131
let mut r = production::GpuRenderer::default();
127
132
let b = r.render(gl, &old0)?;
128
133
r.destroy(gl);
129
134
b
130
135
};
131
let neck0b = unsafe {
136
let pivot0b = unsafe {
132
137
let mut r = production::GpuRenderer::default();
133
let b = r.render(gl, &neck0)?;
138
let b = r.render(gl, &pivot0)?;
134
139
r.destroy(gl);
135
140
b
136
141
};
@@ -138,12 +143,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
138
143
let feet = ((old0b.height * 9 / 10) * old0b.width + old0b.width / 2) as usize;
139
144
let mid_delta = old0b.diffuse[mid * 4..mid * 4 + 4]
140
145
.iter()
141
.zip(&neck0b.diffuse[mid * 4..mid * 4 + 4])
146
.zip(&pivot0b.diffuse[mid * 4..mid * 4 + 4])
142
147
.map(|(a, b)| a.abs_diff(*b) as u32)
143
148
.sum::<u32>();
144
149
let feet_delta = old0b.diffuse[feet * 4..feet * 4 + 4]
145
150
.iter()
146
.zip(&neck0b.diffuse[feet * 4..feet * 4 + 4])
151
.zip(&pivot0b.diffuse[feet * 4..feet * 4 + 4])
147
152
.map(|(a, b)| a.abs_diff(*b) as u32)
148
153
.sum::<u32>();
149
154
write_rgba(
@@ -153,10 +158,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
153
158
&old.diffuse,
154
159
)?;
155
160
write_rgba(
156
&out.join("neck-pivot-p30-y90.png"),
157
neck.width,
158
neck.height,
159
&neck.diffuse,
161
&out.join("auto-pivot-p30-y90.png"),
162
pivoted.width,
163
pivoted.height,
164
&pivoted.diffuse,
160
165
)?;
161
166
let contact_w = 256;
162
167
let contact_h = 192;
@@ -168,9 +173,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
168
173
contact_h,
169
174
);
170
175
let right = downsample(
171
&neck.diffuse,
172
neck.width,
173
neck.height,
176
&pivoted.diffuse,
177
pivoted.width,
178
pivoted.height,
174
179
contact_w / 2,
175
180
contact_h,
176
181
);
@@ -185,7 +190,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
185
190
}
186
191
}
187
192
write_rgba(
188
&out.join("neck-vs-center-contact.png"),
193
&out.join("auto-vs-center-contact.png"),
189
194
contact_w,
190
195
contact_h,
191
196
&contact,
@@ -195,7 +200,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
195
200
"pitch": pitch,
196
201
"yaw": yaw,
197
202
"center_y_milli": 1000,
198
"neck_y_milli": neck_y,
203
"pivot_y_milli": pivot_y,
199
204
"pivot_source": resolved.source,
200
205
"highres": [old.width, old.height],
201
206
"changed_pixels_pitch30": changed,
@@ -203,16 +208,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
203
208
"zero_pitch_feet_channel_delta": feet_delta,
204
209
"artifacts": [
205
210
"center-pivot-p30-y90.png",
206
"neck-pivot-p30-y90.png",
207
"neck-vs-center-contact.png"
211
"auto-pivot-p30-y90.png",
212
"auto-vs-center-contact.png"
208
213
]
209
214
});
210
215
std::fs::write(
211
out.join("neck-pivot-probe.json"),
216
out.join("auto-pivot-probe.json"),
212
217
serde_json::to_vec_pretty(&report).unwrap(),
213
218
)
214
219
.map_err(|e| e.to_string())?;
215
println!("NECK_PIVOT_PROBE {report}");
220
println!("AUTO_PIVOT_PROBE {report}");
216
221
Ok(report)
217
222
})();
218
223
*result.lock().unwrap() = Some(test);
@@ -1,5 +1,5 @@1
//! Real Mesa/Xvfb proof that neck pivot differs from center-only orbit at pitched yaw.1
//! Real Mesa/Xvfb proof that the automatic (rest-pose centre) pivot differs from a center-only orbit at pitched yaw.2
//! Usage: OUTDIR=... xvfb-run -a cargo run --example neck_pivot_probe --locked2
//! Usage: OUTDIR=... xvfb-run -a cargo run --example auto_pivot_probe --locked3
use paperdoll_renderer::{camera, preview, production, project::CameraFraming};3
use paperdoll_renderer::{camera, preview, production, project::CameraFraming};4
use std::{4
use std::{5
path::{Path, PathBuf},5
path::{Path, PathBuf},@@ -41,7 +41,7 @@ fn downsample(src: &[u8], sw: u32, sh: u32, dw: u32, dh: u32) -> Vec<u8> {41
41
42
fn main() -> Result<(), Box<dyn std::error::Error>> {42
fn main() -> Result<(), Box<dyn std::error::Error>> {43
let out = PathBuf::from(43
let out = PathBuf::from(44
std::env::var("OUTDIR").unwrap_or_else(|_| "/workspace/paperdoll-neck-artifacts".into()),44
std::env::var("OUTDIR").unwrap_or_else(|_| "/workspace/paperdoll-pivot-artifacts".into()),45
);45
);46
std::fs::create_dir_all(&out)?;46
std::fs::create_dir_all(&out)?;47
let outcome = Arc::new(Mutex::new(None));47
let outcome = Arc::new(Mutex::new(None));@@ -51,7 +51,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {51
..paperdoll_renderer::preview_gl::native_options()51
..paperdoll_renderer::preview_gl::native_options()52
};52
};53
eframe::run_native(53
eframe::run_native(54
"Paperdoll neck pivot probe",54
"Paperdoll auto pivot probe",55
options,55
options,56
Box::new(move |creation| {56
Box::new(move |creation| {57
let test = (|| -> Result<serde_json::Value, String> {57
let test = (|| -> Result<serde_json::Value, String> {@@ -64,9 +64,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {64
.join("tests/fixtures/bodies/test-body-male.glb"),64
.join("tests/fixtures/bodies/test-body-male.glb"),65
)?;65
)?;66
let resolved = camera::resolve(&body, CameraFraming::default());66
let resolved = camera::resolve(&body, CameraFraming::default());67
let neck_y = resolved.framing.pivot_y_milli.ok_or("nekpivot ontbreekt")?;67
let pivot_y = resolved68
if neck_y == CameraFraming::default().center_y_milli {68
.framing69
return Err("nekpivot mag niet gelijk zijn aan default centrum".into());69
.pivot_y_milli70
.ok_or("automatische pivot ontbreekt")?;71
if pivot_y == CameraFraming::default().center_y_milli {72
return Err(73
"automatische pivot mag niet gelijk zijn aan default centrum".into(),74
);70
}75
}71
let mut renderer = production::GpuRenderer::default();76
let mut renderer = production::GpuRenderer::default();72
let mut cache = paperdoll_renderer::equipment::TextureCache::default();77
let mut cache = paperdoll_renderer::equipment::TextureCache::default();@@ -87,26 +92,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {87
depth_range_milli: None,92
depth_range_milli: None,88
},93
},89
output: out.clone(),94
output: out.clone(),90
project_id: "neck-probe".into(),95
project_id: "auto-pivot-probe".into(),91
project_name: "Neck probe".into(),96
project_name: "Neck probe".into(),92
body_model: production::SourceFingerprint {97
body_model: production::SourceFingerprint {93
path: "assets/body/test-body-male.glb".into(),98
path: "assets/body/test-body-male.glb".into(),94
sha256: paperdoll_renderer::digest::sha256_hex(b"neck-probe-body"),99
sha256: paperdoll_renderer::digest::sha256_hex(b"auto-pivot-probe-body"),95
},100
},96
preset_sha256: None,101
preset_sha256: None,97
};102
};98
let old_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;103
let old_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;99
let old = unsafe { renderer.render(gl, &old_scene) }?;104
let old = unsafe { renderer.render(gl, &old_scene) }?;100
job.framing.pivot_y_milli = None;105
job.framing.pivot_y_milli = None;101
let neck_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;106
let pivot_scene = production::scene(&job, "walk", 0.0, pitch, yaw, &mut cache)?;102
let neck = unsafe { renderer.render(gl, &neck_scene) }?;107
let pivoted = unsafe { renderer.render(gl, &pivot_scene) }?;103
unsafe { renderer.destroy(gl) };108
unsafe { renderer.destroy(gl) };104
assert_eq!((old.width, old.height), (neck.width, neck.height));109
assert_eq!((old.width, old.height), (pivoted.width, pivoted.height));105
let mut changed = 0usize;110
let mut changed = 0usize;106
for (a, b) in old111
for (a, b) in old107
.diffuse112
.diffuse108
.chunks_exact(4)113
.chunks_exact(4)109
.zip(neck.diffuse.chunks_exact(4))114
.zip(pivoted.diffuse.chunks_exact(4))110
{115
{111
if a != b {116
if a != b {112
changed += 1;117
changed += 1;@@ -114,23 +119,23 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {114
}119
}115
if changed < 200 {120
if changed < 200 {116
return Err(format!(121
return Err(format!(117
"te weinig pixelverschil tussen centrum-pivot en nekpivot: {changed}"122
"te weinig pixelverschil tussen centrum-pivot en automatische pivot: {changed}"118
));123
));119
}124
}120
// Zero-pitch image center / feet framing must stay close after raising pivot.125
// Zero-pitch image center / feet framing must stay close after raising pivot.121
job.framing.pivot_y_milli = Some(1000);126
job.framing.pivot_y_milli = Some(1000);122
let old0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;127
let old0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;123
job.framing.pivot_y_milli = None;128
job.framing.pivot_y_milli = None;124
let neck0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;129
let pivot0 = production::scene(&job, "walk", 0.0, 0., 0., &mut cache)?;125
let old0b = unsafe {130
let old0b = unsafe {126
let mut r = production::GpuRenderer::default();131
let mut r = production::GpuRenderer::default();127
let b = r.render(gl, &old0)?;132
let b = r.render(gl, &old0)?;128
r.destroy(gl);133
r.destroy(gl);129
b134
b130
};135
};131
let neck0b = unsafe {136
let pivot0b = unsafe {132
let mut r = production::GpuRenderer::default();137
let mut r = production::GpuRenderer::default();133
let b = r.render(gl, &neck0)?;138
let b = r.render(gl, &pivot0)?;134
r.destroy(gl);139
r.destroy(gl);135
b140
b136
};141
};@@ -138,12 +143,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {138
let feet = ((old0b.height * 9 / 10) * old0b.width + old0b.width / 2) as usize;143
let feet = ((old0b.height * 9 / 10) * old0b.width + old0b.width / 2) as usize;139
let mid_delta = old0b.diffuse[mid * 4..mid * 4 + 4]144
let mid_delta = old0b.diffuse[mid * 4..mid * 4 + 4]140
.iter()145
.iter()141
.zip(&neck0b.diffuse[mid * 4..mid * 4 + 4])146
.zip(&pivot0b.diffuse[mid * 4..mid * 4 + 4])142
.map(|(a, b)| a.abs_diff(*b) as u32)147
.map(|(a, b)| a.abs_diff(*b) as u32)143
.sum::<u32>();148
.sum::<u32>();144
let feet_delta = old0b.diffuse[feet * 4..feet * 4 + 4]149
let feet_delta = old0b.diffuse[feet * 4..feet * 4 + 4]145
.iter()150
.iter()146
.zip(&neck0b.diffuse[feet * 4..feet * 4 + 4])151
.zip(&pivot0b.diffuse[feet * 4..feet * 4 + 4])147
.map(|(a, b)| a.abs_diff(*b) as u32)152
.map(|(a, b)| a.abs_diff(*b) as u32)148
.sum::<u32>();153
.sum::<u32>();149
write_rgba(154
write_rgba(@@ -153,10 +158,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {153
&old.diffuse,158
&old.diffuse,154
)?;159
)?;155
write_rgba(160
write_rgba(156
&out.join("neck-pivot-p30-y90.png"),161
&out.join("auto-pivot-p30-y90.png"),157
neck.width,162
pivoted.width,158
neck.height,163
pivoted.height,159
&neck.diffuse,164
&pivoted.diffuse,160
)?;165
)?;161
let contact_w = 256;166
let contact_w = 256;162
let contact_h = 192;167
let contact_h = 192;@@ -168,9 +173,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {168
contact_h,173
contact_h,169
);174
);170
let right = downsample(175
let right = downsample(171
&neck.diffuse,176
&pivoted.diffuse,172
neck.width,177
pivoted.width,173
neck.height,178
pivoted.height,174
contact_w / 2,179
contact_w / 2,175
contact_h,180
contact_h,176
);181
);@@ -185,7 +190,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {185
}190
}186
}191
}187
write_rgba(192
write_rgba(188
&out.join("neck-vs-center-contact.png"),193
&out.join("auto-vs-center-contact.png"),189
contact_w,194
contact_w,190
contact_h,195
contact_h,191
&contact,196
&contact,@@ -195,7 +200,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {195
"pitch": pitch,200
"pitch": pitch,196
"yaw": yaw,201
"yaw": yaw,197
"center_y_milli": 1000,202
"center_y_milli": 1000,198
"neck_y_milli": neck_y,203
"pivot_y_milli": pivot_y,199
"pivot_source": resolved.source,204
"pivot_source": resolved.source,200
"highres": [old.width, old.height],205
"highres": [old.width, old.height],201
"changed_pixels_pitch30": changed,206
"changed_pixels_pitch30": changed,@@ -203,16 +208,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {203
"zero_pitch_feet_channel_delta": feet_delta,208
"zero_pitch_feet_channel_delta": feet_delta,204
"artifacts": [209
"artifacts": [205
"center-pivot-p30-y90.png",210
"center-pivot-p30-y90.png",206
"neck-pivot-p30-y90.png",211
"auto-pivot-p30-y90.png",207
"neck-vs-center-contact.png"212
"auto-vs-center-contact.png"208
]213
]209
});214
});210
std::fs::write(215
std::fs::write(211
out.join("neck-pivot-probe.json"),216
out.join("auto-pivot-probe.json"),212
serde_json::to_vec_pretty(&report).unwrap(),217
serde_json::to_vec_pretty(&report).unwrap(),213
)218
)214
.map_err(|e| e.to_string())?;219
.map_err(|e| e.to_string())?;215
println!("NECK_PIVOT_PROBE {report}");220
println!("AUTO_PIVOT_PROBE {report}");216
Ok(report)221
Ok(report)217
})();222
})();218
*result.lock().unwrap() = Some(test);223
*result.lock().unwrap() = Some(test);