CSMHelper.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. ( function () {
  2. class CSMHelper extends THREE.Group {
  3. constructor( csm ) {
  4. super();
  5. this.csm = csm;
  6. this.displayFrustum = true;
  7. this.displayPlanes = true;
  8. this.displayShadowBounds = true;
  9. const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
  10. const positions = new Float32Array( 24 );
  11. const frustumGeometry = new THREE.BufferGeometry();
  12. frustumGeometry.setIndex( new THREE.BufferAttribute( indices, 1 ) );
  13. frustumGeometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3, false ) );
  14. const frustumLines = new THREE.LineSegments( frustumGeometry, new THREE.LineBasicMaterial() );
  15. this.add( frustumLines );
  16. this.frustumLines = frustumLines;
  17. this.cascadeLines = [];
  18. this.cascadePlanes = [];
  19. this.shadowLines = [];
  20. }
  21. updateVisibility() {
  22. const displayFrustum = this.displayFrustum;
  23. const displayPlanes = this.displayPlanes;
  24. const displayShadowBounds = this.displayShadowBounds;
  25. const frustumLines = this.frustumLines;
  26. const cascadeLines = this.cascadeLines;
  27. const cascadePlanes = this.cascadePlanes;
  28. const shadowLines = this.shadowLines;
  29. for ( let i = 0, l = cascadeLines.length; i < l; i ++ ) {
  30. const cascadeLine = cascadeLines[ i ];
  31. const cascadePlane = cascadePlanes[ i ];
  32. const shadowLineGroup = shadowLines[ i ];
  33. cascadeLine.visible = displayFrustum;
  34. cascadePlane.visible = displayFrustum && displayPlanes;
  35. shadowLineGroup.visible = displayShadowBounds;
  36. }
  37. frustumLines.visible = displayFrustum;
  38. }
  39. update() {
  40. const csm = this.csm;
  41. const camera = csm.camera;
  42. const cascades = csm.cascades;
  43. const mainFrustum = csm.mainFrustum;
  44. const frustums = csm.frustums;
  45. const lights = csm.lights;
  46. const frustumLines = this.frustumLines;
  47. const frustumLinePositions = frustumLines.geometry.getAttribute( 'position' );
  48. const cascadeLines = this.cascadeLines;
  49. const cascadePlanes = this.cascadePlanes;
  50. const shadowLines = this.shadowLines;
  51. this.position.copy( camera.position );
  52. this.quaternion.copy( camera.quaternion );
  53. this.scale.copy( camera.scale );
  54. this.updateMatrixWorld( true );
  55. while ( cascadeLines.length > cascades ) {
  56. this.remove( cascadeLines.pop() );
  57. this.remove( cascadePlanes.pop() );
  58. this.remove( shadowLines.pop() );
  59. }
  60. while ( cascadeLines.length < cascades ) {
  61. const cascadeLine = new THREE.Box3Helper( new THREE.Box3(), 0xffffff );
  62. const planeMat = new THREE.MeshBasicMaterial( {
  63. transparent: true,
  64. opacity: 0.1,
  65. depthWrite: false,
  66. side: THREE.DoubleSide
  67. } );
  68. const cascadePlane = new THREE.Mesh( new THREE.PlaneGeometry(), planeMat );
  69. const shadowLineGroup = new THREE.Group();
  70. const shadowLine = new THREE.Box3Helper( new THREE.Box3(), 0xffff00 );
  71. shadowLineGroup.add( shadowLine );
  72. this.add( cascadeLine );
  73. this.add( cascadePlane );
  74. this.add( shadowLineGroup );
  75. cascadeLines.push( cascadeLine );
  76. cascadePlanes.push( cascadePlane );
  77. shadowLines.push( shadowLineGroup );
  78. }
  79. for ( let i = 0; i < cascades; i ++ ) {
  80. const frustum = frustums[ i ];
  81. const light = lights[ i ];
  82. const shadowCam = light.shadow.camera;
  83. const farVerts = frustum.vertices.far;
  84. const cascadeLine = cascadeLines[ i ];
  85. const cascadePlane = cascadePlanes[ i ];
  86. const shadowLineGroup = shadowLines[ i ];
  87. const shadowLine = shadowLineGroup.children[ 0 ];
  88. cascadeLine.box.min.copy( farVerts[ 2 ] );
  89. cascadeLine.box.max.copy( farVerts[ 0 ] );
  90. cascadeLine.box.max.z += 1e-4;
  91. cascadePlane.position.addVectors( farVerts[ 0 ], farVerts[ 2 ] );
  92. cascadePlane.position.multiplyScalar( 0.5 );
  93. cascadePlane.scale.subVectors( farVerts[ 0 ], farVerts[ 2 ] );
  94. cascadePlane.scale.z = 1e-4;
  95. this.remove( shadowLineGroup );
  96. shadowLineGroup.position.copy( shadowCam.position );
  97. shadowLineGroup.quaternion.copy( shadowCam.quaternion );
  98. shadowLineGroup.scale.copy( shadowCam.scale );
  99. shadowLineGroup.updateMatrixWorld( true );
  100. this.attach( shadowLineGroup );
  101. shadowLine.box.min.set( shadowCam.bottom, shadowCam.left, - shadowCam.far );
  102. shadowLine.box.max.set( shadowCam.top, shadowCam.right, - shadowCam.near );
  103. }
  104. const nearVerts = mainFrustum.vertices.near;
  105. const farVerts = mainFrustum.vertices.far;
  106. frustumLinePositions.setXYZ( 0, farVerts[ 0 ].x, farVerts[ 0 ].y, farVerts[ 0 ].z );
  107. frustumLinePositions.setXYZ( 1, farVerts[ 3 ].x, farVerts[ 3 ].y, farVerts[ 3 ].z );
  108. frustumLinePositions.setXYZ( 2, farVerts[ 2 ].x, farVerts[ 2 ].y, farVerts[ 2 ].z );
  109. frustumLinePositions.setXYZ( 3, farVerts[ 1 ].x, farVerts[ 1 ].y, farVerts[ 1 ].z );
  110. frustumLinePositions.setXYZ( 4, nearVerts[ 0 ].x, nearVerts[ 0 ].y, nearVerts[ 0 ].z );
  111. frustumLinePositions.setXYZ( 5, nearVerts[ 3 ].x, nearVerts[ 3 ].y, nearVerts[ 3 ].z );
  112. frustumLinePositions.setXYZ( 6, nearVerts[ 2 ].x, nearVerts[ 2 ].y, nearVerts[ 2 ].z );
  113. frustumLinePositions.setXYZ( 7, nearVerts[ 1 ].x, nearVerts[ 1 ].y, nearVerts[ 1 ].z );
  114. frustumLinePositions.needsUpdate = true;
  115. }
  116. }
  117. THREE.CSMHelper = CSMHelper;
  118. } )();