mirror of
https://github.com/storytold/effectcraft.git
synced 2026-11-06 18:41:26 +00:00
HDR Highlight Compression: check the curve at Amount 25, 50 and 75 (#3123)
New After Effects 2026 renders of the same EXR at Amount 25, 50 and 75 (our own 1110-extra sample, 16-bit PNGs) confirm the transfer curve that was fitted at 84, 90 and 100. The worst channel error over all pixels is 4.0, 5.5 and 4.3 of 65535, against 997, 2415 and 3867 for the old soft knee. The code is unchanged. The measured-reference test now covers all six Amounts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
b9182972b2
commit
af7044d7db
1 file changed
+23
-13
@@ -68,7 +68,7 @@ fn hdr_spow(v: f32, e: f32) -> f32 {
|
||||
/// One straight-colour pixel through HDR Highlight Compression at blend `t` (Amount / 100, > 0).
|
||||
///
|
||||
/// Measured behaviour (16-bit renders of a 0–4 HDR ramp and coloured patches at Amount 100,
|
||||
/// 90 and 84): every channel is divided by `1 + Y` (`Y` = 0.30 R + 0.59 G + 0.11 B, so a grey
|
||||
/// 90, 84, 75, 50 and 25): every channel is divided by `1 + Y` (`Y` = 0.30 R + 0.59 G + 0.11 B, so a grey
|
||||
/// value `x` lands on `x / (1 + x)`), clipped at 1, then mixed with the input as `x^0.4` values.
|
||||
fn hdr_compress_pixel(c: [f32; 3], t: f32) -> [f32; 3] {
|
||||
let y = (HDR_LUMA[0] * c[0] + HDR_LUMA[1] * c[1] + HDR_LUMA[2] * c[2]).max(0.0);
|
||||
@@ -600,26 +600,36 @@ mod tests {
|
||||
}
|
||||
|
||||
/// Our own measurements of After Effects 2026 (32 bpc, no working space; 16-bit PNG renders
|
||||
/// decoded back to linear): input pixel, then the output at Amount 100, 90 and 84.
|
||||
/// decoded back to linear): input pixel, then the output at Amount 100, 90, 84, 75, 50 and 25.
|
||||
#[test]
|
||||
fn hdr_compression_matches_measured_reference() {
|
||||
const AMOUNTS: [f64; 6] = [100.0, 90.0, 84.0, 75.0, 50.0, 25.0];
|
||||
#[rustfmt::skip]
|
||||
let table: [([f32; 3], [[f32; 3]; 3]); 9] = [
|
||||
([0.18005371; 3], [[0.1524; 3], [0.1550; 3], [0.1566; 3]]),
|
||||
([0.49365234; 3], [[0.3302; 3], [0.3450; 3], [0.3540; 3]]),
|
||||
([1.0058594; 3], [[0.5014; 3], [0.5427; 3], [0.5683; 3]]),
|
||||
([2.0058594; 3], [[0.6673; 3], [0.7637; 3], [0.8256; 3]]),
|
||||
([2.9941406; 3], [[0.7496; 3], [0.8962; 3], [0.9922; 3]]),
|
||||
([3.9941406; 3], [[0.7998; 3], [0.9929; 3], [1.1213; 3]]),
|
||||
([0.7998047, 0.099975586, 0.099975586], [[0.6101, 0.0762, 0.0762], [0.6279, 0.0784, 0.0784], [0.6386, 0.0798, 0.0798]]),
|
||||
([0.099975586, 0.7001953, 0.19995117], [[0.0681, 0.4776, 0.1363], [0.0711, 0.4976, 0.1420], [0.0727, 0.5097, 0.1456]]),
|
||||
([0.30004883, 0.5, 2.5], [[0.1807, 0.3012, 0.9998], [0.1911, 0.3184, 1.1147], [0.1972, 0.3288, 1.1860]]),
|
||||
let table: [([f32; 3], [[f32; 3]; 6]); 9] = [
|
||||
([0.18005371; 3], [[0.1524; 3], [0.1550; 3], [0.1566; 3], [0.1590; 3], [0.1660; 3], [0.1729; 3]]),
|
||||
([0.49365234; 3], [[0.3302; 3], [0.3450; 3], [0.3540; 3], [0.3674; 3], [0.4073; 3], [0.4492; 3]]),
|
||||
([1.0058594; 3], [[0.5014; 3], [0.5427; 3], [0.5683; 3], [0.6085; 3], [0.7280; 3], [0.8602; 3]]),
|
||||
([2.0058594; 3], [[0.6673; 3], [0.7637; 3], [0.8256; 3], [0.9232; 3], [1.2292; 3], [1.5892; 3]]),
|
||||
([2.9941406; 3], [[0.7496; 3], [0.8962; 3], [0.9922; 3], [1.1465; 3], [1.6475; 3], [2.2604; 3]]),
|
||||
([3.9941406; 3], [[0.7998; 3], [0.9929; 3], [1.1213; 3], [1.3303; 3], [2.0312; 3], [2.9141; 3]]),
|
||||
([0.7998047, 0.099975586, 0.099975586], [
|
||||
[0.6101, 0.0762, 0.0762], [0.6279, 0.0784, 0.0784], [0.6386, 0.0798, 0.0798],
|
||||
[0.6547, 0.0817, 0.0817], [0.7012, 0.0877, 0.0877], [0.7496, 0.0937, 0.0937],
|
||||
]),
|
||||
([0.099975586, 0.7001953, 0.19995117], [
|
||||
[0.0681, 0.4776, 0.1363], [0.0711, 0.4976, 0.1420], [0.0727, 0.5097, 0.1456],
|
||||
[0.0754, 0.5287, 0.1508], [0.0832, 0.5829, 0.1662], [0.0912, 0.6397, 0.1825],
|
||||
]),
|
||||
([0.30004883, 0.5, 2.5], [
|
||||
[0.1807, 0.3012, 0.9998], [0.1911, 0.3184, 1.1147], [0.1972, 0.3288, 1.1860],
|
||||
[0.2071, 0.3453, 1.2995], [0.2359, 0.3931, 1.6484], [0.2669, 0.4444, 2.0482],
|
||||
]),
|
||||
];
|
||||
let mut img = Image::new(table.len() as u32, 1);
|
||||
for (x, (c, _)) in table.iter().enumerate() {
|
||||
img.set(x as u32, 0, [c[0], c[1], c[2], 1.0]);
|
||||
}
|
||||
for (i, amount) in [100.0, 90.0, 84.0].into_iter().enumerate() {
|
||||
for (i, amount) in AMOUNTS.into_iter().enumerate() {
|
||||
let out = run("ec.utility.hdrcompression", &[("amount", num(amount))], img.clone());
|
||||
for (x, (input, want)) in table.iter().enumerate() {
|
||||
let got = out.img.data[x];
|
||||
|
||||
Reference in new issue
Block a user