PMREMNode.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import TempNode from '../core/TempNode.js';
  2. import { addNodeClass } from '../core/Node.js';
  3. import { texture } from '../accessors/TextureNode.js';
  4. import { textureCubeUV } from './PMREMUtils.js';
  5. import { uniform } from '../core/UniformNode.js';
  6. import { NodeUpdateType } from '../core/constants.js';
  7. import { nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
  8. import { WebGLCoordinateSystem } from 'three';
  9. let _generator = null;
  10. const _cache = new WeakMap();
  11. function _generateCubeUVSize( imageHeight ) {
  12. const maxMip = Math.log2( imageHeight ) - 2;
  13. const texelHeight = 1.0 / imageHeight;
  14. const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );
  15. return { texelWidth, texelHeight, maxMip };
  16. }
  17. function _getPMREMFromTexture( texture ) {
  18. let cacheTexture = _cache.get( texture );
  19. const pmremVersion = cacheTexture !== undefined ? cacheTexture.pmremVersion : - 1;
  20. if ( pmremVersion !== texture.pmremVersion ) {
  21. if ( texture.isCubeTexture ) {
  22. if ( texture.source.data.some( ( texture ) => texture === undefined ) ) {
  23. throw new Error( 'PMREMNode: Undefined texture in CubeTexture. Use onLoad callback or async loader' );
  24. }
  25. cacheTexture = _generator.fromCubemap( texture, cacheTexture );
  26. } else {
  27. if ( texture.image === undefined ) {
  28. throw new Error( 'PMREMNode: Undefined image in Texture. Use onLoad callback or async loader' );
  29. }
  30. cacheTexture = _generator.fromEquirectangular( texture, cacheTexture );
  31. }
  32. cacheTexture.pmremVersion = texture.pmremVersion;
  33. _cache.set( texture, cacheTexture );
  34. }
  35. return cacheTexture.texture;
  36. }
  37. class PMREMNode extends TempNode {
  38. constructor( value, uvNode = null, levelNode = null ) {
  39. super( 'vec3' );
  40. this._value = value;
  41. this._pmrem = null;
  42. this.uvNode = uvNode;
  43. this.levelNode = levelNode;
  44. this._generator = null;
  45. this._texture = texture( null );
  46. this._width = uniform( 0 );
  47. this._height = uniform( 0 );
  48. this._maxMip = uniform( 0 );
  49. this.updateBeforeType = NodeUpdateType.RENDER;
  50. }
  51. set value( value ) {
  52. this._value = value;
  53. this._pmrem = null;
  54. }
  55. get value() {
  56. return this._value;
  57. }
  58. updateFromTexture( texture ) {
  59. const cubeUVSize = _generateCubeUVSize( texture.image.height );
  60. this._texture.value = texture;
  61. this._width.value = cubeUVSize.texelWidth;
  62. this._height.value = cubeUVSize.texelHeight;
  63. this._maxMip.value = cubeUVSize.maxMip;
  64. }
  65. updateBefore() {
  66. let pmrem = this._pmrem;
  67. const pmremVersion = pmrem ? pmrem.pmremVersion : - 1;
  68. const texture = this._value;
  69. if ( pmremVersion !== texture.pmremVersion ) {
  70. if ( texture.isPMREMTexture === true ) {
  71. pmrem = texture;
  72. } else {
  73. pmrem = _getPMREMFromTexture( texture );
  74. }
  75. this._pmrem = pmrem;
  76. this.updateFromTexture( pmrem );
  77. }
  78. }
  79. setup( builder ) {
  80. if ( _generator === null ) {
  81. _generator = builder.createPMREMGenerator();
  82. }
  83. //
  84. this.updateBefore( builder );
  85. //
  86. let uvNode = this.uvNode;
  87. if ( uvNode === null && builder.context.getUV ) {
  88. uvNode = builder.context.getUV( this );
  89. }
  90. //
  91. const texture = this.value;
  92. if ( builder.renderer.coordinateSystem === WebGLCoordinateSystem && texture.isPMREMTexture !== true && texture.isRenderTargetTexture === true ) {
  93. uvNode = vec3( uvNode.x.negate(), uvNode.yz );
  94. }
  95. //
  96. let levelNode = this.levelNode;
  97. if ( levelNode === null && builder.context.getTextureLevel ) {
  98. levelNode = builder.context.getTextureLevel( this );
  99. }
  100. //
  101. return textureCubeUV( this._texture, uvNode, levelNode, this._width, this._height, this._maxMip );
  102. }
  103. }
  104. export const pmremTexture = nodeProxy( PMREMNode );
  105. addNodeClass( 'PMREMNode', PMREMNode );
  106. export default PMREMNode;