babylon.imageProcessingConfiguration.ts 19 KB

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