Created
November 16, 2022 23:17
-
-
Save itsdouges/05621f06bd38848ab4704a280f596104 to your computer and use it in GitHub Desktop.
Cascaded Shadow Maps for React Three Fiber
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useFrame, useThree } from '@react-three/fiber'; | |
import { useLayoutEffect, useMemo } from 'react'; | |
import { Camera, Vector3, Vector3Tuple } from 'three'; | |
import CSM, { Params } from 'three-csm'; | |
interface CascadedShadowMapProps extends Omit<Params, 'lightDirection' | 'camera' | 'parent'> { | |
fade?: boolean; | |
lightDirection?: Vector3Tuple; | |
} | |
class CSMProxy { | |
instance: CSM | undefined; | |
args: Params; | |
constructor(args: Params) { | |
this.args = args; | |
} | |
set fade(fade: boolean) { | |
if (this.instance) { | |
this.instance.fade = fade; | |
} | |
} | |
set camera(camera: Camera) { | |
if (this.instance) { | |
this.instance.camera = camera; | |
} | |
} | |
set lightDirection(vector: Vector3 | Vector3Tuple) { | |
if (this.instance) { | |
this.instance.lightDirection = Array.isArray(vector) | |
? new Vector3().fromArray(vector).normalize() | |
: vector; | |
} | |
} | |
attach() { | |
this.instance = new CSM(this.args); | |
} | |
dispose() { | |
if (this.instance) { | |
this.instance.dispose(); | |
} | |
} | |
} | |
export function CascadedShadowMap({ | |
maxFar = 50, | |
shadowMapSize = 1024, | |
lightIntensity = 0.25, | |
cascades = 2, | |
fade, | |
lightDirection = [1, -1, 1], | |
shadowBias = 0.000001, | |
customSplitsCallback, | |
lightFar, | |
lightMargin, | |
lightNear, | |
mode, | |
}: CascadedShadowMapProps) { | |
const camera = useThree((three) => three.camera); | |
const parent = useThree((three) => three.scene); | |
const proxyInstance = useMemo( | |
() => | |
new CSMProxy({ | |
camera, | |
cascades, | |
customSplitsCallback, | |
lightDirection: new Vector3().fromArray(lightDirection).normalize(), | |
lightFar, | |
lightIntensity, | |
lightMargin, | |
lightNear, | |
maxFar, | |
mode, | |
parent, | |
shadowBias, | |
shadowMapSize, | |
}), | |
// These values will cause CSM to re-instantiate itself. | |
// This is an expensive operation and should be avoided. | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
[ | |
// Values that can be updated during runtime are omitted from this deps check. | |
cascades, | |
customSplitsCallback, | |
fade, | |
lightFar, | |
lightIntensity, | |
lightMargin, | |
lightNear, | |
maxFar, | |
mode, | |
shadowBias, | |
shadowMapSize, | |
] | |
); | |
useFrame(() => { | |
if (proxyInstance && proxyInstance.instance) { | |
proxyInstance.instance.update(camera.matrix); | |
} | |
}); | |
useLayoutEffect(() => { | |
proxyInstance.attach(); | |
return () => { | |
proxyInstance.dispose(); | |
}; | |
}, [proxyInstance]); | |
return ( | |
<primitive object={proxyInstance} camera={camera} fade={fade} lightDirection={lightDirection} /> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/node_modules/three-csm/build/CSM.d.ts b/node_modules/three-csm/build/CSM.d.ts | |
index 465eefa..f738080 100644 | |
--- a/node_modules/three-csm/build/CSM.d.ts | |
+++ b/node_modules/three-csm/build/CSM.d.ts | |
@@ -1,8 +1,8 @@ | |
-import { Vector3, DirectionalLight, Object3D, Material, PerspectiveCamera } from 'three'; | |
+import { Vector3, DirectionalLight, Object3D, Material, PerspectiveCamera, Matrix4, Camera } from 'three'; | |
import CSMHelper from './CSMHelper'; | |
import CSMFrustum from './CSMFrustum'; | |
-interface Params { | |
- camera: PerspectiveCamera; | |
+export interface Params { | |
+ camera: Camera; | |
parent: Object3D; | |
cascades?: number; | |
maxFar?: number; | |
@@ -17,7 +17,7 @@ interface Params { | |
customSplitsCallback?: (cascadeCount: any, nearDistance: any, farDistance: any) => number[]; | |
} | |
declare class CSM { | |
- camera: PerspectiveCamera; | |
+ camera: Camera; | |
parent: Object3D; | |
cascades: number; | |
maxFar: number; | |
@@ -41,7 +41,7 @@ declare class CSM { | |
private initCascades; | |
private updateShadowBounds; | |
private updateBreaks; | |
- update(): void; | |
+ update(matrix: Matrix4): void; | |
private injectInclude; | |
setupMaterial(material: Material): void; | |
private updateUniforms; | |
diff --git a/node_modules/three-csm/build/three-csm.module.js b/node_modules/three-csm/build/three-csm.module.js | |
index 7bd13ed..21ba916 100644 | |
--- a/node_modules/three-csm/build/three-csm.module.js | |
+++ b/node_modules/three-csm/build/three-csm.module.js | |
@@ -251,6 +251,7 @@ uniform float shadowFar; | |
class CSMHelper extends Group { | |
constructor(csm) { | |
super(); | |
+ | |
this.displayFrustum = true; | |
this.displayPlanes = true; | |
this.displayShadowBounds = true; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment