screenSpaceReflectionPostProcess.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import { Nullable } from "../types";
  2. import { Camera } from "../Cameras/camera";
  3. import { Effect } from "../Materials/effect";
  4. import { PostProcess, PostProcessOptions } from "./postProcess";
  5. import { Constants } from "../Engines/constants";
  6. import { GeometryBufferRenderer } from '../Rendering/geometryBufferRenderer';
  7. import { serialize, SerializationHelper } from '../Misc/decorators';
  8. import { PrePassRenderer } from "../Rendering/prePassRenderer";
  9. import { ScreenSpaceReflectionsConfiguration } from "../Rendering/screenSpaceReflectionsConfiguration";
  10. import "../Shaders/screenSpaceReflection.fragment";
  11. import { _TypeStore } from '../Misc/typeStore';
  12. declare type Engine = import("../Engines/engine").Engine;
  13. declare type Scene = import("../scene").Scene;
  14. /**
  15. * The ScreenSpaceReflectionPostProcess performs realtime reflections using only and only the available informations on the screen (positions and normals).
  16. * Basically, the screen space reflection post-process will compute reflections according the material's reflectivity.
  17. */
  18. export class ScreenSpaceReflectionPostProcess extends PostProcess {
  19. /**
  20. * Gets or sets a reflection threshold mainly used to adjust the reflection's height.
  21. */
  22. @serialize()
  23. public threshold: number = 1.2;
  24. /**
  25. * Gets or sets the current reflection strength. 1.0 is an ideal value but can be increased/decreased for particular results.
  26. */
  27. @serialize()
  28. public strength: number = 1;
  29. /**
  30. * Gets or sets the falloff exponent used while computing fresnel. More the exponent is high, more the reflections will be discrete.
  31. */
  32. @serialize()
  33. public reflectionSpecularFalloffExponent: number = 3;
  34. /**
  35. * Gets or sets the step size used to iterate until the effect finds the color of the reflection's pixel. Typically in interval [0.1, 1.0]
  36. */
  37. @serialize()
  38. public step: number = 1.0;
  39. /**
  40. * Gets or sets the factor applied when computing roughness. Default value is 0.2.
  41. */
  42. @serialize()
  43. public roughnessFactor: number = 0.2;
  44. private _forceGeometryBuffer: boolean = false;
  45. private _geometryBufferRenderer: Nullable<GeometryBufferRenderer>;
  46. private _prePassRenderer: PrePassRenderer;
  47. private _enableSmoothReflections: boolean = false;
  48. private _reflectionSamples: number = 64;
  49. private _smoothSteps: number = 5;
  50. /**
  51. * Gets a string identifying the name of the class
  52. * @returns "ScreenSpaceReflectionPostProcess" string
  53. */
  54. public getClassName(): string {
  55. return "ScreenSpaceReflectionPostProcess";
  56. }
  57. /**
  58. * Creates a new instance of ScreenSpaceReflectionPostProcess.
  59. * @param name The name of the effect.
  60. * @param scene The scene containing the objects to calculate reflections.
  61. * @param options The required width/height ratio to downsize to before computing the render pass.
  62. * @param camera The camera to apply the render pass to.
  63. * @param samplingMode The sampling mode to be used when computing the pass. (default: 0)
  64. * @param engine The engine which the post process will be applied. (default: current engine)
  65. * @param reusable If the post process can be reused on the same frame. (default: false)
  66. * @param textureType Type of textures used when performing the post process. (default: 0)
  67. * @param blockCompilation If compilation of the shader should not be done in the constructor. The updateEffect method can be used to compile the shader at a later time. (default: false)
  68. * @param forceGeometryBuffer If this post process should use geometry buffer instead of prepass (default: false)
  69. */
  70. constructor(name: string, scene: Scene, options: number | PostProcessOptions, camera: Nullable<Camera>, samplingMode?: number, engine?: Engine, reusable?: boolean, textureType: number = Constants.TEXTURETYPE_UNSIGNED_INT, blockCompilation = false, forceGeometryBuffer = false) {
  71. super(name, "screenSpaceReflection", [
  72. "projection", "view", "threshold", "reflectionSpecularFalloffExponent", "strength", "step", "roughnessFactor"
  73. ], [
  74. "textureSampler", "normalSampler", "positionSampler", "reflectivitySampler"
  75. ], options, camera, samplingMode, engine, reusable,
  76. "#define SSR_SUPPORTED\n#define REFLECTION_SAMPLES 64\n#define SMOOTH_STEPS 5\n",
  77. textureType, undefined, null, blockCompilation);
  78. this._forceGeometryBuffer = forceGeometryBuffer;
  79. if (this._forceGeometryBuffer) {
  80. // Get geometry buffer renderer and update effect
  81. const geometryBufferRenderer = scene.enableGeometryBufferRenderer();
  82. if (geometryBufferRenderer) {
  83. if (geometryBufferRenderer.isSupported) {
  84. geometryBufferRenderer.enablePosition = true;
  85. geometryBufferRenderer.enableReflectivity = true;
  86. this._geometryBufferRenderer = geometryBufferRenderer;
  87. }
  88. }
  89. } else {
  90. this._prePassRenderer = <PrePassRenderer>scene.enablePrePassRenderer();
  91. this._prePassRenderer.markAsDirty();
  92. this._prePassEffectConfiguration = new ScreenSpaceReflectionsConfiguration();
  93. }
  94. this._updateEffectDefines();
  95. // On apply, send uniforms
  96. this.onApply = (effect: Effect) => {
  97. const geometryBufferRenderer = this._geometryBufferRenderer;
  98. const prePassRenderer = this._prePassRenderer;
  99. if (!prePassRenderer && !geometryBufferRenderer) {
  100. return;
  101. }
  102. if (geometryBufferRenderer) {
  103. // Samplers
  104. const positionIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.POSITION_TEXTURE_TYPE);
  105. const roughnessIndex = geometryBufferRenderer.getTextureIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE);
  106. effect.setTexture("normalSampler", geometryBufferRenderer.getGBuffer().textures[1]);
  107. effect.setTexture("positionSampler", geometryBufferRenderer.getGBuffer().textures[positionIndex]);
  108. effect.setTexture("reflectivitySampler", geometryBufferRenderer.getGBuffer().textures[roughnessIndex]);
  109. } else {
  110. // Samplers
  111. const positionIndex = prePassRenderer.getIndex(Constants.PREPASS_POSITION_TEXTURE_TYPE);
  112. const roughnessIndex = prePassRenderer.getIndex(Constants.PREPASS_REFLECTIVITY_TEXTURE_TYPE);
  113. const normalIndex = prePassRenderer.getIndex(Constants.PREPASS_DEPTHNORMAL_TEXTURE_TYPE);
  114. effect.setTexture("normalSampler", prePassRenderer.prePassRT.textures[normalIndex]);
  115. effect.setTexture("positionSampler", prePassRenderer.prePassRT.textures[positionIndex]);
  116. effect.setTexture("reflectivitySampler", prePassRenderer.prePassRT.textures[roughnessIndex]);
  117. }
  118. // Uniforms
  119. const camera = scene.activeCamera;
  120. if (!camera) {
  121. return;
  122. }
  123. const viewMatrix = camera.getViewMatrix();
  124. const projectionMatrix = camera.getProjectionMatrix();
  125. effect.setMatrix("projection", projectionMatrix);
  126. effect.setMatrix("view", viewMatrix);
  127. effect.setFloat("threshold", this.threshold);
  128. effect.setFloat("reflectionSpecularFalloffExponent", this.reflectionSpecularFalloffExponent);
  129. effect.setFloat("strength", this.strength);
  130. effect.setFloat("step", this.step);
  131. effect.setFloat("roughnessFactor", this.roughnessFactor);
  132. };
  133. }
  134. /**
  135. * Gets wether or not smoothing reflections is enabled.
  136. * Enabling smoothing will require more GPU power and can generate a drop in FPS.
  137. */
  138. @serialize()
  139. public get enableSmoothReflections(): boolean {
  140. return this._enableSmoothReflections;
  141. }
  142. /**
  143. * Sets wether or not smoothing reflections is enabled.
  144. * Enabling smoothing will require more GPU power and can generate a drop in FPS.
  145. */
  146. public set enableSmoothReflections(enabled: boolean) {
  147. if (enabled === this._enableSmoothReflections) {
  148. return;
  149. }
  150. this._enableSmoothReflections = enabled;
  151. this._updateEffectDefines();
  152. }
  153. /**
  154. * Gets the number of samples taken while computing reflections. More samples count is high,
  155. * more the post-process wil require GPU power and can generate a drop in FPS. Basically in interval [25, 100].
  156. */
  157. @serialize()
  158. public get reflectionSamples(): number {
  159. return this._reflectionSamples;
  160. }
  161. /**
  162. * Sets the number of samples taken while computing reflections. More samples count is high,
  163. * more the post-process wil require GPU power and can generate a drop in FPS. Basically in interval [25, 100].
  164. */
  165. public set reflectionSamples(samples: number) {
  166. if (samples === this._reflectionSamples) {
  167. return;
  168. }
  169. this._reflectionSamples = samples;
  170. this._updateEffectDefines();
  171. }
  172. /**
  173. * Gets the number of samples taken while smoothing reflections. More samples count is high,
  174. * more the post-process will require GPU power and can generate a drop in FPS.
  175. * Default value (5.0) work pretty well in all cases but can be adjusted.
  176. */
  177. @serialize()
  178. public get smoothSteps(): number {
  179. return this._smoothSteps;
  180. }
  181. /*
  182. * Sets the number of samples taken while smoothing reflections. More samples count is high,
  183. * more the post-process will require GPU power and can generate a drop in FPS.
  184. * Default value (5.0) work pretty well in all cases but can be adjusted.
  185. */
  186. public set smoothSteps(steps: number) {
  187. if (steps === this._smoothSteps) {
  188. return;
  189. }
  190. this._smoothSteps = steps;
  191. this._updateEffectDefines();
  192. }
  193. private _updateEffectDefines(): void {
  194. const defines: string[] = [];
  195. if (this._geometryBufferRenderer || this._prePassRenderer) {
  196. defines.push("#define SSR_SUPPORTED");
  197. if (this._prePassRenderer) {
  198. defines.push("#define PREPASS_LAYOUT");
  199. }
  200. }
  201. if (this._enableSmoothReflections) {
  202. defines.push("#define ENABLE_SMOOTH_REFLECTIONS");
  203. }
  204. defines.push("#define REFLECTION_SAMPLES " + (this._reflectionSamples >> 0));
  205. defines.push("#define SMOOTH_STEPS " + (this._smoothSteps >> 0));
  206. this.updateEffect(defines.join("\n"));
  207. }
  208. /** @hidden */
  209. public static _Parse(parsedPostProcess: any, targetCamera: Camera, scene: Scene, rootUrl: string) {
  210. return SerializationHelper.Parse(() => {
  211. return new ScreenSpaceReflectionPostProcess(
  212. parsedPostProcess.name, scene,
  213. parsedPostProcess.options, targetCamera,
  214. parsedPostProcess.renderTargetSamplingMode,
  215. scene.getEngine(), parsedPostProcess.textureType, parsedPostProcess.reusable);
  216. }, parsedPostProcess, scene, rootUrl);
  217. }
  218. }
  219. _TypeStore.RegisteredTypes["BABYLON.ScreenSpaceReflectionPostProcess"] = ScreenSpaceReflectionPostProcess;