gpu-curtains
Version:
gpu-curtains is a 3D WebGPU rendering engine. It can be used as a standalone 3D engine, but also includes extra classes focused on mapping 3d objects to DOM elements; It allows users to synchronize values such as position, sizing, or scale between them.
154 lines (153 loc) • 4.89 kB
JavaScript
import { Vec3 } from "../../math/Vec3.mjs";
import { Texture } from "../textures/Texture.mjs";
import { PerspectiveCamera } from "../cameras/PerspectiveCamera.mjs";
import { Shadow, shadowStruct } from "./Shadow.mjs";
import { getDefaultSpotShadowDepthVs } from "../shaders/full/vertex/get-default-spot-shadow-depth-vertex-shader-code.mjs";
//#region src/core/shadows/SpotShadow.ts
/** @ignore */
const spotShadowStruct = {
...shadowStruct,
position: {
type: "vec3f",
value: new Vec3()
},
viewMatrix: {
type: "mat4x4f",
value: new Float32Array(16)
},
projectionMatrix: {
type: "mat4x4f",
value: new Float32Array(16)
}
};
/**
* Create a shadow map from a {@link SpotLight} by rendering to a depth texture using a {@link PerspectiveCamera}.
*/
var SpotShadow = class extends Shadow {
/**
* SpotShadow constructor
* @param renderer - {@link CameraRenderer} or {@link GPUCurtains} used to create this {@link SpotShadow}.
* @param parameters - {@link SpotShadowParams} used to create this {@link SpotShadow}.
*/
constructor(renderer, { light, intensity, bias, normalBias, pcfSamples, radius, depthTextureSize, depthTextureFormat, autoRender, useRenderBundle, camera = {
near: .1,
far: 150
} } = {}) {
super(renderer, {
light,
intensity,
bias,
normalBias,
pcfSamples,
radius,
depthTextureSize,
depthTextureFormat,
autoRender,
useRenderBundle
});
camera.far = this.light.range !== 0 ? this.light.range : camera.far;
this.options = {
...this.options,
camera
};
this.focus = 1;
this.camera = new PerspectiveCamera({
near: this.options.camera.near,
far: this.options.camera.far,
fov: 180 / Math.PI * 2 * this.light.angle * this.focus,
width: this.options.depthTextureSize.x,
height: this.options.depthTextureSize.y,
onMatricesChanged: () => {
this.onPropertyChanged("projectionMatrix", this.camera.projectionMatrix);
this.onPropertyChanged("viewMatrix", this.camera.viewMatrix);
}
});
this.camera.position.set(0);
this.camera.parent = this.light;
}
/**
* Set or reset this {@link SpotShadow} {@link CameraRenderer} corresponding {@link core/bindings/BufferBinding.BufferBinding | BufferBinding}.
*/
setRendererBinding() {
this.rendererBinding = this.renderer.bindings.spotShadows;
}
/**
* Set the parameters and start casting shadows.
* @param parameters - Parameters to use for this {@link SpotShadow}.
*/
cast(parameters = {}) {
super.cast(parameters);
if (parameters.camera) {
if (parameters.camera.near) {
this.options.camera.near = parameters.camera.near;
this.camera.near = this.options.camera.near;
}
if (parameters.camera.far) {
this.options.camera.far = this.light.range !== 0 ? this.light.range : parameters.camera.far;
this.camera.far = this.options.camera.far;
}
}
}
/**
* Resend all properties to the {@link CameraRenderer} corresponding {@link core/bindings/BufferBinding.BufferBinding | BufferBinding}. Called when the maximum number of corresponding {@link SpotLight} has been overflowed or when the {@link renderer} has changed.
*/
reset() {
this.setRendererBinding();
super.reset();
this.onPropertyChanged("projectionMatrix", this.camera.projectionMatrix);
this.onPropertyChanged("viewMatrix", this.camera.viewMatrix);
this.setPosition();
}
/**
* Copy the {@link SpotLight} actual position and update binding.
*/
setPosition() {
this.onPropertyChanged("position", this.light.actualPosition);
}
/**
* Set the {@link PerspectiveCamera#fov | camera fov} based on the {@link SpotLight#angle | SpotLight angle}.
*/
setCameraFov() {
this.camera.fov = 180 / Math.PI * 2 * this.light.angle * this.focus;
}
/**
* Reset the {@link depthTexture} when the {@link depthTextureSize} changes and update camera ratio.
*/
onDepthTextureSizeChanged() {
super.setDepthTexture();
this.camera.setSize({
width: this.depthTextureSize.x,
height: this.depthTextureSize.y
});
}
/**
* Create the {@link depthTexture}.
*/
createDepthTexture() {
this.depthTexture = new Texture(this.renderer, {
label: `${this.light.options.label} (index: ${this.light.index}) shadow depth texture`,
name: "spotShadowDepthTexture" + this.index,
type: "depth",
format: this.depthTextureFormat,
sampleCount: this.sampleCount,
fixedSize: {
width: this.depthTextureSize.x,
height: this.depthTextureSize.y
},
autoDestroy: false
});
}
/**
* Get the default depth pass vertex shader for this {@link SpotShadow}.
* parameters - {@link VertexShaderInputBaseParams} used to compute the output `worldPosition` and `normal` vectors.
* @returns - Depth pass vertex shader.
*/
getDefaultShadowDepthVs({ bindings = [], geometry }) {
return { code: getDefaultSpotShadowDepthVs(this.index, {
bindings,
geometry
}) };
}
};
//#endregion
export { SpotShadow, spotShadowStruct };