|
@@ -0,0 +1,163 @@
|
|
|
+import {
|
|
|
+ Group,
|
|
|
+ Mesh,
|
|
|
+ LineSegments,
|
|
|
+ BufferGeometry,
|
|
|
+ LineBasicMaterial,
|
|
|
+ Box3Helper,
|
|
|
+ Box3,
|
|
|
+ PlaneBufferGeometry,
|
|
|
+ MeshBasicMaterial,
|
|
|
+ BufferAttribute,
|
|
|
+ DoubleSide
|
|
|
+} from '../../../build/three.module.js';
|
|
|
+
|
|
|
+class CSMHelper extends Group {
|
|
|
+
|
|
|
+ constructor( csm ) {
|
|
|
+
|
|
|
+ super();
|
|
|
+ this.csm = csm;
|
|
|
+ this.displayFrustum = true;
|
|
|
+ this.displayPlanes = true;
|
|
|
+ this.displayShadowBounds = true;
|
|
|
+
|
|
|
+ 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 ] );
|
|
|
+ const positions = new Float32Array( 24 );
|
|
|
+ const frustumGeometry = new BufferGeometry();
|
|
|
+ frustumGeometry.setIndex( new BufferAttribute( indices, 1 ) );
|
|
|
+ frustumGeometry.setAttribute( 'position', new BufferAttribute( positions, 3, false ) );
|
|
|
+ const frustumLines = new LineSegments( frustumGeometry, new LineBasicMaterial() );
|
|
|
+ this.add( frustumLines );
|
|
|
+
|
|
|
+ this.frustumLines = frustumLines;
|
|
|
+ this.cascadeLines = [];
|
|
|
+ this.cascadePlanes = [];
|
|
|
+ this.shadowLines = [];
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ updateVisibility() {
|
|
|
+
|
|
|
+ const displayFrustum = this.displayFrustum;
|
|
|
+ const displayPlanes = this.displayPlanes;
|
|
|
+ const displayShadowBounds = this.displayShadowBounds;
|
|
|
+
|
|
|
+ const frustumLines = this.frustumLines;
|
|
|
+ const cascadeLines = this.cascadeLines;
|
|
|
+ const cascadePlanes = this.cascadePlanes;
|
|
|
+ const shadowLines = this.shadowLines;
|
|
|
+ for ( let i = 0, l = cascadeLines.length; i < l; i ++ ) {
|
|
|
+
|
|
|
+ const cascadeLine = cascadeLines[ i ];
|
|
|
+ const cascadePlane = cascadePlanes[ i ];
|
|
|
+ const shadowLineGroup = shadowLines[ i ];
|
|
|
+
|
|
|
+ cascadeLine.visible = displayFrustum;
|
|
|
+ cascadePlane.visible = displayFrustum && displayPlanes;
|
|
|
+ shadowLineGroup.visible = displayShadowBounds;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ frustumLines.visible = displayFrustum;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ update() {
|
|
|
+
|
|
|
+ const csm = this.csm;
|
|
|
+ const camera = csm.camera;
|
|
|
+ const cascades = csm.cascades;
|
|
|
+ const mainFrustum = csm.mainFrustum;
|
|
|
+ const frustums = csm.frustums;
|
|
|
+ const lights = csm.lights;
|
|
|
+
|
|
|
+ const frustumLines = this.frustumLines;
|
|
|
+ const frustumLinePositions = frustumLines.geometry.getAttribute( 'position' );
|
|
|
+ const cascadeLines = this.cascadeLines;
|
|
|
+ const cascadePlanes = this.cascadePlanes;
|
|
|
+ const shadowLines = this.shadowLines;
|
|
|
+
|
|
|
+ this.position.copy( camera.position );
|
|
|
+ this.quaternion.copy( camera.quaternion );
|
|
|
+ this.scale.copy( camera.scale );
|
|
|
+ this.updateMatrixWorld( true );
|
|
|
+
|
|
|
+ while( cascadeLines.length > cascades ) {
|
|
|
+
|
|
|
+ this.remove( cascadeLines.pop() );
|
|
|
+ this.remove( cascadePlanes.pop() );
|
|
|
+ this.remove( shadowLines.pop() );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ while( cascadeLines.length < cascades ) {
|
|
|
+
|
|
|
+ const cascadeLine = new Box3Helper( new Box3(), 0xffffff );
|
|
|
+ const planeMat = new MeshBasicMaterial( { transparent: true, opacity: 0.1, depthWrite: false, side: DoubleSide } );
|
|
|
+ const cascadePlane = new Mesh( new PlaneBufferGeometry(), planeMat );
|
|
|
+ const shadowLineGroup = new Group();
|
|
|
+ const shadowLine = new Box3Helper( new Box3(), 0xffff00 );
|
|
|
+ shadowLineGroup.add( shadowLine );
|
|
|
+
|
|
|
+ this.add( cascadeLine );
|
|
|
+ this.add( cascadePlane );
|
|
|
+ this.add( shadowLineGroup );
|
|
|
+
|
|
|
+ cascadeLines.push( cascadeLine );
|
|
|
+ cascadePlanes.push( cascadePlane );
|
|
|
+ shadowLines.push( shadowLineGroup );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ for ( let i = 0; i < cascades; i ++ ) {
|
|
|
+
|
|
|
+ const frustum = frustums[ i ];
|
|
|
+ const light = lights[ i ];
|
|
|
+ const shadowCam = light.shadow.camera;
|
|
|
+ const farVerts = frustum.vertices.far;
|
|
|
+
|
|
|
+ const cascadeLine = cascadeLines[ i ];
|
|
|
+ const cascadePlane = cascadePlanes[ i ];
|
|
|
+ const shadowLineGroup = shadowLines[ i ];
|
|
|
+ const shadowLine = shadowLineGroup.children[ 0 ];
|
|
|
+
|
|
|
+ cascadeLine.box.min.copy( farVerts[ 2 ] );
|
|
|
+ cascadeLine.box.max.copy( farVerts[ 0 ] );
|
|
|
+ cascadeLine.box.max.z += 1e-4;
|
|
|
+
|
|
|
+ cascadePlane.position.addVectors( farVerts[ 0 ], farVerts[ 2 ] );
|
|
|
+ cascadePlane.position.multiplyScalar( 0.5 );
|
|
|
+ cascadePlane.scale.subVectors( farVerts[ 0 ], farVerts[ 2 ] );
|
|
|
+ cascadePlane.scale.z = 1e-4;
|
|
|
+
|
|
|
+ this.remove( shadowLineGroup );
|
|
|
+ shadowLineGroup.position.copy( shadowCam.position );
|
|
|
+ shadowLineGroup.quaternion.copy( shadowCam.quaternion );
|
|
|
+ shadowLineGroup.scale.copy( shadowCam.scale );
|
|
|
+ shadowLineGroup.updateMatrixWorld( true );
|
|
|
+ this.attach( shadowLineGroup );
|
|
|
+
|
|
|
+ shadowLine.box.min.set( shadowCam.bottom, shadowCam.left, - shadowCam.far );
|
|
|
+ shadowLine.box.max.set( shadowCam.top, shadowCam.right, - shadowCam.near );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ const nearVerts = mainFrustum.vertices.near;
|
|
|
+ const farVerts = mainFrustum.vertices.far;
|
|
|
+ frustumLinePositions.setXYZ( 0, farVerts[ 0 ].x, farVerts[ 0 ].y, farVerts[ 0 ].z );
|
|
|
+ frustumLinePositions.setXYZ( 1, farVerts[ 3 ].x, farVerts[ 3 ].y, farVerts[ 3 ].z );
|
|
|
+ frustumLinePositions.setXYZ( 2, farVerts[ 2 ].x, farVerts[ 2 ].y, farVerts[ 2 ].z );
|
|
|
+ frustumLinePositions.setXYZ( 3, farVerts[ 1 ].x, farVerts[ 1 ].y, farVerts[ 1 ].z );
|
|
|
+
|
|
|
+ frustumLinePositions.setXYZ( 4, nearVerts[ 0 ].x, nearVerts[ 0 ].y, nearVerts[ 0 ].z );
|
|
|
+ frustumLinePositions.setXYZ( 5, nearVerts[ 3 ].x, nearVerts[ 3 ].y, nearVerts[ 3 ].z );
|
|
|
+ frustumLinePositions.setXYZ( 6, nearVerts[ 2 ].x, nearVerts[ 2 ].y, nearVerts[ 2 ].z );
|
|
|
+ frustumLinePositions.setXYZ( 7, nearVerts[ 1 ].x, nearVerts[ 1 ].y, nearVerts[ 1 ].z );
|
|
|
+ frustumLinePositions.needsUpdate = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+export { CSMHelper };
|