1
0

AnalyticLightNode.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import LightingNode from './LightingNode.js';
  2. import { NodeUpdateType } from '../core/constants.js';
  3. import { uniform } from '../core/UniformNode.js';
  4. import { Color } from '../../math/Color.js';
  5. import { renderGroup } from '../core/UniformGroupNode.js';
  6. import { hash } from '../core/NodeUtils.js';
  7. import { shadow } from './ShadowNode.js';
  8. import { nodeObject } from '../tsl/TSLCore.js';
  9. /**
  10. * Base class for analytic light nodes.
  11. *
  12. * @augments LightingNode
  13. */
  14. class AnalyticLightNode extends LightingNode {
  15. static get type() {
  16. return 'AnalyticLightNode';
  17. }
  18. /**
  19. * Constructs a new analytic light node.
  20. *
  21. * @param {?Light} [light=null] - The light source.
  22. */
  23. constructor( light = null ) {
  24. super();
  25. /**
  26. * The light source.
  27. *
  28. * @type {?Light}
  29. * @default null
  30. */
  31. this.light = light;
  32. /**
  33. * The light's color value.
  34. *
  35. * @type {Color}
  36. */
  37. this.color = new Color();
  38. /**
  39. * The light's color node. Points to `colorNode` of the light source, if set. Otherwise
  40. * it creates a uniform node based on {@link AnalyticLightNode#color}.
  41. *
  42. * @type {Node}
  43. */
  44. this.colorNode = ( light && light.colorNode ) || uniform( this.color ).setGroup( renderGroup );
  45. /**
  46. * This property is used to retain a reference to the original value of {@link AnalyticLightNode#colorNode}.
  47. * The final color node is represented by a different node when using shadows.
  48. *
  49. * @type {?Node}
  50. * @default null
  51. */
  52. this.baseColorNode = null;
  53. /**
  54. * Represents the light's shadow.
  55. *
  56. * @type {?ShadowNode}
  57. * @default null
  58. */
  59. this.shadowNode = null;
  60. /**
  61. * Represents the light's shadow color.
  62. *
  63. * @type {?Node}
  64. * @default null
  65. */
  66. this.shadowColorNode = null;
  67. /**
  68. * This flag can be used for type testing.
  69. *
  70. * @type {boolean}
  71. * @readonly
  72. * @default true
  73. */
  74. this.isAnalyticLightNode = true;
  75. /**
  76. * Overwritten since analytic light nodes are updated
  77. * once per frame.
  78. *
  79. * @type {string}
  80. * @default 'frame'
  81. */
  82. this.updateType = NodeUpdateType.FRAME;
  83. }
  84. /**
  85. * Overwrites the default {@link Node#customCacheKey} implementation by including the
  86. * `light.id` and `light.castShadow` into the cache key.
  87. *
  88. * @return {number} The custom cache key.
  89. */
  90. customCacheKey() {
  91. return hash( this.light.id, this.light.castShadow ? 1 : 0 );
  92. }
  93. getHash() {
  94. return this.light.uuid;
  95. }
  96. /**
  97. * Setups the shadow node for this light. The method exists so concrete light classes
  98. * can setup different types of shadow nodes.
  99. *
  100. * @return {ShadowNode} The created shadow node.
  101. */
  102. setupShadowNode() {
  103. return shadow( this.light );
  104. }
  105. /**
  106. * Setups the shadow for this light. This method is only executed if the light
  107. * cast shadows and the current build object receives shadows. It incorporates
  108. * shadows into the lighting computation.
  109. *
  110. * @param {NodeBuilder} builder - The current node builder.
  111. */
  112. setupShadow( builder ) {
  113. const { renderer } = builder;
  114. if ( renderer.shadowMap.enabled === false ) return;
  115. let shadowColorNode = this.shadowColorNode;
  116. if ( shadowColorNode === null ) {
  117. const customShadowNode = this.light.shadow.shadowNode;
  118. let shadowNode;
  119. if ( customShadowNode !== undefined ) {
  120. shadowNode = nodeObject( customShadowNode );
  121. } else {
  122. shadowNode = this.setupShadowNode( builder );
  123. }
  124. this.shadowNode = shadowNode;
  125. this.shadowColorNode = shadowColorNode = this.colorNode.mul( shadowNode );
  126. this.baseColorNode = this.colorNode;
  127. }
  128. //
  129. this.colorNode = shadowColorNode;
  130. }
  131. /**
  132. * Unlike most other nodes, lighting nodes do not return a output node in {@link Node#setup}.
  133. * The main purpose of lighting nodes is to configure the current {@link LightingModel} and/or
  134. * invocate the respective interface methods.
  135. *
  136. * @param {NodeBuilder} builder - The current node builder.
  137. */
  138. setup( builder ) {
  139. this.colorNode = this.baseColorNode || this.colorNode;
  140. if ( this.light.castShadow ) {
  141. if ( builder.object.receiveShadow ) {
  142. this.setupShadow( builder );
  143. }
  144. } else if ( this.shadowNode !== null ) {
  145. this.shadowNode.dispose();
  146. this.shadowNode = null;
  147. this.shadowColorNode = null;
  148. }
  149. }
  150. /**
  151. * The update method is used to update light uniforms per frame.
  152. * Potentially overwritten in concrete light nodes to update light
  153. * specific uniforms.
  154. *
  155. * @param {NodeFrame} frame - A reference to the current node frame.
  156. */
  157. update( /*frame*/ ) {
  158. const { light } = this;
  159. this.color.copy( light.color ).multiplyScalar( light.intensity );
  160. }
  161. }
  162. export default AnalyticLightNode;
粤ICP备19079148号