BlueGit

golden-age paperdoll-renderer

Files

paperdoll-renderer / examples / rim_compare.rs

rim_compare.rs

rim_compare.rs 4.4 KiB Download Raw
1//! Write with/without rim comparison PNGs for acceptance artifacts.
2use paperdoll_renderer::compositor::{
3 apply_rim, compose, relight, LayerMaps, Light, RimParams, DEFAULT_DEPTH_EDGE_SCALE,
4 DEFAULT_RIM_POWER,
5};
6use paperdoll_renderer::render_job::ImageBuf;
7use std::env;
8use std::path::PathBuf;
9
10fn encode_normal(n: [f32; 3]) -> [u8; 4] {
11 let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt().max(1e-10);
12 let n = [n[0] / len, n[1] / len, n[2] / len];
13 [
14 ((n[0] * 0.5 + 0.5) * 255.0).round() as u8,
15 ((n[1] * 0.5 + 0.5) * 255.0).round() as u8,
16 ((n[2] * 0.5 + 0.5) * 255.0).round() as u8,
17 255,
18 ]
19}
20
21fn sphere_layer(size: u32) -> LayerMaps {
22 let w = size as usize;
23 let mut diffuse = vec![0u8; w * w * 4];
24 let mut normal = vec![0u8; w * w * 4];
25 let mut specular = vec![0u8; w * w * 4];
26 let mut depth = vec![0u16; w * w * 2];
27 let cx = (size as f32 - 1.0) * 0.5;
28 let cy = cx;
29 let radius = cx * 0.92;
30 for y in 0..w {
31 for x in 0..w {
32 let i = y * w + x;
33 let dx = x as f32 - cx;
34 let dy = y as f32 - cy;
35 let r2 = dx * dx + dy * dy;
36 if r2 > radius * radius {
37 continue;
38 }
39 let nz = (1.0 - (r2 / (radius * radius))).sqrt();
40 let nx = dx / radius;
41 let ny = -dy / radius;
42 let n = encode_normal([nx, ny, nz]);
43 let o = i * 4;
44 // Warm albedo
45 diffuse[o] = 160;
46 diffuse[o + 1] = 90;
47 diffuse[o + 2] = 70;
48 diffuse[o + 3] = 255;
49 normal[o..o + 4].copy_from_slice(&n);
50 specular[o] = 40;
51 specular[o + 1] = 40;
52 specular[o + 2] = 40;
53 specular[o + 3] = 255;
54 // Nearer at center (smaller gray)
55 let gray = (5000.0 + (1.0 - nz) * 25000.0) as u16;
56 depth[i * 2] = gray;
57 depth[i * 2 + 1] = 65535;
58 }
59 }
60 LayerMaps {
61 label: "sphere".into(),
62 width: size,
63 height: size,
64 diffuse,
65 normal,
66 specular,
67 depth,
68 }
69}
70
71fn side_by_side(a: &ImageBuf, b: &ImageBuf) -> ImageBuf {
72 assert_eq!(a.width, b.width);
73 assert_eq!(a.height, b.height);
74 let w = a.width as usize;
75 let h = a.height as usize;
76 let out_w = w * 2 + 4;
77 let mut rgba = vec![30u8; out_w * h * 4];
78 for y in 0..h {
79 for x in 0..w {
80 let si = (y * w + x) * 4;
81 let dl = (y * out_w + x) * 4;
82 let dr = (y * out_w + (x + w + 4)) * 4;
83 rgba[dl..dl + 4].copy_from_slice(&a.rgba[si..si + 4]);
84 rgba[dr..dr + 4].copy_from_slice(&b.rgba[si..si + 4]);
85 }
86 }
87 ImageBuf {
88 width: out_w as u32,
89 height: a.height,
90 rgba,
91 }
92}
93
94fn main() -> Result<(), String> {
95 let out = PathBuf::from(
96 env::args()
97 .nth(1)
98 .unwrap_or_else(|| "/workspace/paperdoll-rim-artifacts".into()),
99 );
100 std::fs::create_dir_all(&out).map_err(|e| e.to_string())?;
101 let layer = sphere_layer(96);
102 let composed = compose(&[layer]).map_err(|e| e.to_string())?;
103 let light = Light::default();
104 let lit = relight(&composed, &light).map_err(|e| e.to_string())?;
105 let rimmed = apply_rim(
106 &composed,
107 &lit,
108 &RimParams {
109 intensity: 0.35,
110 power: DEFAULT_RIM_POWER,
111 depth_edge_weight: 0.25,
112 depth_edge_scale: DEFAULT_DEPTH_EDGE_SCALE,
113 },
114 )
115 .map_err(|e| e.to_string())?;
116 let off = apply_rim(&composed, &lit, &RimParams::off()).map_err(|e| e.to_string())?;
117 assert_eq!(off.rgba, lit.rgba);
118 let compare = side_by_side(&lit, &rimmed);
119 for (name, img) in [
120 ("rim_off.png", &lit),
121 ("rim_on.png", &rimmed),
122 ("rim_compare_off_vs_on.png", &compare),
123 ] {
124 let path = out.join(name);
125 let file = std::fs::File::create(&path).map_err(|e| e.to_string())?;
126 let mut encoder = png::Encoder::new(file, img.width, img.height);
127 encoder.set_color(png::ColorType::Rgba);
128 encoder.set_depth(png::BitDepth::Eight);
129 let mut writer = encoder.write_header().map_err(|e| e.to_string())?;
130 writer
131 .write_image_data(&img.rgba)
132 .map_err(|e| e.to_string())?;
133 writer.finish().map_err(|e| e.to_string())?;
134 }
135 // Bound check note
136 println!("wrote comparison PNGs under {}", out.display());
137 Ok(())
138}