reflectionProbe.js 12 KB

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