SpotLightNode.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import AnalyticLightNode from './AnalyticLightNode.js';
  2. import { lightTargetDirection } from './LightNode.js';
  3. import { addLightNode } from './LightsNode.js';
  4. import { getDistanceAttenuation } from './LightUtils.js';
  5. import { uniform } from '../core/UniformNode.js';
  6. import { smoothstep } from '../math/MathNode.js';
  7. import { objectViewPosition } from '../accessors/Object3DNode.js';
  8. import { positionView } from '../accessors/PositionNode.js';
  9. import { addNodeClass } from '../core/Node.js';
  10. import { SpotLight } from 'three';
  11. class SpotLightNode extends AnalyticLightNode {
  12. constructor( light = null ) {
  13. super( light );
  14. this.coneCosNode = uniform( 0 );
  15. this.penumbraCosNode = uniform( 0 );
  16. this.cutoffDistanceNode = uniform( 0 );
  17. this.decayExponentNode = uniform( 0 );
  18. }
  19. update( frame ) {
  20. super.update( frame );
  21. const { light } = this;
  22. this.coneCosNode.value = Math.cos( light.angle );
  23. this.penumbraCosNode.value = Math.cos( light.angle * ( 1 - light.penumbra ) );
  24. this.cutoffDistanceNode.value = light.distance;
  25. this.decayExponentNode.value = light.decay;
  26. }
  27. getSpotAttenuation( angleCosine ) {
  28. const { coneCosNode, penumbraCosNode } = this;
  29. return smoothstep( coneCosNode, penumbraCosNode, angleCosine );
  30. }
  31. setup( builder ) {
  32. super.setup( builder );
  33. const lightingModel = builder.context.lightingModel;
  34. const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this;
  35. const lVector = objectViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode
  36. const lightDirection = lVector.normalize();
  37. const angleCos = lightDirection.dot( lightTargetDirection( light ) );
  38. const spotAttenuation = this.getSpotAttenuation( angleCos );
  39. const lightDistance = lVector.length();
  40. const lightAttenuation = getDistanceAttenuation( {
  41. lightDistance,
  42. cutoffDistance: cutoffDistanceNode,
  43. decayExponent: decayExponentNode
  44. } );
  45. const lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
  46. const reflectedLight = builder.context.reflectedLight;
  47. lightingModel.direct( {
  48. lightDirection,
  49. lightColor,
  50. reflectedLight,
  51. shadowMask: this.shadowMaskNode
  52. }, builder.stack, builder );
  53. }
  54. }
  55. export default SpotLightNode;
  56. addNodeClass( 'SpotLightNode', SpotLightNode );
  57. addLightNode( SpotLight, SpotLightNode );