light.ts 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. import { serialize, SerializationHelper, serializeAsColor3, expandToProperty } from "../Misc/decorators";
  2. import { Nullable } from "../types";
  3. import { Scene } from "../scene";
  4. import { Vector3, Color3 } from "../Maths/math";
  5. import { Node } from "../node";
  6. import { AbstractMesh } from "../Meshes/abstractMesh";
  7. import { Effect } from "../Materials/effect";
  8. import { UniformBuffer } from "../Materials/uniformBuffer";
  9. import { IShadowGenerator } from "./Shadows/shadowGenerator";
  10. import { _TypeStore } from '../Misc/typeStore';
  11. /**
  12. * Base class of all the lights in Babylon. It groups all the generic information about lights.
  13. * Lights are used, as you would expect, to affect how meshes are seen, in terms of both illumination and colour.
  14. * All meshes allow light to pass through them unless shadow generation is activated. The default number of lights allowed is four but this can be increased.
  15. */
  16. export abstract class Light extends Node {
  17. /**
  18. * Falloff Default: light is falling off following the material specification:
  19. * standard material is using standard falloff whereas pbr material can request special falloff per materials.
  20. */
  21. public static readonly FALLOFF_DEFAULT = 0;
  22. /**
  23. * Falloff Physical: light is falling off following the inverse squared distance law.
  24. */
  25. public static readonly FALLOFF_PHYSICAL = 1;
  26. /**
  27. * Falloff gltf: light is falling off as described in the gltf moving to PBR document
  28. * to enhance interoperability with other engines.
  29. */
  30. public static readonly FALLOFF_GLTF = 2;
  31. /**
  32. * Falloff Standard: light is falling off like in the standard material
  33. * to enhance interoperability with other materials.
  34. */
  35. public static readonly FALLOFF_STANDARD = 3;
  36. //lightmapMode Consts
  37. /**
  38. * If every light affecting the material is in this lightmapMode,
  39. * material.lightmapTexture adds or multiplies
  40. * (depends on material.useLightmapAsShadowmap)
  41. * after every other light calculations.
  42. */
  43. public static readonly LIGHTMAP_DEFAULT = 0;
  44. /**
  45. * material.lightmapTexture as only diffuse lighting from this light
  46. * adds only specular lighting from this light
  47. * adds dynamic shadows
  48. */
  49. public static readonly LIGHTMAP_SPECULAR = 1;
  50. /**
  51. * material.lightmapTexture as only lighting
  52. * no light calculation from this light
  53. * only adds dynamic shadows from this light
  54. */
  55. public static readonly LIGHTMAP_SHADOWSONLY = 2;
  56. // Intensity Mode Consts
  57. /**
  58. * Each light type uses the default quantity according to its type:
  59. * point/spot lights use luminous intensity
  60. * directional lights use illuminance
  61. */
  62. public static readonly INTENSITYMODE_AUTOMATIC = 0;
  63. /**
  64. * lumen (lm)
  65. */
  66. public static readonly INTENSITYMODE_LUMINOUSPOWER = 1;
  67. /**
  68. * candela (lm/sr)
  69. */
  70. public static readonly INTENSITYMODE_LUMINOUSINTENSITY = 2;
  71. /**
  72. * lux (lm/m^2)
  73. */
  74. public static readonly INTENSITYMODE_ILLUMINANCE = 3;
  75. /**
  76. * nit (cd/m^2)
  77. */
  78. public static readonly INTENSITYMODE_LUMINANCE = 4;
  79. // Light types ids const.
  80. /**
  81. * Light type const id of the point light.
  82. */
  83. public static readonly LIGHTTYPEID_POINTLIGHT = 0;
  84. /**
  85. * Light type const id of the directional light.
  86. */
  87. public static readonly LIGHTTYPEID_DIRECTIONALLIGHT = 1;
  88. /**
  89. * Light type const id of the spot light.
  90. */
  91. public static readonly LIGHTTYPEID_SPOTLIGHT = 2;
  92. /**
  93. * Light type const id of the hemispheric light.
  94. */
  95. public static readonly LIGHTTYPEID_HEMISPHERICLIGHT = 3;
  96. /**
  97. * Diffuse gives the basic color to an object.
  98. */
  99. @serializeAsColor3()
  100. public diffuse = new Color3(1.0, 1.0, 1.0);
  101. /**
  102. * Specular produces a highlight color on an object.
  103. * Note: This is note affecting PBR materials.
  104. */
  105. @serializeAsColor3()
  106. public specular = new Color3(1.0, 1.0, 1.0);
  107. /**
  108. * Defines the falloff type for this light. This lets overrriding how punctual light are
  109. * falling off base on range or angle.
  110. * This can be set to any values in Light.FALLOFF_x.
  111. *
  112. * Note: This is only useful for PBR Materials at the moment. This could be extended if required to
  113. * other types of materials.
  114. */
  115. @serialize()
  116. public falloffType = Light.FALLOFF_DEFAULT;
  117. /**
  118. * Strength of the light.
  119. * Note: By default it is define in the framework own unit.
  120. * Note: In PBR materials the intensityMode can be use to chose what unit the intensity is defined in.
  121. */
  122. @serialize()
  123. public intensity = 1.0;
  124. private _range = Number.MAX_VALUE;
  125. protected _inverseSquaredRange = 0;
  126. /**
  127. * Defines how far from the source the light is impacting in scene units.
  128. * Note: Unused in PBR material as the distance light falloff is defined following the inverse squared falloff.
  129. */
  130. @serialize()
  131. public get range(): number {
  132. return this._range;
  133. }
  134. /**
  135. * Defines how far from the source the light is impacting in scene units.
  136. * Note: Unused in PBR material as the distance light falloff is defined following the inverse squared falloff.
  137. */
  138. public set range(value: number) {
  139. this._range = value;
  140. this._inverseSquaredRange = 1.0 / (this.range * this.range);
  141. }
  142. /**
  143. * Cached photometric scale default to 1.0 as the automatic intensity mode defaults to 1.0 for every type
  144. * of light.
  145. */
  146. private _photometricScale = 1.0;
  147. private _intensityMode: number = Light.INTENSITYMODE_AUTOMATIC;
  148. /**
  149. * Gets the photometric scale used to interpret the intensity.
  150. * This is only relevant with PBR Materials where the light intensity can be defined in a physical way.
  151. */
  152. @serialize()
  153. public get intensityMode(): number {
  154. return this._intensityMode;
  155. }
  156. /**
  157. * Sets the photometric scale used to interpret the intensity.
  158. * This is only relevant with PBR Materials where the light intensity can be defined in a physical way.
  159. */
  160. public set intensityMode(value: number) {
  161. this._intensityMode = value;
  162. this._computePhotometricScale();
  163. }
  164. private _radius = 0.00001;
  165. /**
  166. * Gets the light radius used by PBR Materials to simulate soft area lights.
  167. */
  168. @serialize()
  169. public get radius(): number {
  170. return this._radius;
  171. }
  172. /**
  173. * sets the light radius used by PBR Materials to simulate soft area lights.
  174. */
  175. public set radius(value: number) {
  176. this._radius = value;
  177. this._computePhotometricScale();
  178. }
  179. @serialize()
  180. private _renderPriority: number;
  181. /**
  182. * Defines the rendering priority of the lights. It can help in case of fallback or number of lights
  183. * exceeding the number allowed of the materials.
  184. */
  185. @expandToProperty("_reorderLightsInScene")
  186. public renderPriority: number = 0;
  187. @serialize("shadowEnabled")
  188. private _shadowEnabled: boolean = true;
  189. /**
  190. * Gets wether or not the shadows are enabled for this light. This can help turning off/on shadow without detaching
  191. * the current shadow generator.
  192. */
  193. public get shadowEnabled(): boolean {
  194. return this._shadowEnabled;
  195. }
  196. /**
  197. * Sets wether or not the shadows are enabled for this light. This can help turning off/on shadow without detaching
  198. * the current shadow generator.
  199. */
  200. public set shadowEnabled(value: boolean) {
  201. if (this._shadowEnabled === value) {
  202. return;
  203. }
  204. this._shadowEnabled = value;
  205. this._markMeshesAsLightDirty();
  206. }
  207. private _includedOnlyMeshes: AbstractMesh[];
  208. /**
  209. * Gets the only meshes impacted by this light.
  210. */
  211. public get includedOnlyMeshes(): AbstractMesh[] {
  212. return this._includedOnlyMeshes;
  213. }
  214. /**
  215. * Sets the only meshes impacted by this light.
  216. */
  217. public set includedOnlyMeshes(value: AbstractMesh[]) {
  218. this._includedOnlyMeshes = value;
  219. this._hookArrayForIncludedOnly(value);
  220. }
  221. private _excludedMeshes: AbstractMesh[];
  222. /**
  223. * Gets the meshes not impacted by this light.
  224. */
  225. public get excludedMeshes(): AbstractMesh[] {
  226. return this._excludedMeshes;
  227. }
  228. /**
  229. * Sets the meshes not impacted by this light.
  230. */
  231. public set excludedMeshes(value: AbstractMesh[]) {
  232. this._excludedMeshes = value;
  233. this._hookArrayForExcluded(value);
  234. }
  235. @serialize("excludeWithLayerMask")
  236. private _excludeWithLayerMask = 0;
  237. /**
  238. * Gets the layer id use to find what meshes are not impacted by the light.
  239. * Inactive if 0
  240. */
  241. public get excludeWithLayerMask(): number {
  242. return this._excludeWithLayerMask;
  243. }
  244. /**
  245. * Sets the layer id use to find what meshes are not impacted by the light.
  246. * Inactive if 0
  247. */
  248. public set excludeWithLayerMask(value: number) {
  249. this._excludeWithLayerMask = value;
  250. this._resyncMeshes();
  251. }
  252. @serialize("includeOnlyWithLayerMask")
  253. private _includeOnlyWithLayerMask = 0;
  254. /**
  255. * Gets the layer id use to find what meshes are impacted by the light.
  256. * Inactive if 0
  257. */
  258. public get includeOnlyWithLayerMask(): number {
  259. return this._includeOnlyWithLayerMask;
  260. }
  261. /**
  262. * Sets the layer id use to find what meshes are impacted by the light.
  263. * Inactive if 0
  264. */
  265. public set includeOnlyWithLayerMask(value: number) {
  266. this._includeOnlyWithLayerMask = value;
  267. this._resyncMeshes();
  268. }
  269. @serialize("lightmapMode")
  270. private _lightmapMode = 0;
  271. /**
  272. * Gets the lightmap mode of this light (should be one of the constants defined by Light.LIGHTMAP_x)
  273. */
  274. public get lightmapMode(): number {
  275. return this._lightmapMode;
  276. }
  277. /**
  278. * Sets the lightmap mode of this light (should be one of the constants defined by Light.LIGHTMAP_x)
  279. */
  280. public set lightmapMode(value: number) {
  281. if (this._lightmapMode === value) {
  282. return;
  283. }
  284. this._lightmapMode = value;
  285. this._markMeshesAsLightDirty();
  286. }
  287. /**
  288. * Shadow generator associted to the light.
  289. * @hidden Internal use only.
  290. */
  291. public _shadowGenerator: Nullable<IShadowGenerator>;
  292. /**
  293. * @hidden Internal use only.
  294. */
  295. public _excludedMeshesIds = new Array<string>();
  296. /**
  297. * @hidden Internal use only.
  298. */
  299. public _includedOnlyMeshesIds = new Array<string>();
  300. /**
  301. * The current light unifom buffer.
  302. * @hidden Internal use only.
  303. */
  304. public _uniformBuffer: UniformBuffer;
  305. /**
  306. * Creates a Light object in the scene.
  307. * Documentation : https://doc.babylonjs.com/babylon101/lights
  308. * @param name The firendly name of the light
  309. * @param scene The scene the light belongs too
  310. */
  311. constructor(name: string, scene: Scene) {
  312. super(name, scene);
  313. this.getScene().addLight(this);
  314. this._uniformBuffer = new UniformBuffer(this.getScene().getEngine());
  315. this._buildUniformLayout();
  316. this.includedOnlyMeshes = new Array<AbstractMesh>();
  317. this.excludedMeshes = new Array<AbstractMesh>();
  318. this._resyncMeshes();
  319. }
  320. protected abstract _buildUniformLayout(): void;
  321. /**
  322. * Sets the passed Effect "effect" with the Light information.
  323. * @param effect The effect to update
  324. * @param lightIndex The index of the light in the effect to update
  325. * @returns The light
  326. */
  327. public abstract transferToEffect(effect: Effect, lightIndex: string): Light;
  328. /**
  329. * Returns the string "Light".
  330. * @returns the class name
  331. */
  332. public getClassName(): string {
  333. return "Light";
  334. }
  335. /** @hidden */
  336. public readonly _isLight = true;
  337. /**
  338. * Converts the light information to a readable string for debug purpose.
  339. * @param fullDetails Supports for multiple levels of logging within scene loading
  340. * @returns the human readable light info
  341. */
  342. public toString(fullDetails?: boolean): string {
  343. var ret = "Name: " + this.name;
  344. ret += ", type: " + (["Point", "Directional", "Spot", "Hemispheric"])[this.getTypeID()];
  345. if (this.animations) {
  346. for (var i = 0; i < this.animations.length; i++) {
  347. ret += ", animation[0]: " + this.animations[i].toString(fullDetails);
  348. }
  349. }
  350. if (fullDetails) {
  351. }
  352. return ret;
  353. }
  354. /** @hidden */
  355. protected _syncParentEnabledState() {
  356. super._syncParentEnabledState();
  357. this._resyncMeshes();
  358. }
  359. /**
  360. * Set the enabled state of this node.
  361. * @param value - the new enabled state
  362. */
  363. public setEnabled(value: boolean): void {
  364. super.setEnabled(value);
  365. this._resyncMeshes();
  366. }
  367. /**
  368. * Returns the Light associated shadow generator if any.
  369. * @return the associated shadow generator.
  370. */
  371. public getShadowGenerator(): Nullable<IShadowGenerator> {
  372. return this._shadowGenerator;
  373. }
  374. /**
  375. * Returns a Vector3, the absolute light position in the World.
  376. * @returns the world space position of the light
  377. */
  378. public getAbsolutePosition(): Vector3 {
  379. return Vector3.Zero();
  380. }
  381. /**
  382. * Specifies if the light will affect the passed mesh.
  383. * @param mesh The mesh to test against the light
  384. * @return true the mesh is affected otherwise, false.
  385. */
  386. public canAffectMesh(mesh: AbstractMesh): boolean {
  387. if (!mesh) {
  388. return true;
  389. }
  390. if (this.includedOnlyMeshes && this.includedOnlyMeshes.length > 0 && this.includedOnlyMeshes.indexOf(mesh) === -1) {
  391. return false;
  392. }
  393. if (this.excludedMeshes && this.excludedMeshes.length > 0 && this.excludedMeshes.indexOf(mesh) !== -1) {
  394. return false;
  395. }
  396. if (this.includeOnlyWithLayerMask !== 0 && (this.includeOnlyWithLayerMask & mesh.layerMask) === 0) {
  397. return false;
  398. }
  399. if (this.excludeWithLayerMask !== 0 && this.excludeWithLayerMask & mesh.layerMask) {
  400. return false;
  401. }
  402. return true;
  403. }
  404. /**
  405. * Sort function to order lights for rendering.
  406. * @param a First Light object to compare to second.
  407. * @param b Second Light object to compare first.
  408. * @return -1 to reduce's a's index relative to be, 0 for no change, 1 to increase a's index relative to b.
  409. */
  410. public static CompareLightsPriority(a: Light, b: Light): number {
  411. //shadow-casting lights have priority over non-shadow-casting lights
  412. //the renderPrioirty is a secondary sort criterion
  413. if (a.shadowEnabled !== b.shadowEnabled) {
  414. return (b.shadowEnabled ? 1 : 0) - (a.shadowEnabled ? 1 : 0);
  415. }
  416. return b.renderPriority - a.renderPriority;
  417. }
  418. /**
  419. * Releases resources associated with this node.
  420. * @param doNotRecurse Set to true to not recurse into each children (recurse into each children by default)
  421. * @param disposeMaterialAndTextures Set to true to also dispose referenced materials and textures (false by default)
  422. */
  423. public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
  424. if (this._shadowGenerator) {
  425. this._shadowGenerator.dispose();
  426. this._shadowGenerator = null;
  427. }
  428. // Animations
  429. this.getScene().stopAnimation(this);
  430. // Remove from meshes
  431. for (var mesh of this.getScene().meshes) {
  432. mesh._removeLightSource(this);
  433. }
  434. this._uniformBuffer.dispose();
  435. // Remove from scene
  436. this.getScene().removeLight(this);
  437. super.dispose(doNotRecurse, disposeMaterialAndTextures);
  438. }
  439. /**
  440. * Returns the light type ID (integer).
  441. * @returns The light Type id as a constant defines in Light.LIGHTTYPEID_x
  442. */
  443. public getTypeID(): number {
  444. return 0;
  445. }
  446. /**
  447. * Returns the intensity scaled by the Photometric Scale according to the light type and intensity mode.
  448. * @returns the scaled intensity in intensity mode unit
  449. */
  450. public getScaledIntensity() {
  451. return this._photometricScale * this.intensity;
  452. }
  453. /**
  454. * Returns a new Light object, named "name", from the current one.
  455. * @param name The name of the cloned light
  456. * @returns the new created light
  457. */
  458. public clone(name: string): Nullable<Light> {
  459. let constructor = Light.GetConstructorFromName(this.getTypeID(), name, this.getScene());
  460. if (!constructor) {
  461. return null;
  462. }
  463. return SerializationHelper.Clone(constructor, this);
  464. }
  465. /**
  466. * Serializes the current light into a Serialization object.
  467. * @returns the serialized object.
  468. */
  469. public serialize(): any {
  470. var serializationObject = SerializationHelper.Serialize(this);
  471. // Type
  472. serializationObject.type = this.getTypeID();
  473. // Parent
  474. if (this.parent) {
  475. serializationObject.parentId = this.parent.id;
  476. }
  477. // Inclusion / exclusions
  478. if (this.excludedMeshes.length > 0) {
  479. serializationObject.excludedMeshesIds = [];
  480. this.excludedMeshes.forEach((mesh: AbstractMesh) => {
  481. serializationObject.excludedMeshesIds.push(mesh.id);
  482. });
  483. }
  484. if (this.includedOnlyMeshes.length > 0) {
  485. serializationObject.includedOnlyMeshesIds = [];
  486. this.includedOnlyMeshes.forEach((mesh: AbstractMesh) => {
  487. serializationObject.includedOnlyMeshesIds.push(mesh.id);
  488. });
  489. }
  490. // Animations
  491. SerializationHelper.AppendSerializedAnimations(this, serializationObject);
  492. serializationObject.ranges = this.serializeAnimationRanges();
  493. return serializationObject;
  494. }
  495. /**
  496. * Creates a new typed light from the passed type (integer) : point light = 0, directional light = 1, spot light = 2, hemispheric light = 3.
  497. * This new light is named "name" and added to the passed scene.
  498. * @param type Type according to the types available in Light.LIGHTTYPEID_x
  499. * @param name The friendly name of the light
  500. * @param scene The scene the new light will belong to
  501. * @returns the constructor function
  502. */
  503. static GetConstructorFromName(type: number, name: string, scene: Scene): Nullable<() => Light> {
  504. let constructorFunc = Node.Construct("Light_Type_" + type, name, scene);
  505. if (constructorFunc) {
  506. return <() => Light>constructorFunc;
  507. }
  508. // Default to no light for none present once.
  509. return null;
  510. }
  511. /**
  512. * Parses the passed "parsedLight" and returns a new instanced Light from this parsing.
  513. * @param parsedLight The JSON representation of the light
  514. * @param scene The scene to create the parsed light in
  515. * @returns the created light after parsing
  516. */
  517. public static Parse(parsedLight: any, scene: Scene): Nullable<Light> {
  518. let constructor = Light.GetConstructorFromName(parsedLight.type, parsedLight.name, scene);
  519. if (!constructor) {
  520. return null;
  521. }
  522. var light = SerializationHelper.Parse(constructor, parsedLight, scene);
  523. // Inclusion / exclusions
  524. if (parsedLight.excludedMeshesIds) {
  525. light._excludedMeshesIds = parsedLight.excludedMeshesIds;
  526. }
  527. if (parsedLight.includedOnlyMeshesIds) {
  528. light._includedOnlyMeshesIds = parsedLight.includedOnlyMeshesIds;
  529. }
  530. // Parent
  531. if (parsedLight.parentId) {
  532. light._waitingParentId = parsedLight.parentId;
  533. }
  534. // Falloff
  535. if (parsedLight.falloffType !== undefined) {
  536. light.falloffType = parsedLight.falloffType;
  537. }
  538. // Lightmaps
  539. if (parsedLight.lightmapMode !== undefined) {
  540. light.lightmapMode = parsedLight.lightmapMode;
  541. }
  542. // Animations
  543. if (parsedLight.animations) {
  544. for (var animationIndex = 0; animationIndex < parsedLight.animations.length; animationIndex++) {
  545. var parsedAnimation = parsedLight.animations[animationIndex];
  546. const internalClass = _TypeStore.GetClass("BABYLON.Animation");
  547. if (internalClass) {
  548. light.animations.push(internalClass.Parse(parsedAnimation));
  549. }
  550. }
  551. Node.ParseAnimationRanges(light, parsedLight, scene);
  552. }
  553. if (parsedLight.autoAnimate) {
  554. scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, parsedLight.autoAnimateSpeed || 1.0);
  555. }
  556. return light;
  557. }
  558. private _hookArrayForExcluded(array: AbstractMesh[]): void {
  559. var oldPush = array.push;
  560. array.push = (...items: AbstractMesh[]) => {
  561. var result = oldPush.apply(array, items);
  562. for (var item of items) {
  563. item._resyncLighSource(this);
  564. }
  565. return result;
  566. };
  567. var oldSplice = array.splice;
  568. array.splice = (index: number, deleteCount?: number) => {
  569. var deleted = oldSplice.apply(array, [index, deleteCount]);
  570. for (var item of deleted) {
  571. item._resyncLighSource(this);
  572. }
  573. return deleted;
  574. };
  575. for (var item of array) {
  576. item._resyncLighSource(this);
  577. }
  578. }
  579. private _hookArrayForIncludedOnly(array: AbstractMesh[]): void {
  580. var oldPush = array.push;
  581. array.push = (...items: AbstractMesh[]) => {
  582. var result = oldPush.apply(array, items);
  583. this._resyncMeshes();
  584. return result;
  585. };
  586. var oldSplice = array.splice;
  587. array.splice = (index: number, deleteCount?: number) => {
  588. var deleted = oldSplice.apply(array, [index, deleteCount]);
  589. this._resyncMeshes();
  590. return deleted;
  591. };
  592. this._resyncMeshes();
  593. }
  594. private _resyncMeshes() {
  595. for (var mesh of this.getScene().meshes) {
  596. mesh._resyncLighSource(this);
  597. }
  598. }
  599. /**
  600. * Forces the meshes to update their light related information in their rendering used effects
  601. * @hidden Internal Use Only
  602. */
  603. public _markMeshesAsLightDirty() {
  604. for (var mesh of this.getScene().meshes) {
  605. if (mesh.lightSources.indexOf(this) !== -1) {
  606. mesh._markSubMeshesAsLightDirty();
  607. }
  608. }
  609. }
  610. /**
  611. * Recomputes the cached photometric scale if needed.
  612. */
  613. private _computePhotometricScale(): void {
  614. this._photometricScale = this._getPhotometricScale();
  615. this.getScene().resetCachedMaterial();
  616. }
  617. /**
  618. * Returns the Photometric Scale according to the light type and intensity mode.
  619. */
  620. private _getPhotometricScale() {
  621. let photometricScale = 0.0;
  622. let lightTypeID = this.getTypeID();
  623. //get photometric mode
  624. let photometricMode = this.intensityMode;
  625. if (photometricMode === Light.INTENSITYMODE_AUTOMATIC) {
  626. if (lightTypeID === Light.LIGHTTYPEID_DIRECTIONALLIGHT) {
  627. photometricMode = Light.INTENSITYMODE_ILLUMINANCE;
  628. } else {
  629. photometricMode = Light.INTENSITYMODE_LUMINOUSINTENSITY;
  630. }
  631. }
  632. //compute photometric scale
  633. switch (lightTypeID) {
  634. case Light.LIGHTTYPEID_POINTLIGHT:
  635. case Light.LIGHTTYPEID_SPOTLIGHT:
  636. switch (photometricMode) {
  637. case Light.INTENSITYMODE_LUMINOUSPOWER:
  638. photometricScale = 1.0 / (4.0 * Math.PI);
  639. break;
  640. case Light.INTENSITYMODE_LUMINOUSINTENSITY:
  641. photometricScale = 1.0;
  642. break;
  643. case Light.INTENSITYMODE_LUMINANCE:
  644. photometricScale = this.radius * this.radius;
  645. break;
  646. }
  647. break;
  648. case Light.LIGHTTYPEID_DIRECTIONALLIGHT:
  649. switch (photometricMode) {
  650. case Light.INTENSITYMODE_ILLUMINANCE:
  651. photometricScale = 1.0;
  652. break;
  653. case Light.INTENSITYMODE_LUMINANCE:
  654. // When radius (and therefore solid angle) is non-zero a directional lights brightness can be specified via central (peak) luminance.
  655. // For a directional light the 'radius' defines the angular radius (in radians) rather than world-space radius (e.g. in metres).
  656. let apexAngleRadians = this.radius;
  657. // Impose a minimum light angular size to avoid the light becoming an infinitely small angular light source (i.e. a dirac delta function).
  658. apexAngleRadians = Math.max(apexAngleRadians, 0.001);
  659. let solidAngle = 2.0 * Math.PI * (1.0 - Math.cos(apexAngleRadians));
  660. photometricScale = solidAngle;
  661. break;
  662. }
  663. break;
  664. case Light.LIGHTTYPEID_HEMISPHERICLIGHT:
  665. // No fall off in hemisperic light.
  666. photometricScale = 1.0;
  667. break;
  668. }
  669. return photometricScale;
  670. }
  671. /**
  672. * Reorder the light in the scene according to their defined priority.
  673. * @hidden Internal Use Only
  674. */
  675. public _reorderLightsInScene(): void {
  676. var scene = this.getScene();
  677. if (this._renderPriority != 0) {
  678. scene.requireLightSorting = true;
  679. }
  680. this.getScene().sortLightsByPriority();
  681. }
  682. /**
  683. * Prepares the list of defines specific to the light type.
  684. * @param defines the list of defines
  685. * @param lightIndex defines the index of the light for the effect
  686. */
  687. public abstract prepareLightSpecificDefines(defines: any, lightIndex: number): void;
  688. }