ColorSpaceNode.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import {
  2. GammaEncoding,
  3. LinearEncoding,
  4. sRGBEncoding
  5. } from '../../../../build/three.module.js';
  6. import { TempNode } from '../core/TempNode.js';
  7. import { FunctionNode } from '../core/FunctionNode.js';
  8. import { ExpressionNode } from '../core/ExpressionNode.js';
  9. class ColorSpaceNode extends TempNode {
  10. constructor( input, method ) {
  11. super( 'v4' );
  12. this.input = input;
  13. this.method = method || ColorSpaceNode.LINEAR_TO_LINEAR;
  14. }
  15. generate( builder, output ) {
  16. const input = this.input.build( builder, 'v4' );
  17. const outputType = this.getType( builder );
  18. const methodNode = ColorSpaceNode.Nodes[ this.method ];
  19. const method = builder.include( methodNode );
  20. if ( method === ColorSpaceNode.LINEAR_TO_LINEAR ) {
  21. return builder.format( input, outputType, output );
  22. } else {
  23. if ( methodNode.inputs.length === 2 ) {
  24. const factor = this.factor.build( builder, 'f' );
  25. return builder.format( method + '( ' + input + ', ' + factor + ' )', outputType, output );
  26. } else {
  27. return builder.format( method + '( ' + input + ' )', outputType, output );
  28. }
  29. }
  30. }
  31. fromEncoding( encoding ) {
  32. const components = ColorSpaceNode.getEncodingComponents( encoding );
  33. this.method = 'LinearTo' + components[ 0 ];
  34. this.factor = components[ 1 ];
  35. }
  36. fromDecoding( encoding ) {
  37. const components = ColorSpaceNode.getEncodingComponents( encoding );
  38. this.method = components[ 0 ] + 'ToLinear';
  39. this.factor = components[ 1 ];
  40. }
  41. copy( source ) {
  42. super.copy( source );
  43. this.input = source.input;
  44. this.method = source.method;
  45. return this;
  46. }
  47. toJSON( meta ) {
  48. let data = this.getJSONNode( meta );
  49. if ( ! data ) {
  50. data = this.createJSONNode( meta );
  51. data.input = this.input.toJSON( meta ).uuid;
  52. data.method = this.method;
  53. }
  54. return data;
  55. }
  56. }
  57. ColorSpaceNode.Nodes = ( function () {
  58. // 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/
  59. const LinearToLinear = new FunctionNode( /* glsl */`
  60. vec4 LinearToLinear( in vec4 value ) {
  61. return value;
  62. }`
  63. );
  64. const GammaToLinear = new FunctionNode( /* glsl */`
  65. vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {
  66. return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );
  67. }`
  68. );
  69. const LinearToGamma = new FunctionNode( /* glsl */`
  70. vec4 LinearToGamma( in vec4 value, in float gammaFactor ) {
  71. return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );
  72. }`
  73. );
  74. const sRGBToLinear = new FunctionNode( /* glsl */`
  75. vec4 sRGBToLinear( in vec4 value ) {
  76. 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.w );
  77. }`
  78. );
  79. const LinearTosRGB = new FunctionNode( /* glsl */`
  80. vec4 LinearTosRGB( in vec4 value ) {
  81. 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.w );
  82. }`
  83. );
  84. return {
  85. LinearToLinear: LinearToLinear,
  86. GammaToLinear: GammaToLinear,
  87. LinearToGamma: LinearToGamma,
  88. sRGBToLinear: sRGBToLinear,
  89. LinearTosRGB: LinearTosRGB
  90. };
  91. } )();
  92. ColorSpaceNode.LINEAR_TO_LINEAR = 'LinearToLinear';
  93. ColorSpaceNode.GAMMA_TO_LINEAR = 'GammaToLinear';
  94. ColorSpaceNode.LINEAR_TO_GAMMA = 'LinearToGamma';
  95. ColorSpaceNode.SRGB_TO_LINEAR = 'sRGBToLinear';
  96. ColorSpaceNode.LINEAR_TO_SRGB = 'LinearTosRGB';
  97. ColorSpaceNode.getEncodingComponents = function ( encoding ) {
  98. switch ( encoding ) {
  99. case LinearEncoding:
  100. return [ 'Linear' ];
  101. case sRGBEncoding:
  102. return [ 'sRGB' ];
  103. case GammaEncoding:
  104. return [ 'Gamma', new ExpressionNode( 'float( GAMMA_FACTOR )', 'f' ) ];
  105. }
  106. };
  107. ColorSpaceNode.prototype.nodeType = 'ColorSpace';
  108. ColorSpaceNode.prototype.hashProperties = [ 'method' ];
  109. export { ColorSpaceNode };