AnalyticLightNode.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import LightingNode from './LightingNode.js';
  2. import { NodeUpdateType } from '../core/constants.js';
  3. import { uniform } from '../core/UniformNode.js';
  4. import { addNodeClass } from '../core/Node.js';
  5. import { /*vec2,*/ vec3 } from '../shadernode/ShaderNode.js';
  6. import { reference } from '../accessors/ReferenceNode.js';
  7. import { texture } from '../accessors/TextureNode.js';
  8. import { positionWorld } from '../accessors/PositionNode.js';
  9. import { normalWorld } from '../accessors/NormalNode.js';
  10. import { WebGPUCoordinateSystem } from 'three';
  11. //import { add } from '../math/OperatorNode.js';
  12. import { Color, DepthTexture, NearestFilter, LessCompare } from 'three';
  13. let depthMaterial = null;
  14. class AnalyticLightNode extends LightingNode {
  15. constructor( light = null ) {
  16. super();
  17. this.updateType = NodeUpdateType.FRAME;
  18. this.light = light;
  19. this.rtt = null;
  20. this.shadowNode = null;
  21. this.color = new Color();
  22. this.colorNode = uniform( this.color );
  23. }
  24. getHash( /*builder*/ ) {
  25. return this.light.uuid;
  26. }
  27. setupShadow( builder ) {
  28. let shadowNode = this.shadowNode;
  29. if ( shadowNode === null ) {
  30. if ( depthMaterial === null ) depthMaterial = builder.createNodeMaterial( 'MeshBasicNodeMaterial' );
  31. const shadow = this.light.shadow;
  32. const rtt = builder.getRenderTarget( shadow.mapSize.width, shadow.mapSize.height );
  33. const depthTexture = new DepthTexture();
  34. depthTexture.minFilter = NearestFilter;
  35. depthTexture.magFilter = NearestFilter;
  36. depthTexture.image.width = shadow.mapSize.width;
  37. depthTexture.image.height = shadow.mapSize.height;
  38. depthTexture.compareFunction = LessCompare;
  39. rtt.depthTexture = depthTexture;
  40. shadow.camera.updateProjectionMatrix();
  41. //
  42. const bias = reference( 'bias', 'float', shadow );
  43. const normalBias = reference( 'normalBias', 'float', shadow );
  44. let shadowCoord = uniform( shadow.matrix ).mul( positionWorld.add( normalWorld.mul( normalBias ) ) );
  45. shadowCoord = shadowCoord.xyz.div( shadowCoord.w );
  46. const frustumTest = shadowCoord.x.greaterThanEqual( 0 )
  47. .and( shadowCoord.x.lessThanEqual( 1 ) )
  48. .and( shadowCoord.y.greaterThanEqual( 0 ) )
  49. .and( shadowCoord.y.lessThanEqual( 1 ) )
  50. .and( shadowCoord.z.lessThanEqual( 1 ) );
  51. if ( builder.renderer.coordinateSystem === WebGPUCoordinateSystem ) {
  52. shadowCoord = vec3(
  53. shadowCoord.x,
  54. shadowCoord.y.oneMinus(), // WebGPU: Flip Y
  55. shadowCoord.z.add( bias ).mul( 2 ).sub( 1 ) // WebGPU: Convertion [ 0, 1 ] to [ - 1, 1 ]
  56. );
  57. } else {
  58. shadowCoord = vec3(
  59. shadowCoord.x,
  60. shadowCoord.y,
  61. shadowCoord.z.add( bias )
  62. );
  63. }
  64. const textureCompare = ( depthTexture, shadowCoord, compare ) => texture( depthTexture, shadowCoord ).compare( compare );
  65. //const textureCompare = ( depthTexture, shadowCoord, compare ) => compare.step( texture( depthTexture, shadowCoord ) );
  66. // BasicShadowMap
  67. shadowNode = textureCompare( depthTexture, shadowCoord.xy, shadowCoord.z );
  68. // PCFShadowMap
  69. /*
  70. const mapSize = reference( 'mapSize', 'vec2', shadow );
  71. const radius = reference( 'radius', 'float', shadow );
  72. const texelSize = vec2( 1 ).div( mapSize );
  73. const dx0 = texelSize.x.negate().mul( radius );
  74. const dy0 = texelSize.y.negate().mul( radius );
  75. const dx1 = texelSize.x.mul( radius );
  76. const dy1 = texelSize.y.mul( radius );
  77. const dx2 = dx0.mul( 2 );
  78. const dy2 = dy0.mul( 2 );
  79. const dx3 = dx1.mul( 2 );
  80. const dy3 = dy1.mul( 2 );
  81. shadowNode = add(
  82. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ),
  83. textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ),
  84. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ),
  85. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ),
  86. textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ),
  87. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ),
  88. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ),
  89. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ),
  90. textureCompare( depthTexture, shadowCoord.xy, shadowCoord.z ),
  91. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ),
  92. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ),
  93. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ),
  94. textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ),
  95. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ),
  96. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ),
  97. textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ),
  98. textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z )
  99. ).mul( 1 / 17 );
  100. */
  101. //
  102. this.rtt = rtt;
  103. this.colorNode = this.colorNode.mul( frustumTest.mix( 1, shadowNode ) );
  104. this.shadowNode = shadowNode;
  105. //
  106. this.updateBeforeType = NodeUpdateType.RENDER;
  107. }
  108. }
  109. setup( builder ) {
  110. if ( this.light.castShadow ) this.setupShadow( builder );
  111. }
  112. updateShadow( frame ) {
  113. const { rtt, light } = this;
  114. const { renderer, scene } = frame;
  115. scene.overrideMaterial = depthMaterial;
  116. rtt.setSize( light.shadow.mapSize.width, light.shadow.mapSize.height );
  117. light.shadow.updateMatrices( light );
  118. renderer.setRenderTarget( rtt );
  119. renderer.render( scene, light.shadow.camera );
  120. renderer.setRenderTarget( null );
  121. scene.overrideMaterial = null;
  122. }
  123. updateBefore( frame ) {
  124. const { light } = this;
  125. if ( light.castShadow ) this.updateShadow( frame );
  126. }
  127. update( /*frame*/ ) {
  128. const { light } = this;
  129. this.color.copy( light.color ).multiplyScalar( light.intensity );
  130. }
  131. }
  132. export default AnalyticLightNode;
  133. addNodeClass( 'AnalyticLightNode', AnalyticLightNode );