SpotLightNode.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import AnalyticLightNode from './AnalyticLightNode.js';
  2. import LightsNode from './LightsNode.js';
  3. import getDistanceAttenuation from '../functions/light/getDistanceAttenuation.js';
  4. import getDirectionVector from '../functions/light/getDirectionVector.js';
  5. import { uniform, smoothstep, positionView, objectViewPosition } from '../shadernode/ShaderNodeElements.js';
  6. import { Vector3, SpotLight } from 'three';
  7. const getSpotAttenuation = ( coneCosine, penumbraCosine, angleCosine ) => smoothstep( coneCosine, penumbraCosine, angleCosine );
  8. class SpotLightNode extends AnalyticLightNode {
  9. constructor( light = null ) {
  10. super( light );
  11. this.directionNode = uniform( new Vector3() );
  12. this.coneCosNode = uniform( 0 );
  13. this.penumbraCosNode = uniform( 0 );
  14. this.cutoffDistanceNode = uniform( 0 );
  15. this.decayExponentNode = uniform( 0 );
  16. }
  17. update( frame ) {
  18. super.update( frame );
  19. const { light } = this;
  20. getDirectionVector( light, frame.camera, this.directionNode.value );
  21. this.coneCosNode.value = Math.cos( light.angle );
  22. this.penumbraCosNode.value = Math.cos( light.angle * ( 1 - light.penumbra ) );
  23. this.cutoffDistanceNode.value = light.distance;
  24. this.decayExponentNode.value = light.decay;
  25. }
  26. construct( builder ) {
  27. const { colorNode, cutoffDistanceNode, decayExponentNode, light } = this;
  28. const lVector = objectViewPosition( light ).sub( positionView );
  29. const lightDirection = lVector.normalize();
  30. const angleCos = lightDirection.dot( this.directionNode );
  31. const spotAttenuation = getSpotAttenuation( this.coneCosNode, this.penumbraCosNode, angleCos );
  32. const lightDistance = lVector.length();
  33. const lightAttenuation = getDistanceAttenuation.call( {
  34. lightDistance,
  35. cutoffDistance: cutoffDistanceNode,
  36. decayExponent: decayExponentNode
  37. } );
  38. const finalColor = colorNode.mul( spotAttenuation ).mul( lightAttenuation );
  39. const lightColor = spotAttenuation.greaterThan( 0 ).cond( finalColor, 0 );
  40. const lightingModelFunctionNode = builder.context.lightingModelNode;
  41. const reflectedLight = builder.context.reflectedLight;
  42. if ( lightingModelFunctionNode && lightingModelFunctionNode.direct ) {
  43. lightingModelFunctionNode.direct.call( {
  44. lightDirection,
  45. lightColor,
  46. reflectedLight
  47. }, builder );
  48. }
  49. }
  50. }
  51. LightsNode.setReference( SpotLight, SpotLightNode );
  52. export default SpotLightNode;