public bool Invert(out tMat3x3 result) { result = default; // calculate the minors for the first row var minor00 = this[1, 1] * this[2, 2] - this[1, 2] * this[2, 1]; var minor01 = this[1, 2] * this[2, 0] - this[1, 0] * this[2, 2]; var minor02 = this[1, 0] * this[2, 1] - this[1, 1] * this[2, 0]; // calculate the determinant var determinant = this[0, 0] * minor00 + this[0, 1] * minor01 + this[0, 2] * minor02; // check if the input is a singular matrix (non-invertable) // (note that the epsilon here was arbitrarily chosen) if (determinant > -0.000001f && determinant < 0.000001f) { return(false); } // the inverse of inMat is (1 / determinant) * adjoint(inMat) var invDet = 1.0f / determinant; result[0, 0] = invDet * minor00; result[0, 1] = invDet * (this[2, 1] * this[0, 2] - this[2, 2] * this[0, 1]); result[0, 2] = invDet * (this[0, 1] * this[1, 2] - this[0, 2] * this[1, 1]); result[1, 0] = invDet * minor01; result[1, 1] = invDet * (this[2, 2] * this[0, 0] - this[2, 0] * this[0, 2]); result[1, 2] = invDet * (this[0, 2] * this[1, 0] - this[0, 0] * this[1, 2]); result[2, 0] = invDet * minor02; result[2, 1] = invDet * (this[2, 0] * this[0, 1] - this[2, 1] * this[0, 0]); result[2, 2] = invDet * (this[0, 0] * this[1, 1] - this[0, 1] * this[1, 0]); return(true); }
/// <summary> /// Convert a linear sRGB color to an sRGB color /// </summary> public static tMat3x3 CalcColorSpaceConversion_RGB_to_XYZ ( tVec2 red_xy, // xy chromaticity coordinates of the red primary tVec2 green_xy, // xy chromaticity coordinates of the green primary tVec2 blue_xy, // xy chromaticity coordinates of the blue primary tVec2 white_xy // xy chromaticity coordinates of the white point ) { tMat3x3 pOutput = new tMat3x3(); // generate xyz chromaticity coordinates (x + y + z = 1) from xy coordinates tVec3 r = new tVec3(red_xy.X, red_xy.Y, 1.0f - (red_xy.X + red_xy.Y)); tVec3 g = new tVec3(green_xy.X, green_xy.Y, 1.0f - (green_xy.X + green_xy.Y)); tVec3 b = new tVec3(blue_xy.X, blue_xy.Y, 1.0f - (blue_xy.X + blue_xy.Y)); tVec3 w = new tVec3(white_xy.X, white_xy.Y, 1.0f - (white_xy.X + white_xy.Y)); // Convert white xyz coordinate to XYZ coordinate by letting that the white // point have and XYZ relative luminance of 1.0. Relative luminance is the Y // component of and XYZ color. // XYZ = xyz * (Y / y) w.X /= white_xy.Y; w.Y /= white_xy.Y; w.Z /= white_xy.Y; // Solve for the transformation matrix 'M' from RGB to XYZ // * We know that the columns of M are equal to the unknown XYZ values of r, g and b. // * We know that the XYZ values of r, g and b are each a scaled version of the known // corresponding xyz chromaticity values. // * We know the XYZ value of white based on its xyz value and the assigned relative // luminance of 1.0. // * We know the RGB value of white is (1,1,1). // // white_XYZ = M * white_RGB // // [r.x g.x b.x] // N = [r.y g.y b.y] // [r.z g.z b.z] // // [sR 0 0 ] // S = [0 sG 0 ] // [0 0 sB] // // M = N * S // white_XYZ = N * S * white_RGB // N^-1 * white_XYZ = S * white_RGB = (sR,sG,sB) // // We now have an equation for the components of the scale matrix 'S' and // can compute 'M' from 'N' and 'S' pOutput.SetCol(0, r); pOutput.SetCol(1, g); pOutput.SetCol(2, b); pOutput.Invert(out tMat3x3 invMat); tVec3 scale = invMat * w; pOutput[0, 0] *= scale.X; pOutput[1, 0] *= scale.X; pOutput[2, 0] *= scale.X; pOutput[0, 1] *= scale.Y; pOutput[1, 1] *= scale.Y; pOutput[2, 1] *= scale.Y; pOutput[0, 2] *= scale.Z; pOutput[1, 2] *= scale.Z; pOutput[2, 2] *= scale.Z; return(pOutput); }