SpotLightNode.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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. construct( builder ) {
  32. super.construct( builder );
  33. const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this;
  34. const lVector = objectViewPosition( light ).sub( positionView ); // @TODO: Add it into LightNode
  35. const lightDirection = lVector.normalize();
  36. const angleCos = lightDirection.dot( lightTargetDirection( light ) );
  37. const spotAttenuation = this.getSpotAttenuation( angleCos );
  38. const lightDistance = lVector.length();
  39. const lightAttenuation = getDistanceAttenuation.call( {
  40. lightDistance,
  41. cutoffDistance: cutoffDistanceNode,
  42. decayExponent: decayExponentNode
  43. } );
  44. const lightColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
  45. const lightingModelFunctionNode = builder.context.lightingModelNode;
  46. const reflectedLight = builder.context.reflectedLight;
  47. if ( lightingModelFunctionNode && lightingModelFunctionNode.direct ) {
  48. lightingModelFunctionNode.direct.call( {
  49. lightDirection,
  50. lightColor,
  51. reflectedLight
  52. }, builder );
  53. }
  54. }
  55. }
  56. export default SpotLightNode;
  57. addLightNode( SpotLight, SpotLightNode );
  58. addNodeClass( SpotLightNode );