Skip to content

Instantly share code, notes, and snippets.

@damywise
Created November 29, 2023 02:56
Show Gist options
  • Save damywise/a8131a6c300953f2ee7a6483b2b8aa72 to your computer and use it in GitHub Desktop.
Save damywise/a8131a6c300953f2ee7a6483b2b8aa72 to your computer and use it in GitHub Desktop.
const m1 = 0.1593017578125;
const m2 = 78.84375;
const c1 = 0.8359375;
const c2 = 18.851525;
const c3 = 18.6875;
double inversePq(double n) {
final top = max(
pow(n, 1 / m2) - c1,
0,
);
final bottom = c2 - c3 * pow(n, 1 / m2);
final result = pow(top / bottom, 1 / m1).toDouble();
return result * 10000 / 203;
}
void applyInversePq(Float32List data) {
for (var i = 0; i < data.length; i += 3) {
data[i] = inversePq(data[i]);
data[i + 1] = inversePq(data[i + 1]);
data[i + 2] = inversePq(data[i + 2]);
}
}
// srgb
final srgbXyzMatrix = Matrix3(
0.4124564,
0.3575761,
0.1804375,
0.2126729,
0.7151522,
0.0721750,
0.0193339,
0.1191920,
0.9503041,
);
// prophoto rgb
final prophotoRgbToXyzMatrix = Matrix3(
0.7976749,
0.1351917,
0.0313534,
0.2880402,
0.7118741,
0.0000857,
0.0000000,
0.0000000,
0.8252100,
);
Matrix3 get rgbToXyzMatrix => prophotoRgbToXyzMatrix.clone();
Matrix3 get inverseRgbToXyzMatrix => prophotoRgbToXyzMatrix.clone()..invert();
Vector3 rgbToXyz(Vector3 rgb) {
return rgbToXyzMatrix.clone() * rgb;
}
Vector3 xyzToRgb(Vector3 xyz) {
return inverseRgbToXyzMatrix.clone() * xyz;
}
Vector3 XYZ_to_xyY(Vector3 XYZ) {
double X = XYZ.x;
double Y = XYZ.y;
double Z = XYZ.z;
double divisor = X + Y + Z;
if (divisor == 0.0) divisor = 1e-6;
double x = X / divisor;
double y = Y / divisor;
return Vector3(x, y, Y);
}
Vector3 xyY_to_XYZ(Vector3 xyY) {
double x = xyY.x;
double y = xyY.y;
double Y = xyY.z;
double multiplo = Y / max(y, 1e-6);
double z = 1.0 - x - y;
double X = x * multiplo;
double Z = z * multiplo;
return Vector3(X, Y, Z);
}
const double ip = 0.58535; // linear length
const double k1 = 0.83802; // linear strength
const double k3 = 0.74204; // shoulder strength
double f2(double Y, double k1, double k3, double ip) {
ip /= k1;
double k2 = (k1 * ip) * (1.0 - k3);
double k4 = (k1 * ip) - (k2 * log(1.0 - k3));
return Y < ip ? Y * k1 : log((Y / ip) - k3) * k2 + k4;
}
double tonemapping(double x) {
const double over_white = 1019.0 / 940.0; // 109% range (super-whites)
return f2(x, k1, k3, ip) / over_white;
}
double gamma2_2(double value) {
return value > 0 ? pow(value, 2.2).toDouble() : 0;
}
void applyGamma(Float32List data) {
for (var i = 0; i < data.length; i += 3) {
data[i] = gamma2_2(data[i]);
data[i + 1] = gamma2_2(data[i + 1]);
data[i + 2] = gamma2_2(data[i + 2]);
}
}
void applyHdrToSdrTonemap(Float32List data) {
applyInversePq(data);
for (var i = 0; i < data.length; i += 3) {
final r = data[i];
final g = data[i + 1];
final b = data[i + 2];
var color = Vector3(r, g, b);
color = rgbToXyz(color);
color = XYZ_to_xyY(color);
color = Vector3(color.x, color.y, tonemapping(color.z));
color = xyY_to_XYZ(color);
color = xyzToRgb(color);
data[i] = color.x;
data[i + 1] = color.y;
data[i + 2] = color.z;
}
applyGamma(data);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment