babylon.imageProcessingConfiguration.ts 19 KB

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