babylon.spotLight.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. module BABYLON {
  2. /**
  3. * A spot light is defined by a position, a direction, an angle, and an exponent.
  4. * These values define a cone of light starting from the position, emitting toward the direction.
  5. * The angle, in radians, defines the size (field of illumination) of the spotlight's conical beam,
  6. * and the exponent defines the speed of the decay of the light with distance (reach).
  7. * Documentation: https://doc.babylonjs.com/babylon101/lights
  8. */
  9. export class SpotLight extends ShadowLight {
  10. /*
  11. upVector , rightVector and direction will form the coordinate system for this spot light.
  12. These three vectors will be used as projection matrix when doing texture projection.
  13. Also we have the following rules always holds:
  14. direction cross up = right
  15. right cross direction = up
  16. up cross right = forward
  17. light_near and light_far will control the range of the texture projection. If a plane is
  18. out of the range in spot light space, there is no texture projection.
  19. */
  20. private _angle: number;
  21. /**
  22. * Gets the cone angle of the spot light in Radians.
  23. */
  24. @serialize()
  25. public get angle(): number {
  26. return this._angle
  27. }
  28. /**
  29. * Sets the cone angle of the spot light in Radians.
  30. */
  31. public set angle(value: number) {
  32. this._angle = value;
  33. this._projectionTextureProjectionLightDirty = true;
  34. this.forceProjectionMatrixCompute();
  35. }
  36. private _shadowAngleScale: number;
  37. /**
  38. * Allows scaling the angle of the light for shadow generation only.
  39. */
  40. @serialize()
  41. public get shadowAngleScale(): number {
  42. return this._shadowAngleScale
  43. }
  44. /**
  45. * Allows scaling the angle of the light for shadow generation only.
  46. */
  47. public set shadowAngleScale(value: number) {
  48. this._shadowAngleScale = value;
  49. this.forceProjectionMatrixCompute();
  50. }
  51. /**
  52. * The light decay speed with the distance from the emission spot.
  53. */
  54. @serialize()
  55. public exponent: number;
  56. private _projectionTextureMatrix = Matrix.Zero();
  57. /**
  58. * Allows reading the projecton texture
  59. */
  60. public get projectionTextureMatrix(): Matrix{
  61. return this._projectionTextureMatrix;
  62. }
  63. protected _projectionTextureLightNear : number = 1e-6;
  64. /**
  65. * Gets the near clip of the Spotlight for texture projection.
  66. */
  67. @serialize()
  68. public get projectionTextureLightNear(): number {
  69. return this._projectionTextureLightNear;
  70. }
  71. /**
  72. * Sets the near clip of the Spotlight for texture projection.
  73. */
  74. public set projectionTextureLightNear(value: number) {
  75. this._projectionTextureLightNear = value;
  76. this._projectionTextureProjectionLightDirty = true;
  77. }
  78. protected _projectionTextureLightFar : number = 1000.0;
  79. /**
  80. * Gets the far clip of the Spotlight for texture projection.
  81. */
  82. @serialize()
  83. public get projectionTextureLightFar(): number {
  84. return this._projectionTextureLightFar;
  85. }
  86. /**
  87. * Sets the far clip of the Spotlight for texture projection.
  88. */
  89. public set projectionTextureLightFar(value: number) {
  90. this._projectionTextureLightFar = value;
  91. this._projectionTextureProjectionLightDirty = true;
  92. }
  93. protected _projectionTextureUpDirection: Vector3 = Vector3.Up();
  94. /**
  95. * Gets the Up vector of the Spotlight for texture projection.
  96. */
  97. @serialize()
  98. public get projectionTextureUpDirection(): Vector3 {
  99. return this._projectionTextureUpDirection;
  100. }
  101. /**
  102. * Sets the Up vector of the Spotlight for texture projection.
  103. */
  104. public set projectionTextureUpDirection(value: Vector3) {
  105. this._projectionTextureUpDirection = value;
  106. this._projectionTextureProjectionLightDirty = true;
  107. }
  108. @serializeAsTexture("projectedLightTexture")
  109. private _projectionTexture: Nullable<BaseTexture>;
  110. /**
  111. * Gets the projection texture of the light.
  112. */
  113. public get projectionTexture(): Nullable<BaseTexture> {
  114. return this._projectionTexture;
  115. }
  116. /**
  117. * Sets the projection texture of the light.
  118. */
  119. public set projectionTexture(value: Nullable<BaseTexture>) {
  120. this._projectionTexture = value;
  121. this._projectionTextureDirty = true;
  122. }
  123. private _projectionTextureViewLightDirty = true;
  124. private _projectionTextureProjectionLightDirty = true;
  125. private _projectionTextureDirty = true;
  126. private _projectionTextureViewTargetVector = Vector3.Zero();
  127. private _projectionTextureViewLightMatrix = Matrix.Zero();
  128. private _projectionTextureProjectionLightMatrix = Matrix.Zero();
  129. private _projectionTextureScalingMatrix = Matrix.FromValues(0.5, 0.0, 0.0, 0.0,
  130. 0.0, 0.5, 0.0, 0.0,
  131. 0.0, 0.0, 0.5, 0.0,
  132. 0.5, 0.5, 0.5, 1.0);
  133. /**
  134. * Creates a SpotLight object in the scene. A spot light is a simply light oriented cone.
  135. * It can cast shadows.
  136. * Documentation : http://doc.babylonjs.com/tutorials/lights
  137. * @param name The light friendly name
  138. * @param position The position of the spot light in the scene
  139. * @param direction The direction of the light in the scene
  140. * @param angle The cone angle of the light in Radians
  141. * @param exponent The light decay speed with the distance from the emission spot
  142. * @param scene The scene the lights belongs to
  143. */
  144. constructor(name: string, position: Vector3, direction: Vector3, angle: number, exponent: number, scene: Scene) {
  145. super(name, scene);
  146. this.position = position;
  147. this.direction = direction;
  148. this.angle = angle;
  149. this.exponent = exponent;
  150. }
  151. /**
  152. * Returns the string "SpotLight".
  153. * @returns the class name
  154. */
  155. public getClassName(): string {
  156. return "SpotLight";
  157. }
  158. /**
  159. * Returns the integer 2.
  160. * @returns The light Type id as a constant defines in Light.LIGHTTYPEID_x
  161. */
  162. public getTypeID(): number {
  163. return Light.LIGHTTYPEID_SPOTLIGHT;
  164. }
  165. /**
  166. * Overrides the direction setter to recompute the projection texture view light Matrix.
  167. */
  168. protected _setDirection(value: Vector3) {
  169. super._setDirection(value);
  170. this._projectionTextureViewLightDirty = true;
  171. }
  172. /**
  173. * Overrides the position setter to recompute the projection texture view light Matrix.
  174. */
  175. protected _setPosition(value: Vector3) {
  176. super._setPosition(value);
  177. this._projectionTextureViewLightDirty = true;
  178. }
  179. /**
  180. * Sets the passed matrix "matrix" as perspective projection matrix for the shadows and the passed view matrix with the fov equal to the SpotLight angle and and aspect ratio of 1.0.
  181. * Returns the SpotLight.
  182. */
  183. protected _setDefaultShadowProjectionMatrix(matrix: Matrix, viewMatrix: Matrix, renderList: Array<AbstractMesh>): void {
  184. var activeCamera = this.getScene().activeCamera;
  185. if (!activeCamera) {
  186. return;
  187. }
  188. this._shadowAngleScale = this._shadowAngleScale || 1;
  189. var angle = this._shadowAngleScale * this._angle;
  190. Matrix.PerspectiveFovLHToRef(angle, 1.0,
  191. this.getDepthMinZ(activeCamera), this.getDepthMaxZ(activeCamera), matrix);
  192. }
  193. protected _computeProjectionTextureViewLightMatrix(): void {
  194. this._projectionTextureViewLightDirty = false;
  195. this._projectionTextureDirty = true;
  196. this.position.addToRef(this.direction, this._projectionTextureViewTargetVector);
  197. Matrix.LookAtLHToRef(this.position,
  198. this._projectionTextureViewTargetVector,
  199. this._projectionTextureUpDirection,
  200. this._projectionTextureViewLightMatrix);
  201. }
  202. protected _computeProjectionTextureProjectionLightMatrix(): void {
  203. this._projectionTextureProjectionLightDirty = false;
  204. this._projectionTextureDirty = true;
  205. var light_far = this.projectionTextureLightFar;
  206. var light_near = this.projectionTextureLightNear;
  207. var P = light_far / (light_far - light_near);
  208. var Q = - P * light_near;
  209. var S = 1.0 / Math.tan(this._angle / 2.0);
  210. var A = 1.0;
  211. Matrix.FromValuesToRef(S / A, 0.0, 0.0, 0.0,
  212. 0.0, S, 0.0, 0.0,
  213. 0.0, 0.0, P, 1.0,
  214. 0.0, 0.0, Q, 0.0, this._projectionTextureProjectionLightMatrix);
  215. }
  216. /**
  217. * Main function for light texture projection matrix computing.
  218. */
  219. protected _computeProjectionTextureMatrix(): void {
  220. this._projectionTextureDirty = false;
  221. this._projectionTextureViewLightMatrix.multiplyToRef(this._projectionTextureProjectionLightMatrix, this._projectionTextureMatrix);
  222. this._projectionTextureMatrix.multiplyToRef(this._projectionTextureScalingMatrix, this._projectionTextureMatrix);
  223. }
  224. protected _buildUniformLayout(): void {
  225. this._uniformBuffer.addUniform("vLightData", 4);
  226. this._uniformBuffer.addUniform("vLightDiffuse", 4);
  227. this._uniformBuffer.addUniform("vLightSpecular", 3);
  228. this._uniformBuffer.addUniform("vLightDirection", 3);
  229. this._uniformBuffer.addUniform("shadowsInfo", 3);
  230. this._uniformBuffer.addUniform("depthValues", 2);
  231. this._uniformBuffer.create();
  232. }
  233. /**
  234. * Sets the passed Effect object with the SpotLight transfomed position (or position if not parented) and normalized direction.
  235. * @param effect The effect to update
  236. * @param lightIndex The index of the light in the effect to update
  237. * @returns The spot light
  238. */
  239. public transferToEffect(effect: Effect, lightIndex: string): SpotLight {
  240. var normalizeDirection;
  241. if (this.computeTransformedInformation()) {
  242. this._uniformBuffer.updateFloat4("vLightData",
  243. this.transformedPosition.x,
  244. this.transformedPosition.y,
  245. this.transformedPosition.z,
  246. this.exponent,
  247. lightIndex);
  248. normalizeDirection = Vector3.Normalize(this.transformedDirection);
  249. } else {
  250. this._uniformBuffer.updateFloat4("vLightData",
  251. this.position.x,
  252. this.position.y,
  253. this.position.z,
  254. this.exponent,
  255. lightIndex);
  256. normalizeDirection = Vector3.Normalize(this.direction);
  257. }
  258. this._uniformBuffer.updateFloat4("vLightDirection",
  259. normalizeDirection.x,
  260. normalizeDirection.y,
  261. normalizeDirection.z,
  262. Math.cos(this.angle * 0.5),
  263. lightIndex);
  264. if (this.projectionTexture && this.projectionTexture.isReady()) {
  265. if (this._projectionTextureViewLightDirty) {
  266. this._computeProjectionTextureViewLightMatrix();
  267. }
  268. if (this._projectionTextureProjectionLightDirty) {
  269. this._computeProjectionTextureProjectionLightMatrix();
  270. }
  271. if (this._projectionTextureDirty) {
  272. this._computeProjectionTextureMatrix();
  273. }
  274. effect.setMatrix("textureProjectionMatrix" + lightIndex, this._projectionTextureMatrix);
  275. effect.setTexture("projectionLightSampler" + lightIndex, this.projectionTexture);
  276. }
  277. return this;
  278. }
  279. /**
  280. * Disposes the light and the associated resources.
  281. */
  282. public dispose() : void {
  283. super.dispose();
  284. if (this._projectionTexture){
  285. this._projectionTexture.dispose();
  286. }
  287. }
  288. }
  289. }