babylon.imageProcessingConfiguration.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. module BABYLON {
  2. /**
  3. * Interface to follow in your material defines to integrate easily the
  4. * Image proccessing functions.
  5. */
  6. export interface IImageProcessingConfigurationDefines {
  7. IMAGEPROCESSING: boolean;
  8. VIGNETTE: boolean;
  9. VIGNETTEBLENDMODEMULTIPLY: boolean;
  10. VIGNETTEBLENDMODEOPAQUE: boolean;
  11. TONEMAPPING: boolean;
  12. CONTRAST: boolean;
  13. EXPOSURE: boolean;
  14. COLORCURVES: boolean;
  15. COLORGRADING: boolean;
  16. COLORGRADING3D: boolean;
  17. SAMPLER3DGREENDEPTH: boolean;
  18. SAMPLER3DBGRMAP: boolean;
  19. IMAGEPROCESSINGPOSTPROCESS: boolean;
  20. }
  21. /**
  22. * This groups together the common properties used for image processing either in direct forward pass
  23. * or through post processing effect depending on the use of the image processing pipeline in your scene
  24. * or not.
  25. */
  26. export class ImageProcessingConfiguration {
  27. /**
  28. * Color curves setup used in the effect if colorCurvesEnabled is set to true
  29. */
  30. @serializeAsColorCurves()
  31. public colorCurves: Nullable<ColorCurves> = new ColorCurves();
  32. @serialize()
  33. private _colorCurvesEnabled = false;
  34. /**
  35. * Gets wether the color curves effect is enabled.
  36. */
  37. public get colorCurvesEnabled(): boolean {
  38. return this._colorCurvesEnabled;
  39. }
  40. /**
  41. * Sets wether the color curves effect is enabled.
  42. */
  43. public set colorCurvesEnabled(value: boolean) {
  44. if (this._colorCurvesEnabled === value) {
  45. return;
  46. }
  47. this._colorCurvesEnabled = value;
  48. this._updateParameters();
  49. }
  50. /**
  51. * Color grading LUT texture used in the effect if colorGradingEnabled is set to true
  52. */
  53. @serializeAsTexture()
  54. public colorGradingTexture: Nullable<BaseTexture>;
  55. @serialize()
  56. private _colorGradingEnabled = false;
  57. /**
  58. * Gets wether the color grading effect is enabled.
  59. */
  60. public get colorGradingEnabled(): boolean {
  61. return this._colorGradingEnabled;
  62. }
  63. /**
  64. * Sets wether the color grading effect is enabled.
  65. */
  66. public set colorGradingEnabled(value: boolean) {
  67. if (this._colorGradingEnabled === value) {
  68. return;
  69. }
  70. this._colorGradingEnabled = value;
  71. this._updateParameters();
  72. }
  73. @serialize()
  74. private _colorGradingWithGreenDepth = true;
  75. /**
  76. * Gets wether the color grading effect is using a green depth for the 3d Texture.
  77. */
  78. public get colorGradingWithGreenDepth(): boolean {
  79. return this._colorGradingWithGreenDepth;
  80. }
  81. /**
  82. * Sets wether the color grading effect is using a green depth for the 3d Texture.
  83. */
  84. public set colorGradingWithGreenDepth(value: boolean) {
  85. if (this._colorGradingWithGreenDepth === value) {
  86. return;
  87. }
  88. this._colorGradingWithGreenDepth = value;
  89. this._updateParameters();
  90. }
  91. @serialize()
  92. private _colorGradingBGR = true;
  93. /**
  94. * Gets wether the color grading texture contains BGR values.
  95. */
  96. public get colorGradingBGR(): boolean {
  97. return this._colorGradingBGR;
  98. }
  99. /**
  100. * Sets wether the color grading texture contains BGR values.
  101. */
  102. public set colorGradingBGR(value: boolean) {
  103. if (this._colorGradingBGR === value) {
  104. return;
  105. }
  106. this._colorGradingBGR = value;
  107. this._updateParameters();
  108. }
  109. @serialize()
  110. public _exposure = 1.0;
  111. /**
  112. * Gets the Exposure used in the effect.
  113. */
  114. public get exposure(): number {
  115. return this._exposure;
  116. }
  117. /**
  118. * Sets the Exposure used in the effect.
  119. */
  120. public set exposure(value: number) {
  121. if (this._exposure === value) {
  122. return;
  123. }
  124. this._exposure = value;
  125. this._updateParameters();
  126. }
  127. @serialize()
  128. private _toneMappingEnabled = false;
  129. /**
  130. * Gets wether the tone mapping effect is enabled.
  131. */
  132. public get toneMappingEnabled(): boolean {
  133. return this._toneMappingEnabled;
  134. }
  135. /**
  136. * Sets wether the tone mapping effect is enabled.
  137. */
  138. public set toneMappingEnabled(value: boolean) {
  139. if (this._toneMappingEnabled === value) {
  140. return;
  141. }
  142. this._toneMappingEnabled = value;
  143. this._updateParameters();
  144. }
  145. @serialize()
  146. protected _contrast = 1.0;
  147. /**
  148. * Gets the contrast used in the effect.
  149. */
  150. public get contrast(): number {
  151. return this._contrast;
  152. }
  153. /**
  154. * Sets the contrast used in the effect.
  155. */
  156. public set contrast(value: number) {
  157. if (this._contrast === value) {
  158. return;
  159. }
  160. this._contrast = value;
  161. this._updateParameters();
  162. }
  163. /**
  164. * Vignette stretch size.
  165. */
  166. @serialize()
  167. public vignetteStretch = 0;
  168. /**
  169. * Vignette centre X Offset.
  170. */
  171. @serialize()
  172. public vignetteCentreX = 0;
  173. /**
  174. * Vignette centre Y Offset.
  175. */
  176. @serialize()
  177. public vignetteCentreY = 0;
  178. /**
  179. * Vignette weight or intensity of the vignette effect.
  180. */
  181. @serialize()
  182. public vignetteWeight = 1.5;
  183. /**
  184. * Color of the vignette applied on the screen through the chosen blend mode (vignetteBlendMode)
  185. * if vignetteEnabled is set to true.
  186. */
  187. @serializeAsColor4()
  188. public vignetteColor: BABYLON.Color4 = new BABYLON.Color4(0, 0, 0, 0);
  189. /**
  190. * Camera field of view used by the Vignette effect.
  191. */
  192. @serialize()
  193. public vignetteCameraFov = 0.5;
  194. @serialize()
  195. private _vignetteBlendMode = ImageProcessingConfiguration.VIGNETTEMODE_MULTIPLY;
  196. /**
  197. * Gets the vignette blend mode allowing different kind of effect.
  198. */
  199. public get vignetteBlendMode(): number {
  200. return this._vignetteBlendMode;
  201. }
  202. /**
  203. * Sets the vignette blend mode allowing different kind of effect.
  204. */
  205. public set vignetteBlendMode(value: number) {
  206. if (this._vignetteBlendMode === value) {
  207. return;
  208. }
  209. this._vignetteBlendMode = value;
  210. this._updateParameters();
  211. }
  212. @serialize()
  213. private _vignetteEnabled = false;
  214. /**
  215. * Gets wether the vignette effect is enabled.
  216. */
  217. public get vignetteEnabled(): boolean {
  218. return this._vignetteEnabled;
  219. }
  220. /**
  221. * Sets wether the vignette effect is enabled.
  222. */
  223. public set vignetteEnabled(value: boolean) {
  224. if (this._vignetteEnabled === value) {
  225. return;
  226. }
  227. this._vignetteEnabled = value;
  228. this._updateParameters();
  229. }
  230. @serialize()
  231. private _applyByPostProcess = false;
  232. /**
  233. * Gets wether the image processing is applied through a post process or not.
  234. */
  235. public get applyByPostProcess(): boolean {
  236. return this._applyByPostProcess;
  237. }
  238. /**
  239. * Sets wether the image processing is applied through a post process or not.
  240. */
  241. public set applyByPostProcess(value: boolean) {
  242. if (this._applyByPostProcess === value) {
  243. return;
  244. }
  245. this._applyByPostProcess = value;
  246. this._updateParameters();
  247. }
  248. @serialize()
  249. private _isEnabled = true;
  250. /**
  251. * Gets wether the image processing is enabled or not.
  252. */
  253. public get isEnabled(): boolean {
  254. return this._isEnabled;
  255. }
  256. /**
  257. * Sets wether the image processing is enabled or not.
  258. */
  259. public set isEnabled(value: boolean) {
  260. if (this._isEnabled === value) {
  261. return;
  262. }
  263. this._isEnabled = value;
  264. this._updateParameters();
  265. }
  266. /**
  267. * An event triggered when the configuration changes and requires Shader to Update some parameters.
  268. * @type {BABYLON.Observable}
  269. */
  270. public onUpdateParameters = new Observable<ImageProcessingConfiguration>();
  271. /**
  272. * Method called each time the image processing information changes requires to recompile the effect.
  273. */
  274. protected _updateParameters(): void {
  275. this.onUpdateParameters.notifyObservers(this);
  276. }
  277. public getClassName(): string {
  278. return "ImageProcessingConfiguration";
  279. }
  280. /**
  281. * Prepare the list of uniforms associated with the Image Processing effects.
  282. * @param uniformsList The list of uniforms used in the effect
  283. * @param defines the list of defines currently in use
  284. */
  285. public static PrepareUniforms(uniforms: string[], defines: IImageProcessingConfigurationDefines): void {
  286. if (defines.EXPOSURE) {
  287. uniforms.push("exposureLinear");
  288. }
  289. if (defines.CONTRAST) {
  290. uniforms.push("contrast");
  291. }
  292. if (defines.COLORGRADING) {
  293. uniforms.push("colorTransformSettings");
  294. }
  295. if (defines.VIGNETTE) {
  296. uniforms.push("vInverseScreenSize");
  297. uniforms.push("vignetteSettings1");
  298. uniforms.push("vignetteSettings2");
  299. }
  300. if (defines.COLORCURVES) {
  301. ColorCurves.PrepareUniforms(uniforms);
  302. }
  303. }
  304. /**
  305. * Prepare the list of samplers associated with the Image Processing effects.
  306. * @param uniformsList The list of uniforms used in the effect
  307. * @param defines the list of defines currently in use
  308. */
  309. public static PrepareSamplers(samplersList: string[], defines: IImageProcessingConfigurationDefines): void {
  310. if (defines.COLORGRADING) {
  311. samplersList.push("txColorTransform");
  312. }
  313. }
  314. /**
  315. * Prepare the list of defines associated to the shader.
  316. * @param defines the list of defines to complete
  317. */
  318. public prepareDefines(defines: IImageProcessingConfigurationDefines, forPostProcess: boolean = false): void {
  319. if (forPostProcess !== this.applyByPostProcess || !this._isEnabled) {
  320. defines.VIGNETTE = false;
  321. defines.TONEMAPPING = false;
  322. defines.CONTRAST = false;
  323. defines.EXPOSURE = false;
  324. defines.COLORCURVES = false;
  325. defines.COLORGRADING = false;
  326. defines.COLORGRADING3D = false;
  327. defines.IMAGEPROCESSING = false;
  328. defines.IMAGEPROCESSINGPOSTPROCESS = this.applyByPostProcess && this._isEnabled;
  329. return;
  330. }
  331. defines.VIGNETTE = this.vignetteEnabled;
  332. defines.VIGNETTEBLENDMODEMULTIPLY = (this.vignetteBlendMode === ImageProcessingConfiguration._VIGNETTEMODE_MULTIPLY);
  333. defines.VIGNETTEBLENDMODEOPAQUE = !defines.VIGNETTEBLENDMODEMULTIPLY;
  334. defines.TONEMAPPING = this.toneMappingEnabled;
  335. defines.CONTRAST = (this.contrast !== 1.0);
  336. defines.EXPOSURE = (this.exposure !== 1.0);
  337. defines.COLORCURVES = (this.colorCurvesEnabled && !!this.colorCurves);
  338. defines.COLORGRADING = (this.colorGradingEnabled && !!this.colorGradingTexture);
  339. if (defines.COLORGRADING) {
  340. defines.COLORGRADING3D = this.colorGradingTexture!.is3D;
  341. } else {
  342. defines.COLORGRADING3D = false;
  343. }
  344. defines.SAMPLER3DGREENDEPTH = this.colorGradingWithGreenDepth;
  345. defines.SAMPLER3DBGRMAP = this.colorGradingBGR;
  346. defines.IMAGEPROCESSINGPOSTPROCESS = this.applyByPostProcess;
  347. defines.IMAGEPROCESSING = defines.VIGNETTE || defines.TONEMAPPING || defines.CONTRAST || defines.EXPOSURE || defines.COLORCURVES || defines.COLORGRADING;
  348. }
  349. /**
  350. * Returns true if all the image processing information are ready.
  351. */
  352. public isReady() {
  353. // Color Grading texure can not be none blocking.
  354. return !this.colorGradingEnabled || !this.colorGradingTexture || this.colorGradingTexture.isReady();
  355. }
  356. /**
  357. * Binds the image processing to the shader.
  358. * @param effect The effect to bind to
  359. */
  360. public bind(effect: Effect, aspectRatio = 1) : void {
  361. // Color Curves
  362. if (this._colorCurvesEnabled && this.colorCurves) {
  363. ColorCurves.Bind(this.colorCurves, effect);
  364. }
  365. // Vignette
  366. if (this._vignetteEnabled) {
  367. var inverseWidth = 1 / effect.getEngine().getRenderWidth();
  368. var inverseHeight = 1 / effect.getEngine().getRenderHeight();
  369. effect.setFloat2("vInverseScreenSize", inverseWidth, inverseHeight);
  370. let vignetteScaleY = Math.tan(this.vignetteCameraFov * 0.5);
  371. let vignetteScaleX = vignetteScaleY * aspectRatio;
  372. let vignetteScaleGeometricMean = Math.sqrt(vignetteScaleX * vignetteScaleY);
  373. vignetteScaleX = Tools.Mix(vignetteScaleX, vignetteScaleGeometricMean, this.vignetteStretch);
  374. vignetteScaleY = Tools.Mix(vignetteScaleY, vignetteScaleGeometricMean, this.vignetteStretch);
  375. effect.setFloat4("vignetteSettings1", vignetteScaleX, vignetteScaleY, -vignetteScaleX * this.vignetteCentreX, -vignetteScaleY * this.vignetteCentreY);
  376. let vignettePower = -2.0 * this.vignetteWeight;
  377. effect.setFloat4("vignetteSettings2", this.vignetteColor.r, this.vignetteColor.g, this.vignetteColor.b, vignettePower);
  378. }
  379. // Exposure
  380. effect.setFloat("exposureLinear", this.exposure);
  381. // Contrast
  382. effect.setFloat("contrast", this.contrast);
  383. // Color transform settings
  384. if (this.colorGradingTexture) {
  385. effect.setTexture("txColorTransform", this.colorGradingTexture);
  386. let textureSize = this.colorGradingTexture.getSize().height;
  387. effect.setFloat4("colorTransformSettings",
  388. (textureSize - 1) / textureSize, // textureScale
  389. 0.5 / textureSize, // textureOffset
  390. textureSize, // textureSize
  391. this.colorGradingTexture.level // weight
  392. );
  393. }
  394. }
  395. /**
  396. * Clones the current image processing instance.
  397. * @return The cloned image processing
  398. */
  399. public clone(): ImageProcessingConfiguration {
  400. return SerializationHelper.Clone(() => new ImageProcessingConfiguration(), this);
  401. }
  402. /**
  403. * Serializes the current image processing instance to a json representation.
  404. * @return a JSON representation
  405. */
  406. public serialize(): any {
  407. return SerializationHelper.Serialize(this);
  408. }
  409. /**
  410. * Parses the image processing from a json representation.
  411. * @param source the JSON source to parse
  412. * @return The parsed image processing
  413. */
  414. public static Parse(source: any) : ImageProcessingConfiguration {
  415. return SerializationHelper.Parse(() => new ImageProcessingConfiguration(), source, null, null);
  416. }
  417. // Static constants associated to the image processing.
  418. private static _VIGNETTEMODE_MULTIPLY = 0;
  419. private static _VIGNETTEMODE_OPAQUE = 1;
  420. /**
  421. * Used to apply the vignette as a mix with the pixel color.
  422. */
  423. public static get VIGNETTEMODE_MULTIPLY(): number {
  424. return this._VIGNETTEMODE_MULTIPLY;
  425. }
  426. /**
  427. * Used to apply the vignette as a replacement of the pixel color.
  428. */
  429. public static get VIGNETTEMODE_OPAQUE(): number {
  430. return this._VIGNETTEMODE_OPAQUE;
  431. }
  432. }
  433. }