From 4b04a09dc0b69e80bd1447d9330025f283dfdc09 Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Mon, 12 Dec 2022 16:27:26 +0000 Subject: [PATCH 1/6] Improved shadow cascades rendering, allowing per cascade update --- .../src/examples/graphics/shadow-cascades.tsx | 92 ++++++++++++++++--- src/framework/components/light/component.js | 19 +++- src/scene/light.js | 25 +++-- .../renderer/shadow-renderer-directional.js | 41 ++++++++- src/scene/renderer/shadow-renderer.js | 38 +++----- 5 files changed, 164 insertions(+), 51 deletions(-) diff --git a/examples/src/examples/graphics/shadow-cascades.tsx b/examples/src/examples/graphics/shadow-cascades.tsx index 78fd4be3240..e4b89e5c793 100644 --- a/examples/src/examples/graphics/shadow-cascades.tsx +++ b/examples/src/examples/graphics/shadow-cascades.tsx @@ -2,7 +2,7 @@ import React from 'react'; import * as pc from '../../../../'; import { BindingTwoWay } from '@playcanvas/pcui'; -import { LabelGroup, Panel, SelectInput, SliderInput } from '@playcanvas/pcui/react'; +import { BooleanInput, LabelGroup, Panel, SelectInput, SliderInput } from '@playcanvas/pcui/react'; import { Observer } from '@playcanvas/observer'; class ShadowCascadesExample { @@ -25,6 +25,9 @@ class ShadowCascadesExample { + + + @@ -61,7 +64,8 @@ class ShadowCascadesExample { shadowResolution: 2048, // shadow map resolution storing 4 cascades cascadeDistribution: 0.5, // distribution of cascade distances to prefer sharpness closer to the camera shadowType: pc.SHADOW_PCF3, // shadow filter type - vsmBlurSize: 11 // shader filter blur size for VSM shadows + vsmBlurSize: 11, // shader filter blur size for VSM shadows + everyFrame: true // true if all cascades update every frame } }); @@ -84,6 +88,34 @@ class ShadowCascadesExample { terrain.setLocalScale(30, 30, 30); app.root.addChild(terrain); + // get the clouds so that we can animate them + const srcClouds : Array = terrain.find((node: pc.GraphNode) => { + + const isCloud = node.name.includes('Icosphere'); + + if (isCloud) { + // no shadow receiving for clouds + (node as pc.Entity).render.receiveShadows = false; + } + + return isCloud; + }); + + // clone some additional clouds + const clouds : Array = []; + srcClouds.forEach((cloud) => { + clouds.push(cloud); + + for (let i = 0; i < 3; i++) { + const clone = cloud.clone() as pc.Entity; + cloud.parent.addChild(clone); + clouds.push(clone); + } + }); + + // shuffle the array to give clouds random order + clouds.sort(() => Math.random() - 0.5); + // find a tree in the middle to use as a focus point const tree = terrain.findOne("name", "Arbol 2.002"); @@ -95,7 +127,7 @@ class ShadowCascadesExample { }); // and position it in the world - camera.setLocalPosition(300, 60, 25); + camera.setLocalPosition(300, 160, 25); // add orbit camera script with a mouse and a touch support camera.addComponent("script"); @@ -129,21 +161,59 @@ class ShadowCascadesExample { app.root.addChild(dirLight); dirLight.setLocalEulerAngles(45, 350, 20); + // update mode of cascades + let updateEveryFrame = true; + // handle HUD changes - update properties on the light data.on('*:set', (path: string, value: any) => { const pathArray = path.split('.'); - // @ts-ignore - dirLight.light[pathArray[2]] = value; + + if (pathArray[2] === 'everyFrame') { + updateEveryFrame = value; + } else { + // @ts-ignore + dirLight.light[pathArray[2]] = value; + } }); - // on the first frame, when camera is updated, move it further away from the focus tree - let firstFrame = true; - app.on("update", function () { - if (firstFrame) { - firstFrame = false; + const cloudSpeed = 0.2; + let frameNumber = 0; + let time = 0; + app.on("update", function (dt: number) { + + time += dt; + + // on the first frame, when camera is updated, move it further away from the focus tree + if (frameNumber === 0) { // @ts-ignore engine-tsd - camera.script.orbitCamera.distance = 320; + camera.script.orbitCamera.distance = 470; + } + + if (updateEveryFrame) { + + // no per cascade rendering control + dirLight.light.faceUpdateModes = null; + + } else { + + // set up shadow update modes, nearest cascade updates each frame, then next one every 5 and so on + dirLight.light.faceUpdateModes = [ + pc.SHADOWUPDATE_THISFRAME, + (frameNumber % 5) === 0 ? pc.SHADOWUPDATE_THISFRAME : pc.SHADOWUPDATE_NONE, + (frameNumber % 10) === 0 ? pc.SHADOWUPDATE_THISFRAME : pc.SHADOWUPDATE_NONE, + (frameNumber % 15) === 0 ? pc.SHADOWUPDATE_THISFRAME : pc.SHADOWUPDATE_NONE + ]; } + + // move the clouds around + clouds.forEach((cloud, index: number) => { + const redialOffset = (index / clouds.length) * (6.24 / cloudSpeed); + const radius = 8 + 2 * Math.sin(redialOffset); + const cloudTime = time + redialOffset; + cloud.setLocalPosition(radius * Math.sin(cloudTime * cloudSpeed), 4, radius * Math.cos(cloudTime * cloudSpeed)); + }); + + frameNumber++; }); }); } diff --git a/src/framework/components/light/component.js b/src/framework/components/light/component.js index c9d969f88d6..dbd498e9cd7 100644 --- a/src/framework/components/light/component.js +++ b/src/framework/components/light/component.js @@ -9,7 +9,7 @@ import { LIGHTFALLOFF_LINEAR, MASK_AFFECT_LIGHTMAPPED, MASK_AFFECT_DYNAMIC, MASK_BAKE, SHADOW_PCF3, - SHADOWUPDATE_REALTIME + SHADOWUPDATE_REALTIME, SHADOWUPDATE_THISFRAME } from '../../../scene/constants.js'; import { Asset } from '../../asset/asset.js'; @@ -225,10 +225,6 @@ class LightComponent extends Component { this.onEnable(); } - updateShadow() { - this.light.updateShadow(); - } - onCookieAssetSet() { let forceLoad = false; @@ -321,6 +317,19 @@ class LightComponent extends Component { // remove cookie asset events this.cookieAsset = null; } + + /** + * Returns an array of SHADOWUPDATE_ setting per shadow cascade, or undefined if not used. + * + * @type {number[]} + */ + set faceUpdateModes(values) { + this.light.faceUpdateModes = values; + } + + get faceUpdateModes() { + return this.light.faceUpdateModes; + } } function _defineProperty(name, defaultValue, setFunc, skipEqualsCheck) { diff --git a/src/scene/light.js b/src/scene/light.js index 58832cc57e2..0e478d4ebed 100644 --- a/src/scene/light.js +++ b/src/scene/light.js @@ -5,6 +5,8 @@ import { Vec2 } from '../core/math/vec2.js'; import { Vec3 } from '../core/math/vec3.js'; import { Vec4 } from '../core/math/vec4.js'; +import { DEVICETYPE_WEBGPU } from '../platform/graphics/constants.js'; + import { BLUR_GAUSSIAN, LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_OMNI, LIGHTTYPE_SPOT, @@ -171,6 +173,7 @@ class Light { this.shadowIntensity = 1.0; this._normalOffsetBias = 0.0; this.shadowUpdateMode = SHADOWUPDATE_REALTIME; + this.faceUpdateModes = null; this._isVsm = false; this._isPcf = true; @@ -250,6 +253,7 @@ class Light { const stype = this._shadowType; this._shadowType = null; + this.faceUpdateModes = null; this.shadowType = stype; // refresh shadow type; switching from direct/spot to omni and back may change it } @@ -294,7 +298,8 @@ class Light { if (this._type === LIGHTTYPE_OMNI) value = SHADOW_PCF3; // VSM or HW PCF for omni lights is not supported yet - if (value === SHADOW_PCF5 && !device.webgl2) { + const supportsPCF5 = device.webgl2 || device.deviceType === DEVICETYPE_WEBGPU; + if (value === SHADOW_PCF5 && !supportsPCF5) { value = SHADOW_PCF3; // fallback from HW PCF to old PCF } @@ -574,6 +579,14 @@ class Light { if (this.shadowUpdateMode === SHADOWUPDATE_NONE) { this.shadowUpdateMode = SHADOWUPDATE_THISFRAME; } + + if (this.faceUpdateModes) { + for (let i = 0; i < this.faceUpdateModes.length; i++) { + if (this.faceUpdateModes[i] === SHADOWUPDATE_NONE) { + this.faceUpdateModes[i] = SHADOWUPDATE_THISFRAME; + } + } + } } // returns LightRenderData with matching camera and face @@ -620,6 +633,10 @@ class Light { clone.shadowUpdateMode = this.shadowUpdateMode; clone.mask = this.mask; + if (this.faceUpdateModes) { + clone.faceUpdateModes = this.faceUpdateModes.slice(); + } + // Spot properties clone.innerConeAngle = this._innerConeAngle; clone.outerConeAngle = this._outerConeAngle; @@ -801,12 +818,6 @@ class Light { this._updateFinalColor(); } - updateShadow() { - if (this.shadowUpdateMode !== SHADOWUPDATE_REALTIME) { - this.shadowUpdateMode = SHADOWUPDATE_THISFRAME; - } - } - layersDirty() { if (this._scene?.layers) { this._scene.layers._dirtyLights = true; diff --git a/src/scene/renderer/shadow-renderer-directional.js b/src/scene/renderer/shadow-renderer-directional.js index b8bfb14ca77..e7ee1321951 100644 --- a/src/scene/renderer/shadow-renderer-directional.js +++ b/src/scene/renderer/shadow-renderer-directional.js @@ -1,10 +1,11 @@ import { Debug, DebugHelper } from '../../core/debug.js'; +import { math } from '../../core/math/math.js'; import { Vec3 } from '../../core/math/vec3.js'; import { Mat4 } from '../../core/math/mat4.js'; import { BoundingBox } from '../../core/shape/bounding-box.js'; import { - LIGHTTYPE_DIRECTIONAL + LIGHTTYPE_DIRECTIONAL, SHADOWUPDATE_NONE, SHADOWUPDATE_THISFRAME } from '../constants.js'; import { RenderPass } from '../../platform/graphics/render-pass.js'; @@ -63,8 +64,14 @@ class ShadowRendererDirectional extends ShadowRenderer { const nearDist = camera._nearClip; this.generateSplitDistances(light, nearDist, light.shadowDistance); + const faceUpdateModes = light.faceUpdateModes; for (let cascade = 0; cascade < light.numCascades; cascade++) { + // if manually controlling cascade rendering and the cascade does not render this frame + if (faceUpdateModes?.[cascade] === SHADOWUPDATE_NONE) { + break; + } + const lightRenderData = light.getRenderData(camera, cascade); const shadowCam = lightRenderData.shadowCamera; @@ -160,14 +167,35 @@ class ShadowRendererDirectional extends ShadowRenderer { } } + // function to generate frustum split distances + generateSplitDistances(light, nearDist, farDist) { + + light._shadowCascadeDistances.fill(farDist); + for (let i = 1; i < light.numCascades; i++) { + + // lerp between linear and logarithmic distance, called practical split distance + const fraction = i / light.numCascades; + const linearDist = nearDist + (farDist - nearDist) * fraction; + const logDist = nearDist * (farDist / nearDist) ** fraction; + const dist = math.lerp(linearDist, logDist, light.cascadeDistribution); + light._shadowCascadeDistances[i - 1] = dist; + } + } + addLightRenderPasses(frameGraph, light, camera) { // shadow cascades have more faces rendered within a singe render pass const faceCount = light.numShadowFaces; + const faceUpdateModes = light.faceUpdateModes; // prepare render targets / cameras for rendering + let allCascadesRendering = true; let shadowCamera; for (let face = 0; face < faceCount; face++) { + + if (faceUpdateModes?.[face] === SHADOWUPDATE_NONE) + allCascadesRendering = false; + shadowCamera = this.prepareFace(light, camera, face); } @@ -175,7 +203,14 @@ class ShadowRendererDirectional extends ShadowRenderer { // inside the render pass, render all faces for (let face = 0; face < faceCount; face++) { - this.renderFace(light, camera, face, false); + + if (faceUpdateModes?.[face] !== SHADOWUPDATE_NONE) { + this.renderFace(light, camera, face, !allCascadesRendering); + } + + if (faceUpdateModes?.[face] === SHADOWUPDATE_THISFRAME) { + faceUpdateModes[face] = SHADOWUPDATE_NONE; + } } }, () => { @@ -186,7 +221,7 @@ class ShadowRendererDirectional extends ShadowRenderer { }); // setup render pass using any of the cameras, they all have the same pass related properties - this.setupRenderPass(renderPass, shadowCamera); + this.setupRenderPass(renderPass, shadowCamera, allCascadesRendering); DebugHelper.setName(renderPass, `DirShadow-${light._node.name}`); frameGraph.addRenderPass(renderPass); diff --git a/src/scene/renderer/shadow-renderer.js b/src/scene/renderer/shadow-renderer.js index 1235f2fc305..c23eff3b420 100644 --- a/src/scene/renderer/shadow-renderer.js +++ b/src/scene/renderer/shadow-renderer.js @@ -160,21 +160,6 @@ class ShadowRenderer { visible.sort(this.renderer.sortCompareDepth); } - // function to generate frustum split distances - generateSplitDistances(light, nearDist, farDist) { - - light._shadowCascadeDistances.fill(farDist); - for (let i = 1; i < light.numCascades; i++) { - - // lerp between linear and logarithmic distance, called practical split distance - const fraction = i / light.numCascades; - const linearDist = nearDist + (farDist - nearDist) * fraction; - const logDist = nearDist * (farDist / nearDist) ** fraction; - const dist = math.lerp(linearDist, logDist, light.cascadeDistribution); - light._shadowCascadeDistances[i - 1] = dist; - } - } - setupRenderState(device, light) { const isClustered = this.renderer.scene.clusteredLightingEnabled; @@ -340,20 +325,23 @@ class ShadowRenderer { return light.getRenderData(light._type === LIGHTTYPE_DIRECTIONAL ? camera : null, face); } - setupRenderPass(renderPass, shadowCamera) { + setupRenderPass(renderPass, shadowCamera, clearRenderTarget) { const rt = shadowCamera.renderTarget; renderPass.init(rt); - // color - const clearColor = shadowCamera.clearColorBuffer; - renderPass.colorOps.clear = clearColor; - if (clearColor) - renderPass.colorOps.clearValue.copy(shadowCamera.clearColor); - - // depth - renderPass.depthStencilOps.storeDepth = !clearColor; - renderPass.setClearDepth(1.0); + // only clear the render pass target if all faces (cascades) are getting rendered + if (clearRenderTarget) { + // color + const clearColor = shadowCamera.clearColorBuffer; + renderPass.colorOps.clear = clearColor; + if (clearColor) + renderPass.colorOps.clearValue.copy(shadowCamera.clearColor); + + // depth + renderPass.depthStencilOps.storeDepth = !clearColor; + renderPass.setClearDepth(1.0); + } // not sampling dynamically generated cubemaps renderPass.requiresCubemaps = false; From 60b01a068675f4a99ae69a5755219f106a8ceeb7 Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Mon, 12 Dec 2022 16:32:26 +0000 Subject: [PATCH 2/6] lint --- src/framework/components/light/component.js | 2 +- src/scene/renderer/shadow-renderer.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/framework/components/light/component.js b/src/framework/components/light/component.js index dbd498e9cd7..0419685bd1a 100644 --- a/src/framework/components/light/component.js +++ b/src/framework/components/light/component.js @@ -9,7 +9,7 @@ import { LIGHTFALLOFF_LINEAR, MASK_AFFECT_LIGHTMAPPED, MASK_AFFECT_DYNAMIC, MASK_BAKE, SHADOW_PCF3, - SHADOWUPDATE_REALTIME, SHADOWUPDATE_THISFRAME + SHADOWUPDATE_REALTIME } from '../../../scene/constants.js'; import { Asset } from '../../asset/asset.js'; diff --git a/src/scene/renderer/shadow-renderer.js b/src/scene/renderer/shadow-renderer.js index c23eff3b420..c4d1238b580 100644 --- a/src/scene/renderer/shadow-renderer.js +++ b/src/scene/renderer/shadow-renderer.js @@ -2,7 +2,6 @@ import { Debug } from '../../core/debug.js'; import { now } from '../../core/time.js'; import { Color } from '../../core/math/color.js'; import { Mat4 } from '../../core/math/mat4.js'; -import { math } from '../../core/math/math.js'; import { Vec3 } from '../../core/math/vec3.js'; import { Vec4 } from '../../core/math/vec4.js'; From 8e188c7ab97ce62b032d910f9b4391de7d4a0096 Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Tue, 13 Dec 2022 09:59:21 +0000 Subject: [PATCH 3/6] small improvement --- examples/src/examples/graphics/shadow-cascades.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/examples/graphics/shadow-cascades.tsx b/examples/src/examples/graphics/shadow-cascades.tsx index e4b89e5c793..29de0263a00 100644 --- a/examples/src/examples/graphics/shadow-cascades.tsx +++ b/examples/src/examples/graphics/shadow-cascades.tsx @@ -208,9 +208,9 @@ class ShadowCascadesExample { // move the clouds around clouds.forEach((cloud, index: number) => { const redialOffset = (index / clouds.length) * (6.24 / cloudSpeed); - const radius = 8 + 2 * Math.sin(redialOffset); + const radius = 9 + 4 * Math.sin(redialOffset); const cloudTime = time + redialOffset; - cloud.setLocalPosition(radius * Math.sin(cloudTime * cloudSpeed), 4, radius * Math.cos(cloudTime * cloudSpeed)); + cloud.setLocalPosition(2 + radius * Math.sin(cloudTime * cloudSpeed), 4, -5 + radius * Math.cos(cloudTime * cloudSpeed)); }); frameNumber++; From 3f7cfb9e5c2701b4c85e662b79eb616f0f1e71bf Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Tue, 13 Dec 2022 10:20:38 +0000 Subject: [PATCH 4/6] api rename --- .../src/examples/graphics/shadow-cascades.tsx | 6 +++--- src/framework/components/light/component.js | 8 ++++---- src/scene/light.js | 16 ++++++++-------- .../renderer/shadow-renderer-directional.js | 14 +++++++------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/examples/src/examples/graphics/shadow-cascades.tsx b/examples/src/examples/graphics/shadow-cascades.tsx index 29de0263a00..1c49ab9fb71 100644 --- a/examples/src/examples/graphics/shadow-cascades.tsx +++ b/examples/src/examples/graphics/shadow-cascades.tsx @@ -192,12 +192,12 @@ class ShadowCascadesExample { if (updateEveryFrame) { // no per cascade rendering control - dirLight.light.faceUpdateModes = null; + dirLight.light.shadowUpdateOverrides = null; } else { - // set up shadow update modes, nearest cascade updates each frame, then next one every 5 and so on - dirLight.light.faceUpdateModes = [ + // set up shadow update overrides, nearest cascade updates each frame, then next one every 5 and so on + dirLight.light.shadowUpdateOverrides = [ pc.SHADOWUPDATE_THISFRAME, (frameNumber % 5) === 0 ? pc.SHADOWUPDATE_THISFRAME : pc.SHADOWUPDATE_NONE, (frameNumber % 10) === 0 ? pc.SHADOWUPDATE_THISFRAME : pc.SHADOWUPDATE_NONE, diff --git a/src/framework/components/light/component.js b/src/framework/components/light/component.js index 0419685bd1a..d778232599b 100644 --- a/src/framework/components/light/component.js +++ b/src/framework/components/light/component.js @@ -323,12 +323,12 @@ class LightComponent extends Component { * * @type {number[]} */ - set faceUpdateModes(values) { - this.light.faceUpdateModes = values; + set shadowUpdateOverrides(values) { + this.light.shadowUpdateOverrides = values; } - get faceUpdateModes() { - return this.light.faceUpdateModes; + get shadowUpdateOverrides() { + return this.light.shadowUpdateOverrides; } } diff --git a/src/scene/light.js b/src/scene/light.js index 0e478d4ebed..6f9783d2c53 100644 --- a/src/scene/light.js +++ b/src/scene/light.js @@ -173,7 +173,7 @@ class Light { this.shadowIntensity = 1.0; this._normalOffsetBias = 0.0; this.shadowUpdateMode = SHADOWUPDATE_REALTIME; - this.faceUpdateModes = null; + this.shadowUpdateOverrides = null; this._isVsm = false; this._isPcf = true; @@ -253,7 +253,7 @@ class Light { const stype = this._shadowType; this._shadowType = null; - this.faceUpdateModes = null; + this.shadowUpdateOverrides = null; this.shadowType = stype; // refresh shadow type; switching from direct/spot to omni and back may change it } @@ -580,10 +580,10 @@ class Light { this.shadowUpdateMode = SHADOWUPDATE_THISFRAME; } - if (this.faceUpdateModes) { - for (let i = 0; i < this.faceUpdateModes.length; i++) { - if (this.faceUpdateModes[i] === SHADOWUPDATE_NONE) { - this.faceUpdateModes[i] = SHADOWUPDATE_THISFRAME; + if (this.shadowUpdateOverrides) { + for (let i = 0; i < this.shadowUpdateOverrides.length; i++) { + if (this.shadowUpdateOverrides[i] === SHADOWUPDATE_NONE) { + this.shadowUpdateOverrides[i] = SHADOWUPDATE_THISFRAME; } } } @@ -633,8 +633,8 @@ class Light { clone.shadowUpdateMode = this.shadowUpdateMode; clone.mask = this.mask; - if (this.faceUpdateModes) { - clone.faceUpdateModes = this.faceUpdateModes.slice(); + if (this.shadowUpdateOverrides) { + clone.shadowUpdateOverrides = this.shadowUpdateOverrides.slice(); } // Spot properties diff --git a/src/scene/renderer/shadow-renderer-directional.js b/src/scene/renderer/shadow-renderer-directional.js index e7ee1321951..0520afe7e65 100644 --- a/src/scene/renderer/shadow-renderer-directional.js +++ b/src/scene/renderer/shadow-renderer-directional.js @@ -64,11 +64,11 @@ class ShadowRendererDirectional extends ShadowRenderer { const nearDist = camera._nearClip; this.generateSplitDistances(light, nearDist, light.shadowDistance); - const faceUpdateModes = light.faceUpdateModes; + const shadowUpdateOverrides = light.shadowUpdateOverrides; for (let cascade = 0; cascade < light.numCascades; cascade++) { // if manually controlling cascade rendering and the cascade does not render this frame - if (faceUpdateModes?.[cascade] === SHADOWUPDATE_NONE) { + if (shadowUpdateOverrides?.[cascade] === SHADOWUPDATE_NONE) { break; } @@ -186,14 +186,14 @@ class ShadowRendererDirectional extends ShadowRenderer { // shadow cascades have more faces rendered within a singe render pass const faceCount = light.numShadowFaces; - const faceUpdateModes = light.faceUpdateModes; + const shadowUpdateOverrides = light.shadowUpdateOverrides; // prepare render targets / cameras for rendering let allCascadesRendering = true; let shadowCamera; for (let face = 0; face < faceCount; face++) { - if (faceUpdateModes?.[face] === SHADOWUPDATE_NONE) + if (shadowUpdateOverrides?.[face] === SHADOWUPDATE_NONE) allCascadesRendering = false; shadowCamera = this.prepareFace(light, camera, face); @@ -204,12 +204,12 @@ class ShadowRendererDirectional extends ShadowRenderer { // inside the render pass, render all faces for (let face = 0; face < faceCount; face++) { - if (faceUpdateModes?.[face] !== SHADOWUPDATE_NONE) { + if (shadowUpdateOverrides?.[face] !== SHADOWUPDATE_NONE) { this.renderFace(light, camera, face, !allCascadesRendering); } - if (faceUpdateModes?.[face] === SHADOWUPDATE_THISFRAME) { - faceUpdateModes[face] = SHADOWUPDATE_NONE; + if (shadowUpdateOverrides?.[face] === SHADOWUPDATE_THISFRAME) { + shadowUpdateOverrides[face] = SHADOWUPDATE_NONE; } } From 36075598b9971d9afa9c4bbb72e6ecacdedb7556 Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Tue, 13 Dec 2022 10:21:46 +0000 Subject: [PATCH 5/6] comment --- src/framework/components/light/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/components/light/component.js b/src/framework/components/light/component.js index d778232599b..844783e80dc 100644 --- a/src/framework/components/light/component.js +++ b/src/framework/components/light/component.js @@ -319,7 +319,7 @@ class LightComponent extends Component { } /** - * Returns an array of SHADOWUPDATE_ setting per shadow cascade, or undefined if not used. + * Returns an array of SHADOWUPDATE_ settings per shadow cascade, or undefined if not used. * * @type {number[]} */ From 031ed2eaaf3d7be65322ec6d319c4498cf4d58bc Mon Sep 17 00:00:00 2001 From: Martin Valigursky Date: Tue, 13 Dec 2022 10:28:14 +0000 Subject: [PATCH 6/6] updated type of the api to accept null as well --- src/framework/components/light/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/components/light/component.js b/src/framework/components/light/component.js index 844783e80dc..4ae04382c77 100644 --- a/src/framework/components/light/component.js +++ b/src/framework/components/light/component.js @@ -321,7 +321,7 @@ class LightComponent extends Component { /** * Returns an array of SHADOWUPDATE_ settings per shadow cascade, or undefined if not used. * - * @type {number[]} + * @type {number[] | null} */ set shadowUpdateOverrides(values) { this.light.shadowUpdateOverrides = values;