import { Vector3D, AssetBase } from '@awayjs/core'; import { LightBase } from '../lights/LightBase'; import { DirectionalLight } from '../lights/DirectionalLight'; import { LightProbe } from '../lights/LightProbe'; import { PointLight } from '../lights/PointLight'; import { ContainerNode } from '@awayjs/view'; /** * LightPickerBase provides an abstract base clase for light picker classes. These classes are responsible for * feeding materials with relevant lights. Usually, StaticLightPicker can be used, but LightPickerBase can be * extended to provide more application-specific dynamic selection of lights. * * @see StaticLightPicker */ export class LightPickerBase extends AssetBase { public static assetType: string = '[asset LightPicker]'; protected _numPointLights: number = 0; protected _numDirectionalLights: number = 0; protected _numCastingPointLights: number = 0; protected _numCastingDirectionalLights: number = 0; protected _numLightProbes: number = 0; protected _allPickedLights: Array; protected _pointLights: Array; protected _castingPointLights: Array; protected _directionalLights: Array; protected _castingDirectionalLights: Array; protected _lightProbes: Array; protected _lightProbeWeights: Array; /** * Creates a new LightPickerBase object. */ constructor() { super(); } /** * Disposes resources used by the light picker. */ public dispose(): void { } /** * @inheritDoc */ public get assetType(): string { return LightPickerBase.assetType; } /** * The maximum amount of directional lights that will be provided. */ public get numDirectionalLights(): number { return this._numDirectionalLights; } /** * The maximum amount of point lights that will be provided. */ public get numPointLights(): number { return this._numPointLights; } /** * The maximum amount of directional lights that cast shadows. */ public get numCastingDirectionalLights(): number { return this._numCastingDirectionalLights; } /** * The amount of point lights that cast shadows. */ public get numCastingPointLights(): number { return this._numCastingPointLights; } /** * The maximum amount of light probes that will be provided. */ public get numLightProbes(): number { return this._numLightProbes; } /** * The collected point lights to be used for shading. */ public get pointLights(): Array { return this._pointLights; } /** * The collected directional lights to be used for shading. */ public get directionalLights(): Array { return this._directionalLights; } /** * The collected point lights that cast shadows to be used for shading. */ public get castingPointLights(): Array { return this._castingPointLights; } /** * The collected directional lights that cast shadows to be used for shading. */ public get castingDirectionalLights(): Array { return this._castingDirectionalLights; } /** * The collected light probes to be used for shading. */ public get lightProbes(): Array { return this._lightProbes; } /** * The weights for each light probe, defining their influence on the object. */ public get lightProbeWeights(): Array { return this._lightProbeWeights; } /** * A collection of all the collected lights. */ public get allPickedLights(): Array { return this._allPickedLights; } /** * Updates set of lights for a given renderable and EntityCollector. Always call super.collectLights() after custom overridden code. */ public collectLights(container: ContainerNode): void { this.updateProbeWeights(container); } /** * Updates the weights for the light probes, based on the renderable's position relative to them. * @param renderable The renderble for which to calculate the light probes' influence. */ private updateProbeWeights(container: ContainerNode): void { // todo: this will cause the same calculations to occur per TriangleGraphic. See if this can be improved. const objectPos: Vector3D = container.getPosition(); let lightPos: Vector3D; const rx: number = objectPos.x, ry: number = objectPos.y, rz: number = objectPos.z; let dx: number, dy: number, dz: number; let w: number, total: number = 0; let i: number; // calculates weights for probes for (i = 0; i < this._numLightProbes; ++i) { lightPos = this._lightProbes[i].transform.matrix3D.position; dx = rx - lightPos.x; dy = ry - lightPos.y; dz = rz - lightPos.z; // weight is inversely proportional to square of distance w = dx * dx + dy * dy + dz * dz; // just... huge if at the same spot w = w > .00001 ? 1 / w : 50000000; this._lightProbeWeights[i] = w; total += w; } // normalize total = 1 / total; for (i = 0; i < this._numLightProbes; ++i) this._lightProbeWeights[i] *= total; } }