UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

847 lines (846 loc) 26.6 kB
/** * @import { Color } from '../../../core/math/color.js' * @import { EventHandle } from '../../../core/event-handle.js' * @import { LightComponentSystem } from './system.js' * @import { Entity } from '../../entity.js' * @import { Texture } from '../../../platform/graphics/texture.js' * @import { Vec2 } from '../../../core/math/vec2.js' */ export const _properties: string[]; /** * The LightComponent enables an {@link Entity} to light the scene. There are three types of light: * * - `directional`: A global light that emits light in the direction of the negative y-axis of the * owner entity. Emulates light sources that appear to be infinitely far away such as the sun. The * owner entity's position is effectively ignored. * - `omni`: A local light that emits light in all directions from the owner entity's position. * Emulates candles, lamps, bulbs, etc. * - `spot`: A local light that emits light similarly to an omni light but is bounded by a cone * centered on the owner entity's negative y-axis. Emulates flashlights, spotlights, etc. * * You should never need to use the LightComponent constructor directly. To add a LightComponent * to an {@link Entity}, use {@link Entity#addComponent}: * * ```javascript * const entity = new pc.Entity(); * entity.addComponent('light', { * type: 'omni', * color: new pc.Color(1, 0, 0), * intensity: 2 * }); * ``` * * Once the LightComponent is added to the entity, you can access it via the {@link Entity#light} * property: * * ```javascript * entity.light.intensity = 3; // Set the intensity of the light * * console.log(entity.light.intensity); // Get the intensity of the light * ``` * * Relevant Engine API examples: * * - [Area Lights](https://playcanvas.github.io/#/graphics/area-lights) * - [Clustered Area Lights](https://playcanvas.github.io/#/graphics/clustered-area-lights) * - [Clustered Lighting](https://playcanvas.github.io/#/graphics/clustered-lighting) * - [Clustered Omni Shadows](https://playcanvas.github.io/#/graphics/clustered-omni-shadows) * - [Clustered Spot Shadows](https://playcanvas.github.io/#/graphics/clustered-spot-shadows) * - [Lights](https://playcanvas.github.io/#/graphics/lights) * * @hideconstructor * @category Graphics */ export class LightComponent extends Component { /** * Create a new LightComponent instance. * * @param {LightComponentSystem} system - The ComponentSystem that created this Component. * @param {Entity} entity - The Entity that this Component is attached to. */ constructor(system: LightComponentSystem, entity: Entity); /** * @type {Light} * @private */ private _light; /** * @type {EventHandle|null} * @private */ private _evtLayersChanged; /** * @type {EventHandle|null} * @private */ private _evtLayerAdded; /** * @type {EventHandle|null} * @private */ private _evtLayerRemoved; /** * @type {Asset|null} * @private */ private _cookieAsset; /** * @type {number|null} * @private */ private _cookieAssetId; /** @private */ private _cookieAssetAdd; /** * @type {Vec4|null} * @private */ private _cookieMatrix; /** * @type {number} * @private */ private _shadowBias; /** * @type {number} * @private */ private _cookieAngle; /** * @type {Vec2|null} * @private */ private _cookieScale; /** * @type {boolean} * @private */ private _castShadows; /** * Mirrors the user-supplied value. {@link Light#affectSpecularity} silently ignores writes for * non-directional lights, so storing it on the component is required to round-trip the user's * intent and re-apply it when the type later becomes directional (via {@link refreshProperties}). * * @type {boolean} * @private */ private _affectSpecularity; /** * @type {boolean} * @private */ private _affectDynamic; /** * @type {boolean} * @private */ private _affectLightmapped; /** * @type {boolean} * @private */ private _bake; /** * @type {number[]} * @private */ private _layers; /** * Preserves the user-facing type string. Required because `'point'` and `'omni'` both map to * the same underlying int on the {@link Light}, so reverse-mapping would normalise the user's * input. * * @type {string} * @private */ private _type; /** * Gets the light component's underlying Light instance. * * @type {Light} * @ignore */ get light(): Light; /** * Sets the type of the light. Can be: * * - `"directional"`: A global light that emits light in the direction of the negative y-axis * of the owner entity. * - `"omni"`: A local light that emits light in all directions from the owner entity's * position. * - `"spot"`: A local light that emits light similarly to an omni light but is bounded by a * cone centered on the owner entity's negative y-axis. * * Defaults to `"directional"`. * * @type {string} */ set type(value: string); /** * Gets the type of the light. * * @type {string} */ get type(): string; /** * Sets the color of the light in sRGB space. The alpha component of the color is ignored. * Defaults to white (`[1, 1, 1]`). * * @type {Color} */ set color(value: Color); /** * Gets the color of the light. * * @type {Color} */ get color(): Color; /** * Sets the brightness of the light. Defaults to 1. * * @type {number} */ set intensity(value: number); /** * Gets the brightness of the light. * * @type {number} */ get intensity(): number; /** * Sets the physically-based luminance. Only used if `scene.physicalUnits` is true. Defaults to 0. * * @type {number} */ set luminance(value: number); /** * Gets the physically-based luminance. * * @type {number} */ get luminance(): number; /** * Sets the light source shape. Can be: * * - {@link LIGHTSHAPE_PUNCTUAL}: Infinitesimally small point. * - {@link LIGHTSHAPE_RECT}: Rectangle shape. * - {@link LIGHTSHAPE_DISK}: Disk shape. * - {@link LIGHTSHAPE_SPHERE}: Sphere shape. * * Defaults to {@link LIGHTSHAPE_PUNCTUAL}. * * @type {number} */ set shape(value: number); /** * Gets the light source shape. * * @type {number} */ get shape(): number; /** * Sets whether material specularity will be affected by this light. Only takes effect when * {@link type} is `"directional"`; for other types the value is preserved on the component and * applied if {@link type} later becomes `"directional"`. Defaults to true. * * @type {boolean} */ set affectSpecularity(value: boolean); /** * Gets whether material specularity will be affected by this light. * * @type {boolean} */ get affectSpecularity(): boolean; /** * Sets whether the light will cast shadows. Defaults to false. * * @type {boolean} */ set castShadows(value: boolean); /** * Gets whether the light will cast shadows. * * @type {boolean} */ get castShadows(): boolean; /** * Sets the distance from the viewpoint beyond which shadows are no longer rendered. Affects * directional lights only. Defaults to 40. * * @type {number} */ set shadowDistance(value: number); /** * Gets the distance from the viewpoint beyond which shadows are no longer rendered. * * @type {number} */ get shadowDistance(): number; /** * Sets the intensity of the shadow darkening. 0 having no effect and 1 meaning shadows are * entirely black. Defaults to 1. * * @type {number} */ set shadowIntensity(value: number); /** * Gets the intensity of the shadow darkening. * * @type {number} */ get shadowIntensity(): number; /** * Sets the size of the texture used for the shadow map. Valid sizes are 64, 128, 256, 512, * 1024, 2048. Defaults to 1024. * * @type {number} */ set shadowResolution(value: number); /** * Gets the size of the texture used for the shadow map. * * @type {number} */ get shadowResolution(): number; /** * Set the depth bias for tuning the appearance of the shadow mapping generated by this light. Valid * range is 0 to 1. Defaults to 0.05. * * @type {number} */ set shadowBias(value: number); /** * Get the depth bias for tuning the appearance of the shadow mapping generated by this light. * * @type {number} */ get shadowBias(): number; /** * Sets the number of shadow cascades. Can be 1, 2, 3 or 4. Defaults to 1, representing no * cascades. * * @type {number} */ set numCascades(value: number); /** * Gets the number of shadow cascades. * * @type {number} */ get numCascades(): number; /** * Sets the blend factor for cascaded shadow maps, defining the fraction of each cascade level * used for blending between adjacent cascades. The value should be between 0 and 1. Defaults * to 0, which disables blending between cascades. * * @type {number} */ set cascadeBlend(value: number); /** * Gets the blend factor for cascaded shadow maps. * * @type {number} */ get cascadeBlend(): number; /** * Sets the number of samples used to bake this light into the lightmap. Defaults to 1. Maximum * value is 255. * * @type {number} */ set bakeNumSamples(value: number); /** * Gets the number of samples used to bake this light into the lightmap. * * @type {number} */ get bakeNumSamples(): number; /** * Sets the angular size in degrees of the area used when baking soft shadow boundaries for the * directional light into the lightmap. Range is 0 to 180. Requires {@link bake} to be set to * true and {@link type} to be `"directional"`. Defaults to 0. * * @type {number} */ set bakeArea(value: number); /** * Gets the angular size in degrees of the area used when baking soft shadow boundaries for * the directional light into the lightmap. * * @type {number} */ get bakeArea(): number; /** * Sets the distribution of subdivision of the camera frustum for individual shadow cascades. * Only used if {@link numCascades} is larger than 1. Can be a value in range of 0 and 1. Value * of 0 represents a linear distribution, value of 1 represents a logarithmic distribution. * Defaults to 0.5. Larger value increases the resolution of the shadows in the near distance. * * @type {number} */ set cascadeDistribution(value: number); /** * Gets the distribution of subdivision of the camera frustum for individual shadow cascades. * * @type {number} */ get cascadeDistribution(): number; /** * Sets the normal offset depth bias. Valid range is 0 to 1. Defaults to 0. * * @type {number} */ set normalOffsetBias(value: number); /** * Gets the normal offset depth bias. * * @type {number} */ get normalOffsetBias(): number; /** * Sets the range of the light. Affects omni and spot lights only. Defaults to 10. * * @type {number} */ set range(value: number); /** * Gets the range of the light. * * @type {number} */ get range(): number; /** * Sets the half-angle (measured in degrees from the light's direction axis to the cone edge) * at which the spotlight cone starts to fade off. The full inner beam angle is twice this * value. Affects spot lights only. Defaults to 40 (i.e. an 80-degree full inner beam). * * @type {number} */ set innerConeAngle(value: number); /** * Gets the half-angle (measured in degrees from the light's direction axis to the cone edge) * at which the spotlight cone starts to fade off. * * @type {number} */ get innerConeAngle(): number; /** * Sets the half-angle (measured in degrees from the light's direction axis to the cone edge) * at which the spotlight cone has faded to nothing. The full outer beam angle is twice this * value. Affects spot lights only. Defaults to 45 (i.e. a 90-degree full outer beam). * * @type {number} */ set outerConeAngle(value: number); /** * Gets the half-angle (measured in degrees from the light's direction axis to the cone edge) * at which the spotlight cone has faded to nothing. * * @type {number} */ get outerConeAngle(): number; /** * Sets the fall off mode for the light. This controls the rate at which a light attenuates * from its position. Can be: * * - {@link LIGHTFALLOFF_LINEAR}: Linear. * - {@link LIGHTFALLOFF_INVERSESQUARED}: Inverse squared. * * Affects omni and spot lights only. Defaults to {@link LIGHTFALLOFF_LINEAR}. * * @type {number} */ set falloffMode(value: number); /** * Gets the fall off mode for the light. * * @type {number} */ get falloffMode(): number; /** * Sets the type of shadows being rendered by this light. Can be: * * - {@link SHADOW_PCF1_32F} * - {@link SHADOW_PCF3_32F} * - {@link SHADOW_PCF5_32F} * - {@link SHADOW_PCF1_16F} * - {@link SHADOW_PCF3_16F} * - {@link SHADOW_PCF5_16F} * - {@link SHADOW_VSM_16F} * - {@link SHADOW_VSM_32F} * - {@link SHADOW_PCSS_32F} * * Defaults to {@link SHADOW_PCF3_32F}. * * @type {number} */ set shadowType(value: number); /** * Gets the type of shadows being rendered by this light. * * @type {number} */ get shadowType(): number; /** * Sets the number of samples used for blurring a variance shadow map. Only odd values are * supported; even values are rounded up to the next odd value. Values should be between 1 and * 25. Defaults to 11. * * @type {number} */ set vsmBlurSize(value: number); /** * Gets the number of samples used for blurring a variance shadow map. * * @type {number} */ get vsmBlurSize(): number; /** * Sets the blurring mode for variance shadow maps. Can be: * * - {@link BLUR_BOX}: Box filter. * - {@link BLUR_GAUSSIAN}: Gaussian filter. May look smoother than box, but requires more samples. * * Defaults to {@link BLUR_GAUSSIAN}. * * @type {number} */ set vsmBlurMode(value: number); /** * Gets the blurring mode for variance shadow maps. * * @type {number} */ get vsmBlurMode(): number; /** * Sets the bias used to fight shadow acne when rendering variance shadow maps. Range is 0 to * 1. Defaults to 0.0025. * * @type {number} */ set vsmBias(value: number); /** * Gets the VSM bias value. * * @type {number} */ get vsmBias(): number; /** * Sets the id of the texture asset to be used as the cookie for this light. Only spot and * omni lights can have cookies. Spot lights expect a 2D texture; omni lights expect a * cubemap. Defaults to null. * * @type {number|null} */ set cookieAsset(value: number | null); /** * Gets the id of the texture asset used as the cookie for this light, or null if none is set. * * @type {number|null} */ get cookieAsset(): number | null; /** * Sets the texture to be used as the cookie for this light. Only spot and omni lights can have * cookies. Spot lights expect a 2D texture; omni lights expect a cubemap. Defaults to null. * * @type {Texture|null} */ set cookie(value: Texture | null); /** * Gets the texture to be used as the cookie for this light. * * @type {Texture|null} */ get cookie(): Texture | null; /** * Sets the cookie texture intensity. Defaults to 1. * * @type {number} */ set cookieIntensity(value: number); /** * Gets the cookie texture intensity. * * @type {number} */ get cookieIntensity(): number; /** * Sets whether normal spotlight falloff is active when a cookie texture is set. When set to * false, a spotlight will work like a pure texture projector (only fading with distance). * Defaults to true. * * @type {boolean} */ set cookieFalloff(value: boolean); /** * Gets whether normal spotlight falloff is active when a cookie texture is set. * * @type {boolean} */ get cookieFalloff(): boolean; /** * Sets the color channels of the cookie texture to use. Can be `"r"`, `"g"`, `"b"`, `"a"` or * `"rgb"`. Defaults to `"rgb"`. * * @type {string} */ set cookieChannel(value: string); /** * Gets the color channels of the cookie texture to use. * * @type {string} */ get cookieChannel(): string; /** * Sets the angle for spotlight cookie rotation in degrees. Defaults to 0. * * @type {number} */ set cookieAngle(value: number); /** * Gets the angle for spotlight cookie rotation (in degrees). * * @type {number} */ get cookieAngle(): number; /** * Sets the spotlight cookie scale. Set to null to use no scaling. Defaults to null. * * @type {Vec2|null} */ set cookieScale(value: Vec2 | null); /** * Gets the spotlight cookie scale. * * @type {Vec2|null} */ get cookieScale(): Vec2 | null; /** * Sets the spotlight cookie position offset. Defaults to null. * * @type {Vec2|null} */ set cookieOffset(value: Vec2 | null); /** * Gets the spotlight cookie position offset. * * @type {Vec2|null} */ get cookieOffset(): Vec2 | null; /** * Sets the shadow update mode. This tells the renderer how often shadows must be updated for * this light. Can be: * * - {@link SHADOWUPDATE_NONE}: Don't render shadows. * - {@link SHADOWUPDATE_THISFRAME}: Render shadows only once (then automatically switches to * {@link SHADOWUPDATE_NONE}). * - {@link SHADOWUPDATE_REALTIME}: Render shadows every frame. * * Defaults to {@link SHADOWUPDATE_REALTIME}. * * @type {number} */ set shadowUpdateMode(value: number); /** * Gets the shadow update mode. * * @type {number} */ get shadowUpdateMode(): number; /** * Sets the bitmask that determines which {@link MeshInstance}s are lit by this light. The * value is composed from {@link MASK_AFFECT_DYNAMIC}, {@link MASK_AFFECT_LIGHTMAPPED} and * {@link MASK_BAKE}. The {@link affectDynamic}, {@link affectLightmapped} and {@link bake} * helpers write to the same underlying mask but maintain their own state and are not * recomputed from `mask`, so writing `mask` directly will not update those helpers (and a * subsequent write to a helper may overwrite bits set via `mask`). Defaults to * {@link MASK_AFFECT_DYNAMIC}. * * @type {number} */ set mask(value: number); /** * Gets the mask to determine which {@link MeshInstance}s are lit by this light. * * @type {number} */ get mask(): number; /** * Sets whether the light will affect non-lightmapped objects. Toggles the * {@link MASK_AFFECT_DYNAMIC} bit on {@link mask}. Defaults to true. * * @type {boolean} */ set affectDynamic(value: boolean); /** * Gets whether the light will affect non-lightmapped objects. * * @type {boolean} */ get affectDynamic(): boolean; /** * Sets whether the light will affect lightmapped objects. Toggles the * {@link MASK_AFFECT_LIGHTMAPPED} bit on {@link mask}. Mutually exclusive with {@link bake} on * the mask: enabling one clears the other's mask bit. Defaults to false. * * @type {boolean} */ set affectLightmapped(value: boolean); /** * Gets whether the light will affect lightmapped objects. * * @type {boolean} */ get affectLightmapped(): boolean; /** * Sets whether the light will be rendered into lightmaps. Toggles the {@link MASK_BAKE} bit * on {@link mask}. Mutually exclusive with {@link affectLightmapped} on the mask: enabling one * clears the other's mask bit. Defaults to false. * * @type {boolean} */ set bake(value: boolean); /** * Gets whether the light will be rendered into lightmaps. * * @type {boolean} */ get bake(): boolean; /** * Sets whether the light's direction will contribute to directional lightmaps. The light must * be enabled and {@link bake} set to true. Be aware that the directional lightmap is an * approximation and can only hold a single direction per pixel. Intersecting multiple lights * with {@link bakeDir} set to true may lead to incorrect-looking specular/bump mapping in the * area of intersection. The error is not always visible though, and is highly scene-dependent. * Defaults to true. * * @type {boolean} */ set bakeDir(value: boolean); /** * Gets whether the light's direction will contribute to directional lightmaps. * * @type {boolean} */ get bakeDir(): boolean; /** * Sets whether the light ever moves. This is an optimization hint. Defaults to false. * * @type {boolean} */ set isStatic(value: boolean); /** * Gets whether the light ever moves. * * @type {boolean} */ get isStatic(): boolean; /** * Sets the array of layer IDs ({@link Layer#id}) to which this light should belong. Don't * push/pop/splice or modify this array. If you want to change it, set a new one instead. * Defaults to [{@link LAYERID_WORLD}]. * * @type {number[]} */ set layers(value: number[]); /** * Gets the array of layer IDs ({@link Layer#id}) to which this light should belong. * * @type {number[]} */ get layers(): number[]; /** * Sets an array of SHADOWUPDATE_ settings per shadow cascade. Set to null if not used. * Defaults to null. * * @type {number[]|null} */ set shadowUpdateOverrides(values: number[] | null); /** * Gets an array of SHADOWUPDATE_ settings per shadow cascade. * * @type {number[]|null} */ get shadowUpdateOverrides(): number[] | null; /** * Sets the number of shadow samples used for soft shadows when the shadow type is * {@link SHADOW_PCSS_32F}. This value should be a positive whole number starting at 1. Higher * values result in smoother shadows but can significantly decrease performance. Defaults to 16. * * @type {number} */ set shadowSamples(value: number); /** * Gets the number of shadow samples used for soft shadows. * * @type {number} */ get shadowSamples(): number; /** * Sets the number of blocker samples used for soft shadows when the shadow type is * {@link SHADOW_PCSS_32F}. These samples are used to estimate the distance between the shadow * caster and the shadow receiver, which is then used for the estimation of contact hardening * in the shadow. This value should be a non-negative whole number. Higher values improve * shadow quality by considering more occlusion points, but can decrease performance. When set * to 0, contact hardening is disabled and the shadow has constant softness. Defaults to 16. * Note that this value can be lower than shadowSamples to optimize performance, often without * large impact on quality. * * @type {number} */ set shadowBlockerSamples(value: number); /** * Gets the number of blocker samples used for contact hardening shadows. * * @type {number} */ get shadowBlockerSamples(): number; /** * Sets the size of penumbra for contact hardening shadows. For area lights, acts as a * multiplier with the dimensions of the area light. For punctual and directional lights it's * the area size of the light. Defaults to 1. * * @type {number} */ set penumbraSize(value: number); /** * Gets the size of penumbra for contact hardening shadows. * * @type {number} */ get penumbraSize(): number; /** * Sets the falloff rate for shadow penumbra for contact hardening shadows. This is a value larger * than or equal to 1. This parameter determines how quickly the shadow softens with distance. * Higher values result in a faster softening of the shadow, while lower values produce a more * gradual transition. Defaults to 1. * * @type {number} */ set penumbraFalloff(value: number); /** * Gets the falloff rate for shadow penumbra for contact hardening shadows. * * @type {number} */ get penumbraFalloff(): number; addLightToLayers(): void; removeLightFromLayers(): void; onLayersChanged(oldComp: any, newComp: any): void; onLayerAdded(layer: any): void; onLayerRemoved(layer: any): void; refreshProperties(): void; onCookieAssetSet(): void; onCookieAssetAdd(asset: any): void; onCookieAssetLoad(): void; onCookieAssetRemove(): void; onRemove(): void; } import { Component } from '../component.js'; import { Light } from '../../../scene/light.js'; import type { Color } from '../../../core/math/color.js'; import type { Texture } from '../../../platform/graphics/texture.js'; import type { Vec2 } from '../../../core/math/vec2.js'; import type { LightComponentSystem } from './system.js'; import type { Entity } from '../../entity.js';