CSMHelper.js 5.7 KB

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