Skip to content

Commit

Permalink
Adding basic Cascading Shadows implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhruv-0-Arora committed Jul 20, 2024
1 parent 55a2dde commit 4f182f0
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 15 deletions.
94 changes: 94 additions & 0 deletions fission/src/systems/scene/CascadingShadows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import * as THREE from 'three';

class CascadingShadows {
private _camera: THREE.PerspectiveCamera;
private _shadowCameras: THREE.OrthographicCamera[] = [];
private _scene: THREE.Scene;

private _renderer: THREE.WebGLRenderer;
private _light: THREE.DirectionalLight;
private _shadowMaps: THREE.WebGLRenderTarget[] = []; // One shadow map per cascade

private _numCascades: number;
private _cascadeSplits: number[];

constructor(camera: THREE.PerspectiveCamera, scene: THREE.Scene, renderer: THREE.WebGLRenderer, numCascades: number = 5) {
this._camera = camera;
this._scene = scene;
this._renderer = renderer;
this._numCascades = numCascades;

// Creating the directional light
this._light = new THREE.DirectionalLight(0xffffff, 3);
this._light.position.set(-1, 3, 2);
this._light.castShadow = true;
scene.add(this._light);

// Split the camera frustum into numCascades cascades
this._cascadeSplits = new Array(numCascades).fill(0).map((_, i) => (i + 1) / numCascades);

// Create the shadow camera and shadow maps
for (let i = 0; i < numCascades; i++) {
const shadowCamera = new THREE.OrthographicCamera(-10, 10, 10, -10, 0.5, 500);
shadowCamera.position.copy(this._light.position);
shadowCamera.lookAt(0, 0, 0);
this._shadowCameras.push(shadowCamera);

const shadowMap = new THREE.WebGLRenderTarget(1024, 1024, {
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
format: THREE.RGBAFormat,
});
this._shadowMaps.push(shadowMap);
}
}

/** Updates the shadow maps */
public Update() {
const frustum = new THREE.Frustum();
const projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices(this._camera.projectionMatrix, this._camera.matrixWorldInverse);
frustum.setFromProjectionMatrix(projScreenMatrix);

for (let i = 0; i < this._numCascades; i++) {
const near = this._camera.near + this._cascadeSplits[i] * (this._camera.far - this._camera.near);
const far = this._camera.near + this._cascadeSplits[i + 1] * (this._camera.far - this._camera.near);

const cascadeFrustum = new THREE.Frustum();
cascadeFrustum.setFromProjectionMatrix(this.GetCascadeMatrix(near, far));

const shadowCamera = this._shadowCameras[i];
shadowCamera.position.copy(this._light.position);
shadowCamera.lookAt(0, 0, 0);
shadowCamera.updateMatrixWorld();
shadowCamera.updateProjectionMatrix();

this._renderer.setRenderTarget(this._shadowMaps[i]);
this._renderer.render(this._scene, shadowCamera);
}

this._renderer.setRenderTarget(null);
}

/** Returns the projection matrix for the cascade */
private GetCascadeMatrix(near: number, far: number): THREE.Matrix4 {
const matrix = new THREE.Matrix4();
const projMatrix = new THREE.Matrix4().makePerspective(
this._camera.fov,
this._camera.aspect,
near,
far,
this._camera.near,
this._camera.far
);
const invMatrix = this._camera.matrixWorld.invert();
matrix.multiplyMatrices(projMatrix, invMatrix);
return matrix;
}

public getShadowMap(index: number): THREE.WebGLRenderTarget {
return this._shadowMaps[index];
}
}

export default CascadingShadows;
36 changes: 21 additions & 15 deletions fission/src/systems/scene/SceneRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import InputSystem from "../input/InputSystem"
import { PixelSpaceCoord, SceneOverlayEvent, SceneOverlayEventKey } from "@/ui/components/SceneOverlayEvents"
import {} from "@/ui/components/SceneOverlayEvents"
import PreferencesSystem from "../preferences/PreferencesSystem"
import CascadingShadows from "./CascadingShadows"

const CLEAR_COLOR = 0x121212
const GROUND_COLOR = 0x4066c7
Expand All @@ -34,6 +35,8 @@ class SceneRenderer extends WorldSystem {
private _orbitControls: OrbitControls
private _transformControls: Map<TransformControls, number> // maps all rendered transform controls to their size

private _light: CascadingShadows

public get sceneObjects() {
return this._sceneObjects
}
Expand Down Expand Up @@ -74,23 +77,25 @@ class SceneRenderer extends WorldSystem {
this._renderer.shadowMap.type = THREE.PCFSoftShadowMap
this._renderer.setSize(window.innerWidth, window.innerHeight)

const directionalLight = new THREE.DirectionalLight(0xffffff, 3.0)
directionalLight.position.set(-1.0, 3.0, 2.0)
directionalLight.castShadow = true
this._scene.add(directionalLight)
// const directionalLight = new THREE.DirectionalLight(0xffffff, 3.0)
// directionalLight.position.set(-1.0, 3.0, 2.0)
// directionalLight.castShadow = true
// this._scene.add(directionalLight)

// const shadowMapSize = Math.min(4096, this._renderer.capabilities.maxTextureSize)
// const shadowCamSize = 15
// console.debug(`Shadow Map Size: ${shadowMapSize}`)

const shadowMapSize = Math.min(4096, this._renderer.capabilities.maxTextureSize)
const shadowCamSize = 15
console.debug(`Shadow Map Size: ${shadowMapSize}`)
// directionalLight.shadow.camera.top = shadowCamSize
// directionalLight.shadow.camera.bottom = -shadowCamSize
// directionalLight.shadow.camera.left = -shadowCamSize
// directionalLight.shadow.camera.right = shadowCamSize
// directionalLight.shadow.mapSize = new THREE.Vector2(shadowMapSize, shadowMapSize)
// directionalLight.shadow.blurSamples = 16
// directionalLight.shadow.normalBias = 0.01
// directionalLight.shadow.bias = 0.0

directionalLight.shadow.camera.top = shadowCamSize
directionalLight.shadow.camera.bottom = -shadowCamSize
directionalLight.shadow.camera.left = -shadowCamSize
directionalLight.shadow.camera.right = shadowCamSize
directionalLight.shadow.mapSize = new THREE.Vector2(shadowMapSize, shadowMapSize)
directionalLight.shadow.blurSamples = 16
directionalLight.shadow.normalBias = 0.01
directionalLight.shadow.bias = 0.0
this._light = new CascadingShadows(this._mainCamera, this._scene, this._renderer)

const ambientLight = new THREE.AmbientLight(0xffffff, 0.1)
this._scene.add(ambientLight)
Expand Down Expand Up @@ -143,6 +148,7 @@ class SceneRenderer extends WorldSystem {
this._sceneObjects.forEach(obj => {
obj.Update()
})
this._light.Update()

this._skybox.position.copy(this._mainCamera.position)

Expand Down

0 comments on commit 4f182f0

Please sign in to comment.