public void Invert() { float fDet = Determinant(); if ( (float) System.Math.Abs(fDet) < float.Epsilon ) throw new Exception( "Matrix is not invertible!" ); // The matrix is not invertible! Singular case! float fIDet = 1.0f / fDet; float4x4 Temp = new float4x4(); Temp[0, 0] = CoFactor( 0, 0 ) * fIDet; Temp[1, 0] = CoFactor( 0, 1 ) * fIDet; Temp[2, 0] = CoFactor( 0, 2 ) * fIDet; Temp[3, 0] = CoFactor( 0, 3 ) * fIDet; Temp[0, 1] = CoFactor( 1, 0 ) * fIDet; Temp[1, 1] = CoFactor( 1, 1 ) * fIDet; Temp[2, 1] = CoFactor( 1, 2 ) * fIDet; Temp[3, 1] = CoFactor( 1, 3 ) * fIDet; Temp[0, 2] = CoFactor( 2, 0 ) * fIDet; Temp[1, 2] = CoFactor( 2, 1 ) * fIDet; Temp[2, 2] = CoFactor( 2, 2 ) * fIDet; Temp[3, 2] = CoFactor( 2, 3 ) * fIDet; Temp[0, 3] = CoFactor( 3, 0 ) * fIDet; Temp[1, 3] = CoFactor( 3, 1 ) * fIDet; Temp[2, 3] = CoFactor( 3, 2 ) * fIDet; Temp[3, 3] = CoFactor( 3, 3 ) * fIDet; row0 = Temp.row0; row1 = Temp.row1; row2 = Temp.row2; row3 = Temp.row3; }
/// <summary> /// Builds the RGB<->XYZ transforms from chromaticities /// (refer to http://wiki.nuaj.net/index.php/Color_Transforms#XYZ_Matrices for explanations) /// </summary> protected void BuildTransformFromChroma( bool _bCheckGammaCurveOverride ) { float3 xyz_R = new float3( m_Chromaticities.R.x, m_Chromaticities.R.y, 1.0f - m_Chromaticities.R.x - m_Chromaticities.R.y ); float3 xyz_G = new float3( m_Chromaticities.G.x, m_Chromaticities.G.y, 1.0f - m_Chromaticities.G.x - m_Chromaticities.G.y ); float3 xyz_B = new float3( m_Chromaticities.B.x, m_Chromaticities.B.y, 1.0f - m_Chromaticities.B.x - m_Chromaticities.B.y ); float3 XYZ_W = xyY2XYZ( new float3( m_Chromaticities.W.x, m_Chromaticities.W.y, 1.0f ) ); float4x4 M_xyz = new float4x4() { row0 = new float4( xyz_R, 0.0f ), row1 = new float4( xyz_G, 0.0f ), row2 = new float4( xyz_B, 0.0f ), row3 = new float4( 0.0f, 0.0f, 0.0f, 1.0f ) }; M_xyz.Invert(); float4 Sum_RGB = new float4( XYZ_W, 1.0f ) * M_xyz; // Finally, we can retrieve the RGB->XYZ transform m_RGB2XYZ.row0 = new float4( Sum_RGB.x * xyz_R, 0.0f ); m_RGB2XYZ.row1 = new float4( Sum_RGB.y * xyz_G, 0.0f ); m_RGB2XYZ.row2 = new float4( Sum_RGB.z * xyz_B, 0.0f ); // And the XYZ->RGB transform m_XYZ2RGB = m_RGB2XYZ; m_XYZ2RGB.Invert(); // ============= Attempt to recognize a standard profile ============= STANDARD_PROFILE RecognizedChromaticity = m_Chromaticities.RecognizedChromaticity; if ( _bCheckGammaCurveOverride ) { // Also ensure the gamma ramp is correct before assigning a standard profile bool bIsGammaCorrect = true; switch ( RecognizedChromaticity ) { case STANDARD_PROFILE.sRGB: bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.sRGB, GAMMA_EXPONENT_sRGB ); break; case STANDARD_PROFILE.ADOBE_RGB_D50: bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.STANDARD, GAMMA_EXPONENT_ADOBE ); break; case STANDARD_PROFILE.ADOBE_RGB_D65: bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.STANDARD, GAMMA_EXPONENT_ADOBE ); break; case STANDARD_PROFILE.PRO_PHOTO: bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.PRO_PHOTO, GAMMA_EXPONENT_PRO_PHOTO ); break; case STANDARD_PROFILE.RADIANCE: bIsGammaCorrect = EnsureGamma( GAMMA_CURVE.STANDARD, 1.0f ); break; } if ( !bIsGammaCorrect ) RecognizedChromaticity = STANDARD_PROFILE.CUSTOM; // A non-standard gamma curves fails our pre-defined design... } // ============= Assign the internal converter depending on the profile ============= switch ( RecognizedChromaticity ) { case STANDARD_PROFILE.sRGB: m_GammaCurve = GAMMA_CURVE.sRGB; m_Gamma = GAMMA_EXPONENT_sRGB; m_InternalConverter = new InternalColorConverter_sRGB(); break; case STANDARD_PROFILE.ADOBE_RGB_D50: m_GammaCurve = GAMMA_CURVE.STANDARD; m_Gamma = GAMMA_EXPONENT_ADOBE; m_InternalConverter = new InternalColorConverter_AdobeRGB_D50(); break; case STANDARD_PROFILE.ADOBE_RGB_D65: m_GammaCurve = GAMMA_CURVE.STANDARD; m_Gamma = GAMMA_EXPONENT_ADOBE; m_InternalConverter = new InternalColorConverter_AdobeRGB_D65(); break; case STANDARD_PROFILE.PRO_PHOTO: m_GammaCurve = GAMMA_CURVE.PRO_PHOTO; m_Gamma = GAMMA_EXPONENT_PRO_PHOTO; m_InternalConverter = new InternalColorConverter_ProPhoto(); break; case STANDARD_PROFILE.RADIANCE: m_GammaCurve = GAMMA_CURVE.STANDARD; m_Gamma = 1.0f; m_InternalConverter = new InternalColorConverter_Radiance(); break; default: // Switch to one of our generic converters switch ( m_GammaCurve ) { case GAMMA_CURVE.sRGB: m_InternalConverter = new InternalColorConverter_Generic_sRGBGamma( m_RGB2XYZ, m_XYZ2RGB ); break; case GAMMA_CURVE.PRO_PHOTO: m_InternalConverter = new InternalColorConverter_Generic_ProPhoto( m_RGB2XYZ, m_XYZ2RGB ); break; case GAMMA_CURVE.STANDARD: if ( Math.Abs( m_Gamma - 1.0f ) < 1e-3f ) m_InternalConverter = new InternalColorConverter_Generic_NoGamma( m_RGB2XYZ, m_XYZ2RGB ); else m_InternalConverter = new InternalColorConverter_Generic_StandardGamma( m_RGB2XYZ, m_XYZ2RGB, m_Gamma ); break; } break; } }
public InternalColorConverter_Generic_sRGBGamma( float4x4 _RGB2XYZ, float4x4 _XYZ2RGB ) { m_RGB2XYZ = _RGB2XYZ; m_XYZ2RGB = _XYZ2RGB; }
public InternalColorConverter_Generic_StandardGamma( float4x4 _RGB2XYZ, float4x4 _XYZ2RGB, float _Gamma ) { m_RGB2XYZ = _RGB2XYZ; m_XYZ2RGB = _XYZ2RGB; m_Gamma = _Gamma; m_InvGamma = 1.0f / _Gamma; }
public InternalColorConverter_Generic_ProPhoto( float4x4 _RGB2XYZ, float4x4 _XYZ2RGB ) { m_RGB2XYZ = _RGB2XYZ; m_XYZ2RGB = _XYZ2RGB; }