HemisphereLightDataNode.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { Color, Node, Vector3 } from 'three/webgpu';
  2. import { Loop, NodeUpdateType, mix, normalWorld, renderGroup, uniform, uniformArray } from 'three/tsl';
  3. const warn = ( message ) => {
  4. console.warn( `THREE.HemisphereLightDataNode: ${ message }` );
  5. };
  6. /**
  7. * Batched data node for hemisphere lights in dynamic lighting mode.
  8. *
  9. * @augments Node
  10. */
  11. class HemisphereLightDataNode extends Node {
  12. static get type() {
  13. return 'HemisphereLightDataNode';
  14. }
  15. constructor( maxCount = 4 ) {
  16. super();
  17. this.maxCount = maxCount;
  18. this._lights = [];
  19. this._skyColors = [];
  20. this._groundColors = [];
  21. this._directions = [];
  22. for ( let i = 0; i < maxCount; i ++ ) {
  23. this._skyColors.push( new Color() );
  24. this._groundColors.push( new Color() );
  25. this._directions.push( new Vector3() );
  26. }
  27. this.skyColorsNode = uniformArray( this._skyColors, 'color' ).setGroup( renderGroup );
  28. this.groundColorsNode = uniformArray( this._groundColors, 'color' ).setGroup( renderGroup );
  29. this.directionsNode = uniformArray( this._directions, 'vec3' ).setGroup( renderGroup );
  30. this.countNode = uniform( 0, 'int' ).setGroup( renderGroup );
  31. this.updateType = NodeUpdateType.RENDER;
  32. }
  33. setLights( lights ) {
  34. if ( lights.length > this.maxCount ) {
  35. warn( `${ lights.length } lights exceed the configured max of ${ this.maxCount }. Excess lights are ignored.` );
  36. }
  37. this._lights = lights;
  38. return this;
  39. }
  40. update() {
  41. const count = Math.min( this._lights.length, this.maxCount );
  42. this.countNode.value = count;
  43. for ( let i = 0; i < count; i ++ ) {
  44. const light = this._lights[ i ];
  45. this._skyColors[ i ].copy( light.color ).multiplyScalar( light.intensity );
  46. this._groundColors[ i ].copy( light.groundColor ).multiplyScalar( light.intensity );
  47. this._directions[ i ].setFromMatrixPosition( light.matrixWorld ).normalize();
  48. }
  49. }
  50. setup( builder ) {
  51. Loop( this.countNode, ( { i } ) => {
  52. const skyColor = this.skyColorsNode.element( i );
  53. const groundColor = this.groundColorsNode.element( i );
  54. const lightDirection = this.directionsNode.element( i );
  55. const hemiDiffuseWeight = normalWorld.dot( lightDirection ).mul( 0.5 ).add( 0.5 );
  56. const irradiance = mix( groundColor, skyColor, hemiDiffuseWeight );
  57. builder.context.irradiance.addAssign( irradiance );
  58. } );
  59. }
  60. }
  61. export default HemisphereLightDataNode;
粤ICP备19079148号