EnvironmentNode.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import LightingNode from './LightingNode.js';
  2. import { cache } from '../core/CacheNode.js';
  3. import { roughness, clearcoatRoughness } from '../core/PropertyNode.js';
  4. import { cameraViewMatrix } from '../accessors/Camera.js';
  5. import { transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld } from '../accessors/Normal.js';
  6. import { positionViewDirection } from '../accessors/Position.js';
  7. import { float } from '../tsl/TSLBase.js';
  8. import { reference } from '../accessors/ReferenceNode.js';
  9. import { transformedBentNormalView } from '../accessors/AccessorsUtils.js';
  10. import { pmremTexture } from '../pmrem/PMREMNode.js';
  11. const _envNodeCache = new WeakMap();
  12. /**
  13. * Represents a physical model for Image-based lighting (IBL). The environment
  14. * is defined via environment maps in the equirectangular, cube map or cubeUV (PMREM) format.
  15. * `EnvironmentNode` is intended for PBR materials like {@link MeshStandardNodeMaterial}.
  16. *
  17. * @augments LightingNode
  18. */
  19. class EnvironmentNode extends LightingNode {
  20. static get type() {
  21. return 'EnvironmentNode';
  22. }
  23. /**
  24. * Constructs a new environment node.
  25. *
  26. * @param {Node} [envNode=null] - A node representing the environment.
  27. */
  28. constructor( envNode = null ) {
  29. super();
  30. /**
  31. * A node representing the environment.
  32. *
  33. * @type {?Node}
  34. * @default null
  35. */
  36. this.envNode = envNode;
  37. }
  38. setup( builder ) {
  39. const { material } = builder;
  40. let envNode = this.envNode;
  41. if ( envNode.isTextureNode || envNode.isMaterialReferenceNode ) {
  42. const value = ( envNode.isTextureNode ) ? envNode.value : material[ envNode.property ];
  43. let cacheEnvNode = _envNodeCache.get( value );
  44. if ( cacheEnvNode === undefined ) {
  45. cacheEnvNode = pmremTexture( value );
  46. _envNodeCache.set( value, cacheEnvNode );
  47. }
  48. envNode = cacheEnvNode;
  49. }
  50. //
  51. const envMap = material.envMap;
  52. const intensity = envMap ? reference( 'envMapIntensity', 'float', builder.material ) : reference( 'environmentIntensity', 'float', builder.scene ); // @TODO: Add materialEnvIntensity in MaterialNode
  53. const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0;
  54. const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView;
  55. const radiance = envNode.context( createRadianceContext( roughness, radianceNormalView ) ).mul( intensity );
  56. const irradiance = envNode.context( createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity );
  57. const isolateRadiance = cache( radiance );
  58. const isolateIrradiance = cache( irradiance );
  59. //
  60. builder.context.radiance.addAssign( isolateRadiance );
  61. builder.context.iblIrradiance.addAssign( isolateIrradiance );
  62. //
  63. const clearcoatRadiance = builder.context.lightingModel.clearcoatRadiance;
  64. if ( clearcoatRadiance ) {
  65. const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity );
  66. const isolateClearcoatRadiance = cache( clearcoatRadianceContext );
  67. clearcoatRadiance.addAssign( isolateClearcoatRadiance );
  68. }
  69. }
  70. }
  71. export default EnvironmentNode;
  72. const createRadianceContext = ( roughnessNode, normalViewNode ) => {
  73. let reflectVec = null;
  74. return {
  75. getUV: () => {
  76. if ( reflectVec === null ) {
  77. reflectVec = positionViewDirection.negate().reflect( normalViewNode );
  78. // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
  79. reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize();
  80. reflectVec = reflectVec.transformDirection( cameraViewMatrix );
  81. }
  82. return reflectVec;
  83. },
  84. getTextureLevel: () => {
  85. return roughnessNode;
  86. }
  87. };
  88. };
  89. const createIrradianceContext = ( normalWorldNode ) => {
  90. return {
  91. getUV: () => {
  92. return normalWorldNode;
  93. },
  94. getTextureLevel: () => {
  95. return float( 1.0 );
  96. }
  97. };
  98. };
粤ICP备19079148号