export default /* glsl */` // For a discussion of what this is, please read this: http://lousodrome.net/blog/light/2013/05/26/gamma-correct-and-hdr-rendering-in-a-32-bits-buffer/ vec4 LinearToLinear( in vec4 value ) { return value; } vec4 GammaToLinear( in vec4 value, in float gammaFactor ) { return vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a ); } vec4 LinearToGamma( in vec4 value, in float gammaFactor ) { return vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a ); } vec4 sRGBToLinear( in vec4 value ) { return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a ); } vec4 LinearTosRGB( in vec4 value ) { return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); } vec4 RGBEToLinear( in vec4 value ) { return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 ); } vec4 LinearToRGBE( in vec4 value ) { float maxComponent = max( max( value.r, value.g ), value.b ); float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 ); return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 ); // return vec4( value.brg, ( 3.0 + 128.0 ) / 256.0 ); } // reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html vec4 RGBMToLinear( in vec4 value, in float maxRange ) { return vec4( value.rgb * value.a * maxRange, 1.0 ); } vec4 LinearToRGBM( in vec4 value, in float maxRange ) { float maxRGB = max( value.r, max( value.g, value.b ) ); float M = clamp( maxRGB / maxRange, 0.0, 1.0 ); M = ceil( M * 255.0 ) / 255.0; return vec4( value.rgb / ( M * maxRange ), M ); } // reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html vec4 RGBDToLinear( in vec4 value, in float maxRange ) { return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 ); } vec4 LinearToRGBD( in vec4 value, in float maxRange ) { float maxRGB = max( value.r, max( value.g, value.b ) ); float D = max( maxRange / maxRGB, 1.0 ); // NOTE: The implementation with min causes the shader to not compile on // a common Alcatel A502DL in Chrome 78/Android 8.1. Some research suggests // that the chipset is Mediatek MT6739 w/ IMG PowerVR GE8100 GPU. // D = min( floor( D ) / 255.0, 1.0 ); D = clamp( floor( D ) / 255.0, 0.0, 1.0 ); return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D ); } // LogLuv reference: http://graphicrants.blogspot.ca/2009/04/rgbm-color-encoding.html // M matrix, for encoding const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 ); vec4 LinearToLogLuv( in vec4 value ) { vec3 Xp_Y_XYZp = cLogLuvM * value.rgb; Xp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) ); vec4 vResult; vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z; float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0; vResult.w = fract( Le ); vResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0; return vResult; } // Inverse M matrix, for decoding const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 ); vec4 LogLuvToLinear( in vec4 value ) { float Le = value.z * 255.0 + value.w; vec3 Xp_Y_XYZp; Xp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 ); Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y; Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z; vec3 vRGB = cLogLuvInverseM * Xp_Y_XYZp.rgb; return vec4( max( vRGB, 0.0 ), 1.0 ); } `;