EncodingFunctions.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import CodeNode from '../core/CodeNode.js';
  2. import FunctionNode from '../core/FunctionNode.js';
  3. export const LinearToLinear = new FunctionNode( `
  4. vec4 ( in vec4 value ) {
  5. return value;
  6. }` );
  7. export const GammaToLinear = new FunctionNode( `
  8. vec4 ( in vec4 value, in float gammaFactor ) {
  9. return vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );
  10. }` );
  11. export const LinearToGamma = new FunctionNode( `
  12. vec4 ( in vec4 value, in float gammaFactor ) {
  13. return vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );
  14. }` );
  15. export const sRGBToLinear = new FunctionNode( `
  16. vec4 ( in vec4 value ) {
  17. 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 );
  18. }` );
  19. export const LinearTosRGB = new FunctionNode( `
  20. vec4 ( in vec4 value ) {
  21. 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 );
  22. }` );
  23. export const RGBEToLinear = new FunctionNode( `
  24. vec4 ( in vec4 value ) {
  25. return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );
  26. }` );
  27. export const LinearToRGBE = new FunctionNode( `
  28. vec4 ( in vec4 value ) {
  29. float maxComponent = max( max( value.r, value.g ), value.b );
  30. float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );
  31. return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );
  32. // return vec4( value.brg, ( 3.0 + 128.0 ) / 256.0 );
  33. }` );
  34. // reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
  35. export const RGBMToLinear = new FunctionNode( `
  36. vec4 ( in vec4 value, in float maxRange ) {
  37. return vec4( value.rgb * value.a * maxRange, 1.0 );
  38. }` );
  39. export const LinearToRGBM = new FunctionNode( `
  40. vec4 ( in vec4 value, in float maxRange ) {
  41. float maxRGB = max( value.r, max( value.g, value.b ) );
  42. float M = clamp( maxRGB / maxRange, 0.0, 1.0 );
  43. M = ceil( M * 255.0 ) / 255.0;
  44. return vec4( value.rgb / ( M * maxRange ), M );
  45. }` );
  46. // reference: http://iwasbeingirony.blogspot.ca/2010/06/difference-between-rgbm-and-rgbd.html
  47. export const RGBDToLinear = new FunctionNode( `
  48. vec4 ( in vec4 value, in float maxRange ) {
  49. return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );
  50. }` );
  51. export const LinearToRGBD = new FunctionNode( `
  52. vec4 ( in vec4 value, in float maxRange ) {
  53. float maxRGB = max( value.r, max( value.g, value.b ) );
  54. float D = max( maxRange / maxRGB, 1.0 );
  55. // NOTE: The implementation with min causes the shader to not compile on
  56. // a common Alcatel A502DL in Chrome 78/Android 8.1. Some research suggests
  57. // that the chipset is Mediatek MT6739 w/ IMG PowerVR GE8100 GPU.
  58. // D = min( floor( D ) / 255.0, 1.0 );
  59. D = clamp( floor( D ) / 255.0, 0.0, 1.0 );
  60. return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );
  61. }` );
  62. // LogLuv reference: http://graphicrants.blogspot.ca/2009/04/rgbm-color-encoding.html
  63. export const cLogLuvM = new CodeNode( 'const mat3 cLogLuvMNode = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );' );
  64. export const LinearToLogLuv = new FunctionNode( `
  65. vec4 ( in vec4 value ) {
  66. vec3 Xp_Y_XYZp = cLogLuvMNode * value.rgb;
  67. Xp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );
  68. vec4 vResult;
  69. vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
  70. float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
  71. vResult.w = fract( Le );
  72. vResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;
  73. return vResult;
  74. }` ).setIncludes( [ cLogLuvM ] );
  75. // Inverse M matrix, for decoding
  76. export const cLogLuvInverseM = new CodeNode( 'const mat3 cLogLuvInverseMNode = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );' );
  77. export const LogLuvToLinear = new FunctionNode( `
  78. vec4 ( in vec4 value ) {
  79. float Le = value.z * 255.0 + value.w;
  80. vec3 Xp_Y_XYZp;
  81. Xp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );
  82. Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;
  83. Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;
  84. vec3 vRGB = cLogLuvInverseMNode * Xp_Y_XYZp.rgb;
  85. return vec4( max( vRGB, 0.0 ), 1.0 );
  86. }` ).setIncludes( [ cLogLuvInverseM ] );