|
@@ -25,6 +25,8 @@ const _frustum = new Frustum();
|
|
|
const _center = new Vector3();
|
|
|
const _size = new Vector3();
|
|
|
const _bbox = new Box3();
|
|
|
+const _uniformArray = [];
|
|
|
+const _logArray = [];
|
|
|
|
|
|
export default class CSM {
|
|
|
|
|
@@ -47,6 +49,7 @@ export default class CSM {
|
|
|
this.customSplitsCallback = data.customSplitsCallback;
|
|
|
this.mainFrustum = new Frustum();
|
|
|
this.frustums = [];
|
|
|
+ this.breaks = [];
|
|
|
|
|
|
this.lights = [];
|
|
|
this.materials = [];
|
|
@@ -93,70 +96,64 @@ export default class CSM {
|
|
|
|
|
|
const camera = this.camera;
|
|
|
const far = Math.min(camera.far, this.maxFar);
|
|
|
- this.breaks = [];
|
|
|
+ this.breaks.length = 0;
|
|
|
|
|
|
switch ( this.mode ) {
|
|
|
|
|
|
case 'uniform':
|
|
|
- this.breaks = uniformSplit( this.cascades, camera.near, far );
|
|
|
+ uniformSplit( this.cascades, camera.near, far, this.breaks );
|
|
|
break;
|
|
|
case 'logarithmic':
|
|
|
- this.breaks = logarithmicSplit( this.cascades, camera.near, far );
|
|
|
+ logarithmicSplit( this.cascades, camera.near, far, this.breaks );
|
|
|
break;
|
|
|
case 'practical':
|
|
|
- this.breaks = practicalSplit( this.cascades, camera.near, far, 0.5 );
|
|
|
+ practicalSplit( this.cascades, camera.near, far, 0.5, this.breaks );
|
|
|
break;
|
|
|
case 'custom':
|
|
|
if ( this.customSplitsCallback === undefined ) console.error( 'CSM: Custom split scheme callback not defined.' );
|
|
|
- this.breaks = this.customSplitsCallback( this.cascades, camera.near, far );
|
|
|
+ this.customSplitsCallback( this.cascades, camera.near, far, this.breaks );
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
- function uniformSplit( amount, near, far ) {
|
|
|
-
|
|
|
- const r = [];
|
|
|
+ function uniformSplit( amount, near, far, target ) {
|
|
|
|
|
|
for ( let i = 1; i < amount; i ++ ) {
|
|
|
|
|
|
- r.push( ( near + ( far - near ) * i / amount ) / far );
|
|
|
+ target.push( ( near + ( far - near ) * i / amount ) / far );
|
|
|
|
|
|
}
|
|
|
|
|
|
- r.push( 1 );
|
|
|
- return r;
|
|
|
+ target.push( 1 );
|
|
|
|
|
|
}
|
|
|
|
|
|
- function logarithmicSplit( amount, near, far ) {
|
|
|
-
|
|
|
- const r = [];
|
|
|
+ function logarithmicSplit( amount, near, far, target ) {
|
|
|
|
|
|
for ( let i = 1; i < amount; i ++ ) {
|
|
|
|
|
|
- r.push( ( near * ( far / near ) ** ( i / amount ) ) / far );
|
|
|
+ target.push( ( near * ( far / near ) ** ( i / amount ) ) / far );
|
|
|
|
|
|
}
|
|
|
|
|
|
- r.push( 1 );
|
|
|
- return r;
|
|
|
+ target.push( 1 );
|
|
|
|
|
|
}
|
|
|
|
|
|
- function practicalSplit( amount, near, far, lambda ) {
|
|
|
+ function practicalSplit( amount, near, far, lambda, target ) {
|
|
|
|
|
|
- const log = logarithmicSplit( amount, near, far );
|
|
|
- const uni = uniformSplit( amount, near, far );
|
|
|
- const r = [];
|
|
|
+ _uniformArray.length = 0;
|
|
|
+ _logArray.length = 0;
|
|
|
+ const log = logarithmicSplit( amount, near, far, _logArray );
|
|
|
+ const uni = uniformSplit( amount, near, far, _uniformArray );
|
|
|
|
|
|
for ( let i = 1; i < amount; i ++ ) {
|
|
|
|
|
|
- r.push( MathUtils.lerp( uni[ i - 1 ], log[ i - 1 ], lambda ) );
|
|
|
+ target.push( MathUtils.lerp( _uniformArray[ i - 1 ], _logArray[ i - 1 ], lambda ) );
|
|
|
|
|
|
}
|
|
|
|
|
|
- r.push( 1 );
|
|
|
- return r;
|
|
|
+ target.push( 1 );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -219,14 +216,7 @@ export default class CSM {
|
|
|
material.defines.CSM_CASCADES = this.cascades;
|
|
|
|
|
|
const breaksVec2 = [];
|
|
|
-
|
|
|
- for ( let i = 0; i < this.cascades; i ++ ) {
|
|
|
-
|
|
|
- let amount = this.breaks[ i ];
|
|
|
- let prev = this.breaks[ i - 1 ] || 0;
|
|
|
- breaksVec2.push( new Vector2( prev, amount ) );
|
|
|
-
|
|
|
- }
|
|
|
+ this.getExtendedBreaks( breaksVec2 );
|
|
|
|
|
|
const self = this;
|
|
|
const far = Math.min(this.camera.far, this.maxFar);
|
|
@@ -249,28 +239,33 @@ export default class CSM {
|
|
|
|
|
|
for ( let i = 0; i < this.materials.length; i ++ ) {
|
|
|
|
|
|
- this.materials[ i ].uniforms.CSM_cascades.value = this.getExtendedBreaks();
|
|
|
- this.materials[ i ].uniforms.cameraNear.value = this.camera.near;
|
|
|
- this.materials[ i ].uniforms.shadowFar.value = far;
|
|
|
+ const uniforms = this.materials[ i ].uniforms;
|
|
|
+ this.getExtendedBreaks( uniforms.CSM_cascades.value );
|
|
|
+ uniforms.cameraNear.value = this.camera.near;
|
|
|
+ uniforms.shadowFar.value = far;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- getExtendedBreaks() {
|
|
|
+ getExtendedBreaks( target ) {
|
|
|
+
|
|
|
+ while ( target.length < this.breaks.length ) {
|
|
|
|
|
|
- let breaksVec2 = [];
|
|
|
+ target.push( new Vector2() );
|
|
|
+
|
|
|
+ }
|
|
|
+ target.length = this.breaks.length;
|
|
|
|
|
|
for ( let i = 0; i < this.cascades; i ++ ) {
|
|
|
|
|
|
let amount = this.breaks[ i ];
|
|
|
let prev = this.breaks[ i - 1 ] || 0;
|
|
|
- breaksVec2.push( new Vector2( prev, amount ) );
|
|
|
+ target[ i ].x = prev;
|
|
|
+ target[ i ].y = amount;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return breaksVec2;
|
|
|
-
|
|
|
}
|
|
|
|
|
|
updateFrustums() {
|