reflectionProbe.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import { serializeAsMeshReference, serializeAsVector3, SerializationHelper } from "../Misc/decorators";
  2. import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
  3. import { Matrix, Vector3 } from "../Maths/math.vector";
  4. import { AbstractMesh } from "../Meshes/abstractMesh";
  5. import { Nullable } from "../types";
  6. import { AbstractScene } from "../abstractScene";
  7. import { Scene } from "../scene";
  8. import { Constants } from "../Engines/constants";
  9. declare module "../abstractScene" {
  10. export interface AbstractScene {
  11. /**
  12. * The list of reflection probes added to the scene
  13. * @see http://doc.babylonjs.com/how_to/how_to_use_reflection_probes
  14. */
  15. reflectionProbes: Array<ReflectionProbe>;
  16. /**
  17. * Removes the given reflection probe from this scene.
  18. * @param toRemove The reflection probe to remove
  19. * @returns The index of the removed reflection probe
  20. */
  21. removeReflectionProbe(toRemove: ReflectionProbe): number;
  22. /**
  23. * Adds the given reflection probe to this scene.
  24. * @param newReflectionProbe The reflection probe to add
  25. */
  26. addReflectionProbe(newReflectionProbe: ReflectionProbe): void;
  27. }
  28. }
  29. AbstractScene.prototype.removeReflectionProbe = function(toRemove: ReflectionProbe): number {
  30. if (!this.reflectionProbes) {
  31. return -1;
  32. }
  33. var index = this.reflectionProbes.indexOf(toRemove);
  34. if (index !== -1) {
  35. this.reflectionProbes.splice(index, 1);
  36. }
  37. return index;
  38. };
  39. AbstractScene.prototype.addReflectionProbe = function(newReflectionProbe: ReflectionProbe): void {
  40. if (!this.reflectionProbes) {
  41. this.reflectionProbes = [];
  42. }
  43. this.reflectionProbes.push(newReflectionProbe);
  44. };
  45. /**
  46. * Class used to generate realtime reflection / refraction cube textures
  47. * @see http://doc.babylonjs.com/how_to/how_to_use_reflection_probes
  48. */
  49. export class ReflectionProbe {
  50. private _scene: Scene;
  51. private _renderTargetTexture: RenderTargetTexture;
  52. private _projectionMatrix: Matrix;
  53. private _viewMatrix = Matrix.Identity();
  54. private _target = Vector3.Zero();
  55. private _add = Vector3.Zero();
  56. @serializeAsMeshReference()
  57. private _attachedMesh: Nullable<AbstractMesh>;
  58. private _invertYAxis = false;
  59. /** Gets or sets probe position (center of the cube map) */
  60. @serializeAsVector3()
  61. public position = Vector3.Zero();
  62. /**
  63. * Creates a new reflection probe
  64. * @param name defines the name of the probe
  65. * @param size defines the texture resolution (for each face)
  66. * @param scene defines the hosting scene
  67. * @param generateMipMaps defines if mip maps should be generated automatically (true by default)
  68. * @param useFloat defines if HDR data (flaot data) should be used to store colors (false by default)
  69. */
  70. constructor(
  71. /** defines the name of the probe */
  72. public name: string,
  73. size: number, scene: Scene, generateMipMaps = true, useFloat = false) {
  74. this._scene = scene;
  75. // Create the scene field if not exist.
  76. if (!this._scene.reflectionProbes) {
  77. this._scene.reflectionProbes = new Array<ReflectionProbe>();
  78. }
  79. this._scene.reflectionProbes.push(this);
  80. let textureType = Constants.TEXTURETYPE_UNSIGNED_BYTE;
  81. if (useFloat) {
  82. const caps = this._scene.getEngine().getCaps();
  83. if (caps.textureHalfFloatRender) {
  84. textureType = Constants.TEXTURETYPE_HALF_FLOAT;
  85. }
  86. else if (caps.textureFloatRender) {
  87. textureType = Constants.TEXTURETYPE_FLOAT;
  88. }
  89. }
  90. this._renderTargetTexture = new RenderTargetTexture(name, size, scene, generateMipMaps, true, textureType, true);
  91. this._renderTargetTexture.onBeforeRenderObservable.add((faceIndex: number) => {
  92. switch (faceIndex) {
  93. case 0:
  94. this._add.copyFromFloats(1, 0, 0);
  95. break;
  96. case 1:
  97. this._add.copyFromFloats(-1, 0, 0);
  98. break;
  99. case 2:
  100. this._add.copyFromFloats(0, this._invertYAxis ? 1 : -1, 0);
  101. break;
  102. case 3:
  103. this._add.copyFromFloats(0, this._invertYAxis ? -1 : 1, 0);
  104. break;
  105. case 4:
  106. this._add.copyFromFloats(0, 0, 1);
  107. break;
  108. case 5:
  109. this._add.copyFromFloats(0, 0, -1);
  110. break;
  111. }
  112. if (this._attachedMesh) {
  113. this.position.copyFrom(this._attachedMesh.getAbsolutePosition());
  114. }
  115. this.position.addToRef(this._add, this._target);
  116. Matrix.LookAtLHToRef(this.position, this._target, Vector3.Up(), this._viewMatrix);
  117. if (scene.activeCamera) {
  118. this._projectionMatrix = Matrix.PerspectiveFovLH(Math.PI / 2, 1, scene.activeCamera.minZ, scene.activeCamera.maxZ);
  119. scene.setTransformMatrix(this._viewMatrix, this._projectionMatrix);
  120. }
  121. scene._forcedViewPosition = this.position;
  122. });
  123. this._renderTargetTexture.onAfterUnbindObservable.add(() => {
  124. scene._forcedViewPosition = null;
  125. scene.updateTransformMatrix(true);
  126. });
  127. }
  128. /** Gets or sets the number of samples to use for multi-sampling (0 by default). Required WebGL2 */
  129. public get samples(): number {
  130. return this._renderTargetTexture.samples;
  131. }
  132. public set samples(value: number) {
  133. this._renderTargetTexture.samples = value;
  134. }
  135. /** Gets or sets the refresh rate to use (on every frame by default) */
  136. public get refreshRate(): number {
  137. return this._renderTargetTexture.refreshRate;
  138. }
  139. public set refreshRate(value: number) {
  140. this._renderTargetTexture.refreshRate = value;
  141. }
  142. /**
  143. * Gets the hosting scene
  144. * @returns a Scene
  145. */
  146. public getScene(): Scene {
  147. return this._scene;
  148. }
  149. /** Gets the internal CubeTexture used to render to */
  150. public get cubeTexture(): RenderTargetTexture {
  151. return this._renderTargetTexture;
  152. }
  153. /** Gets the list of meshes to render */
  154. public get renderList(): Nullable<AbstractMesh[]> {
  155. return this._renderTargetTexture.renderList;
  156. }
  157. /**
  158. * Attach the probe to a specific mesh (Rendering will be done from attached mesh's position)
  159. * @param mesh defines the mesh to attach to
  160. */
  161. public attachToMesh(mesh: Nullable<AbstractMesh>): void {
  162. this._attachedMesh = mesh;
  163. }
  164. /**
  165. * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups
  166. * @param renderingGroupId The rendering group id corresponding to its index
  167. * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
  168. */
  169. public setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void {
  170. this._renderTargetTexture.setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil);
  171. }
  172. /**
  173. * Clean all associated resources
  174. */
  175. public dispose() {
  176. var index = this._scene.reflectionProbes.indexOf(this);
  177. if (index !== -1) {
  178. // Remove from the scene if found
  179. this._scene.reflectionProbes.splice(index, 1);
  180. }
  181. if (this._renderTargetTexture) {
  182. this._renderTargetTexture.dispose();
  183. (<any>this._renderTargetTexture) = null;
  184. }
  185. }
  186. /**
  187. * Converts the reflection probe information to a readable string for debug purpose.
  188. * @param fullDetails Supports for multiple levels of logging within scene loading
  189. * @returns the human readable reflection probe info
  190. */
  191. public toString(fullDetails?: boolean): string {
  192. var ret = "Name: " + this.name;
  193. if (fullDetails) {
  194. ret += ", position: " + this.position.toString();
  195. if (this._attachedMesh) {
  196. ret += ", attached mesh: " + this._attachedMesh.name;
  197. }
  198. }
  199. return ret;
  200. }
  201. /**
  202. * Get the class name of the relfection probe.
  203. * @returns "ReflectionProbe"
  204. */
  205. public getClassName(): string {
  206. return "ReflectionProbe";
  207. }
  208. /**
  209. * Serialize the reflection probe to a JSON representation we can easily use in the resepective Parse function.
  210. * @returns The JSON representation of the texture
  211. */
  212. public serialize(): any {
  213. const serializationObject = SerializationHelper.Serialize(this, this._renderTargetTexture.serialize());
  214. serializationObject.isReflectionProbe = true;
  215. return serializationObject;
  216. }
  217. /**
  218. * Parse the JSON representation of a reflection probe in order to recreate the reflection probe in the given scene.
  219. * @param parsedReflectionProbe Define the JSON representation of the reflection probe
  220. * @param scene Define the scene the parsed reflection probe should be instantiated in
  221. * @param rootUrl Define the root url of the parsing sequence in the case of relative dependencies
  222. * @returns The parsed reflection probe if successful
  223. */
  224. public static Parse(parsedReflectionProbe: any, scene: Scene, rootUrl: string): Nullable<ReflectionProbe> {
  225. let reflectionProbe: Nullable<ReflectionProbe> = null;
  226. if (scene.reflectionProbes) {
  227. for (let index = 0; index < scene.reflectionProbes.length; index++) {
  228. const rp = scene.reflectionProbes[index];
  229. if (rp.name === parsedReflectionProbe.name) {
  230. reflectionProbe = rp;
  231. break;
  232. }
  233. }
  234. }
  235. reflectionProbe = SerializationHelper.Parse(() => reflectionProbe || new ReflectionProbe(parsedReflectionProbe.name, parsedReflectionProbe.renderTargetSize, scene, parsedReflectionProbe._generateMipMaps), parsedReflectionProbe, scene, rootUrl);
  236. reflectionProbe.cubeTexture._waitingRenderList = parsedReflectionProbe.renderList;
  237. if (parsedReflectionProbe._attachedMesh) {
  238. reflectionProbe.attachToMesh(scene.getMeshByID(parsedReflectionProbe._attachedMesh));
  239. }
  240. return reflectionProbe;
  241. }
  242. }