UNPKG

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
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 };