EnvironmentNode.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import LightingNode from './LightingNode.js';
  2. import { cache } from '../core/CacheNode.js';
  3. import { context } from '../core/ContextNode.js';
  4. import { roughness, clearcoatRoughness } from '../core/PropertyNode.js';
  5. import { equirectUV } from '../utils/EquirectUVNode.js';
  6. import { specularMIPLevel } from '../utils/SpecularMIPLevelNode.js';
  7. import { cameraViewMatrix } from '../accessors/CameraNode.js';
  8. import { transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld } from '../accessors/NormalNode.js';
  9. import { positionViewDirection } from '../accessors/PositionNode.js';
  10. import { addNodeClass } from '../core/Node.js';
  11. import { float, vec2 } from '../shadernode/ShaderNode.js';
  12. import { cubeTexture } from '../accessors/CubeTextureNode.js';
  13. import { reference } from '../accessors/ReferenceNode.js';
  14. class EnvironmentNode extends LightingNode {
  15. constructor( envNode = null ) {
  16. super();
  17. this.envNode = envNode;
  18. }
  19. construct( builder ) {
  20. let envNode = this.envNode;
  21. const properties = builder.getNodeProperties( this );
  22. if ( envNode.isTextureNode && envNode.value.isCubeTexture !== true ) {
  23. const texture = envNode.value;
  24. const renderer = builder.renderer;
  25. // @TODO: Add dispose logic here
  26. const cubeRTT = builder.getCubeRenderTarget( 512 ).fromEquirectangularTexture( renderer, texture );
  27. envNode = cubeTexture( cubeRTT.texture );
  28. }
  29. //
  30. const intensity = reference( 'envMapIntensity', 'float', builder.material ); // @TODO: Add materialEnvIntensity in MaterialNode
  31. const radiance = context( envNode, createRadianceContext( roughness, transformedNormalView ) ).mul( intensity );
  32. const irradiance = context( envNode, createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity );
  33. const isolateRadiance = cache( radiance );
  34. //
  35. builder.context.radiance.addAssign( isolateRadiance );
  36. builder.context.iblIrradiance.addAssign( irradiance );
  37. //
  38. let isolateClearcoatRadiance = null;
  39. if ( builder.context.clearcoatRadiance  ) {
  40. const clearcoatRadiance = context( envNode, createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity );
  41. isolateClearcoatRadiance = cache( clearcoatRadiance );
  42. builder.context.clearcoatRadiance.addAssign( isolateClearcoatRadiance );
  43. }
  44. //
  45. properties.radiance = isolateRadiance;
  46. properties.clearcoatRadiance = isolateClearcoatRadiance;
  47. properties.irradiance = irradiance;
  48. }
  49. }
  50. const createRadianceContext = ( roughnessNode, normalViewNode ) => {
  51. let reflectVec = null;
  52. let textureUVNode = null;
  53. return {
  54. getUVNode: ( textureNode ) => {
  55. let node = null;
  56. if ( reflectVec === null ) {
  57. reflectVec = positionViewDirection.negate().reflect( normalViewNode );
  58. reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize();
  59. reflectVec = reflectVec.transformDirection( cameraViewMatrix );
  60. }
  61. if ( textureNode.isCubeTextureNode ) {
  62. node = reflectVec;
  63. } else if ( textureNode.isTextureNode ) {
  64. if ( textureUVNode === null ) {
  65. // @TODO: Needed PMREM
  66. textureUVNode = equirectUV( reflectVec );
  67. }
  68. node = textureUVNode;
  69. }
  70. return node;
  71. },
  72. getSamplerLevelNode: () => {
  73. return roughnessNode;
  74. },
  75. getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => {
  76. return specularMIPLevel( textureNode, levelNode );
  77. }
  78. };
  79. };
  80. const createIrradianceContext = ( normalWorldNode ) => {
  81. let textureUVNode = null;
  82. return {
  83. getUVNode: ( textureNode ) => {
  84. let node = null;
  85. if ( textureNode.isCubeTextureNode ) {
  86. node = normalWorldNode;
  87. } else if ( textureNode.isTextureNode ) {
  88. if ( textureUVNode === null ) {
  89. // @TODO: Needed PMREM
  90. textureUVNode = equirectUV( normalWorldNode );
  91. textureUVNode = vec2( textureUVNode.x, textureUVNode.y.oneMinus() );
  92. }
  93. node = textureUVNode;
  94. }
  95. return node;
  96. },
  97. getSamplerLevelNode: () => {
  98. return float( 1 );
  99. },
  100. getMIPLevelAlgorithmNode: ( textureNode, levelNode ) => {
  101. return specularMIPLevel( textureNode, levelNode );
  102. }
  103. };
  104. };
  105. export default EnvironmentNode;
  106. addNodeClass( EnvironmentNode );