imageProcessingConfiguration.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. import { __decorate } from "../tslib.es6.js";
  2. /* eslint-disable @typescript-eslint/naming-convention */
  3. import { serialize, serializeAsTexture, serializeAsColorCurves, serializeAsColor4 } from "../Misc/decorators.js";
  4. import { Observable } from "../Misc/observable.js";
  5. import { Color4 } from "../Maths/math.color.js";
  6. import { ColorCurves } from "../Materials/colorCurves.js";
  7. import { Mix } from "../Misc/tools.functions.js";
  8. import { SerializationHelper } from "../Misc/decorators.serialization.js";
  9. import { PrepareSamplersForImageProcessing, PrepareUniformsForImageProcessing } from "./imageProcessingConfiguration.functions.js";
  10. /**
  11. * This groups together the common properties used for image processing either in direct forward pass
  12. * or through post processing effect depending on the use of the image processing pipeline in your scene
  13. * or not.
  14. */
  15. export class ImageProcessingConfiguration {
  16. constructor() {
  17. /**
  18. * Color curves setup used in the effect if colorCurvesEnabled is set to true
  19. */
  20. this.colorCurves = new ColorCurves();
  21. this._colorCurvesEnabled = false;
  22. this._colorGradingEnabled = false;
  23. this._colorGradingWithGreenDepth = true;
  24. this._colorGradingBGR = true;
  25. /** @internal */
  26. this._exposure = 1.0;
  27. this._toneMappingEnabled = false;
  28. this._toneMappingType = ImageProcessingConfiguration.TONEMAPPING_STANDARD;
  29. this._contrast = 1.0;
  30. /**
  31. * Vignette stretch size.
  32. */
  33. this.vignetteStretch = 0;
  34. /**
  35. * Vignette center X Offset.
  36. */
  37. this.vignetteCenterX = 0;
  38. /**
  39. * Vignette center Y Offset.
  40. */
  41. this.vignetteCenterY = 0;
  42. /**
  43. * Vignette weight or intensity of the vignette effect.
  44. */
  45. this.vignetteWeight = 1.5;
  46. /**
  47. * Color of the vignette applied on the screen through the chosen blend mode (vignetteBlendMode)
  48. * if vignetteEnabled is set to true.
  49. */
  50. this.vignetteColor = new Color4(0, 0, 0, 0);
  51. /**
  52. * Camera field of view used by the Vignette effect.
  53. */
  54. this.vignetteCameraFov = 0.5;
  55. this._vignetteBlendMode = ImageProcessingConfiguration.VIGNETTEMODE_MULTIPLY;
  56. this._vignetteEnabled = false;
  57. this._ditheringEnabled = false;
  58. this._ditheringIntensity = 1.0 / 255.0;
  59. /** @internal */
  60. this._skipFinalColorClamp = false;
  61. /** @internal */
  62. this._applyByPostProcess = false;
  63. this._isEnabled = true;
  64. /**
  65. * An event triggered when the configuration changes and requires Shader to Update some parameters.
  66. */
  67. this.onUpdateParameters = new Observable();
  68. }
  69. /**
  70. * Gets whether the color curves effect is enabled.
  71. */
  72. get colorCurvesEnabled() {
  73. return this._colorCurvesEnabled;
  74. }
  75. /**
  76. * Sets whether the color curves effect is enabled.
  77. */
  78. set colorCurvesEnabled(value) {
  79. if (this._colorCurvesEnabled === value) {
  80. return;
  81. }
  82. this._colorCurvesEnabled = value;
  83. this._updateParameters();
  84. }
  85. /**
  86. * Color grading LUT texture used in the effect if colorGradingEnabled is set to true
  87. */
  88. get colorGradingTexture() {
  89. return this._colorGradingTexture;
  90. }
  91. /**
  92. * Color grading LUT texture used in the effect if colorGradingEnabled is set to true
  93. */
  94. set colorGradingTexture(value) {
  95. if (this._colorGradingTexture === value) {
  96. return;
  97. }
  98. this._colorGradingTexture = value;
  99. this._updateParameters();
  100. }
  101. /**
  102. * Gets whether the color grading effect is enabled.
  103. */
  104. get colorGradingEnabled() {
  105. return this._colorGradingEnabled;
  106. }
  107. /**
  108. * Sets whether the color grading effect is enabled.
  109. */
  110. set colorGradingEnabled(value) {
  111. if (this._colorGradingEnabled === value) {
  112. return;
  113. }
  114. this._colorGradingEnabled = value;
  115. this._updateParameters();
  116. }
  117. /**
  118. * Gets whether the color grading effect is using a green depth for the 3d Texture.
  119. */
  120. get colorGradingWithGreenDepth() {
  121. return this._colorGradingWithGreenDepth;
  122. }
  123. /**
  124. * Sets whether the color grading effect is using a green depth for the 3d Texture.
  125. */
  126. set colorGradingWithGreenDepth(value) {
  127. if (this._colorGradingWithGreenDepth === value) {
  128. return;
  129. }
  130. this._colorGradingWithGreenDepth = value;
  131. this._updateParameters();
  132. }
  133. /**
  134. * Gets whether the color grading texture contains BGR values.
  135. */
  136. get colorGradingBGR() {
  137. return this._colorGradingBGR;
  138. }
  139. /**
  140. * Sets whether the color grading texture contains BGR values.
  141. */
  142. set colorGradingBGR(value) {
  143. if (this._colorGradingBGR === value) {
  144. return;
  145. }
  146. this._colorGradingBGR = value;
  147. this._updateParameters();
  148. }
  149. /**
  150. * Gets the Exposure used in the effect.
  151. */
  152. get exposure() {
  153. return this._exposure;
  154. }
  155. /**
  156. * Sets the Exposure used in the effect.
  157. */
  158. set exposure(value) {
  159. if (this._exposure === value) {
  160. return;
  161. }
  162. this._exposure = value;
  163. this._updateParameters();
  164. }
  165. /**
  166. * Gets whether the tone mapping effect is enabled.
  167. */
  168. get toneMappingEnabled() {
  169. return this._toneMappingEnabled;
  170. }
  171. /**
  172. * Sets whether the tone mapping effect is enabled.
  173. */
  174. set toneMappingEnabled(value) {
  175. if (this._toneMappingEnabled === value) {
  176. return;
  177. }
  178. this._toneMappingEnabled = value;
  179. this._updateParameters();
  180. }
  181. /**
  182. * Gets the type of tone mapping effect.
  183. */
  184. get toneMappingType() {
  185. return this._toneMappingType;
  186. }
  187. /**
  188. * Sets the type of tone mapping effect used in BabylonJS.
  189. */
  190. set toneMappingType(value) {
  191. if (this._toneMappingType === value) {
  192. return;
  193. }
  194. this._toneMappingType = value;
  195. this._updateParameters();
  196. }
  197. /**
  198. * Gets the contrast used in the effect.
  199. */
  200. get contrast() {
  201. return this._contrast;
  202. }
  203. /**
  204. * Sets the contrast used in the effect.
  205. */
  206. set contrast(value) {
  207. if (this._contrast === value) {
  208. return;
  209. }
  210. this._contrast = value;
  211. this._updateParameters();
  212. }
  213. /**
  214. * Back Compat: Vignette center Y Offset.
  215. * @deprecated use vignetteCenterY instead
  216. */
  217. get vignetteCentreY() {
  218. return this.vignetteCenterY;
  219. }
  220. set vignetteCentreY(value) {
  221. this.vignetteCenterY = value;
  222. }
  223. /**
  224. * Back Compat: Vignette center X Offset.
  225. * @deprecated use vignetteCenterX instead
  226. */
  227. get vignetteCentreX() {
  228. return this.vignetteCenterX;
  229. }
  230. set vignetteCentreX(value) {
  231. this.vignetteCenterX = value;
  232. }
  233. /**
  234. * Gets the vignette blend mode allowing different kind of effect.
  235. */
  236. get vignetteBlendMode() {
  237. return this._vignetteBlendMode;
  238. }
  239. /**
  240. * Sets the vignette blend mode allowing different kind of effect.
  241. */
  242. set vignetteBlendMode(value) {
  243. if (this._vignetteBlendMode === value) {
  244. return;
  245. }
  246. this._vignetteBlendMode = value;
  247. this._updateParameters();
  248. }
  249. /**
  250. * Gets whether the vignette effect is enabled.
  251. */
  252. get vignetteEnabled() {
  253. return this._vignetteEnabled;
  254. }
  255. /**
  256. * Sets whether the vignette effect is enabled.
  257. */
  258. set vignetteEnabled(value) {
  259. if (this._vignetteEnabled === value) {
  260. return;
  261. }
  262. this._vignetteEnabled = value;
  263. this._updateParameters();
  264. }
  265. /**
  266. * Gets whether the dithering effect is enabled.
  267. * The dithering effect can be used to reduce banding.
  268. */
  269. get ditheringEnabled() {
  270. return this._ditheringEnabled;
  271. }
  272. /**
  273. * Sets whether the dithering effect is enabled.
  274. * The dithering effect can be used to reduce banding.
  275. */
  276. set ditheringEnabled(value) {
  277. if (this._ditheringEnabled === value) {
  278. return;
  279. }
  280. this._ditheringEnabled = value;
  281. this._updateParameters();
  282. }
  283. /**
  284. * Gets the dithering intensity. 0 is no dithering. Default is 1.0 / 255.0.
  285. */
  286. get ditheringIntensity() {
  287. return this._ditheringIntensity;
  288. }
  289. /**
  290. * Sets the dithering intensity. 0 is no dithering. Default is 1.0 / 255.0.
  291. */
  292. set ditheringIntensity(value) {
  293. if (this._ditheringIntensity === value) {
  294. return;
  295. }
  296. this._ditheringIntensity = value;
  297. this._updateParameters();
  298. }
  299. /**
  300. * If apply by post process is set to true, setting this to true will skip the final color clamp step in the fragment shader
  301. * Applies to PBR materials.
  302. */
  303. get skipFinalColorClamp() {
  304. return this._skipFinalColorClamp;
  305. }
  306. /**
  307. * If apply by post process is set to true, setting this to true will skip the final color clamp step in the fragment shader
  308. * Applies to PBR materials.
  309. */
  310. set skipFinalColorClamp(value) {
  311. if (this._skipFinalColorClamp === value) {
  312. return;
  313. }
  314. this._skipFinalColorClamp = value;
  315. this._updateParameters();
  316. }
  317. /**
  318. * Gets whether the image processing is applied through a post process or not.
  319. */
  320. get applyByPostProcess() {
  321. return this._applyByPostProcess;
  322. }
  323. /**
  324. * Sets whether the image processing is applied through a post process or not.
  325. */
  326. set applyByPostProcess(value) {
  327. if (this._applyByPostProcess === value) {
  328. return;
  329. }
  330. this._applyByPostProcess = value;
  331. this._updateParameters();
  332. }
  333. /**
  334. * Gets whether the image processing is enabled or not.
  335. */
  336. get isEnabled() {
  337. return this._isEnabled;
  338. }
  339. /**
  340. * Sets whether the image processing is enabled or not.
  341. */
  342. set isEnabled(value) {
  343. if (this._isEnabled === value) {
  344. return;
  345. }
  346. this._isEnabled = value;
  347. this._updateParameters();
  348. }
  349. /**
  350. * Method called each time the image processing information changes requires to recompile the effect.
  351. */
  352. _updateParameters() {
  353. this.onUpdateParameters.notifyObservers(this);
  354. }
  355. /**
  356. * Gets the current class name.
  357. * @returns "ImageProcessingConfiguration"
  358. */
  359. getClassName() {
  360. return "ImageProcessingConfiguration";
  361. }
  362. /**
  363. * Prepare the list of defines associated to the shader.
  364. * @param defines the list of defines to complete
  365. * @param forPostProcess Define if we are currently in post process mode or not
  366. */
  367. prepareDefines(defines, forPostProcess = false) {
  368. if (forPostProcess !== this.applyByPostProcess || !this._isEnabled) {
  369. defines.VIGNETTE = false;
  370. defines.TONEMAPPING = false;
  371. defines.TONEMAPPING_ACES = false;
  372. defines.CONTRAST = false;
  373. defines.EXPOSURE = false;
  374. defines.COLORCURVES = false;
  375. defines.COLORGRADING = false;
  376. defines.COLORGRADING3D = false;
  377. defines.DITHER = false;
  378. defines.IMAGEPROCESSING = false;
  379. defines.SKIPFINALCOLORCLAMP = this.skipFinalColorClamp;
  380. defines.IMAGEPROCESSINGPOSTPROCESS = this.applyByPostProcess && this._isEnabled;
  381. return;
  382. }
  383. defines.VIGNETTE = this.vignetteEnabled;
  384. defines.VIGNETTEBLENDMODEMULTIPLY = this.vignetteBlendMode === ImageProcessingConfiguration._VIGNETTEMODE_MULTIPLY;
  385. defines.VIGNETTEBLENDMODEOPAQUE = !defines.VIGNETTEBLENDMODEMULTIPLY;
  386. defines.TONEMAPPING = this.toneMappingEnabled;
  387. switch (this._toneMappingType) {
  388. case ImageProcessingConfiguration.TONEMAPPING_ACES:
  389. defines.TONEMAPPING_ACES = true;
  390. break;
  391. default:
  392. defines.TONEMAPPING_ACES = false;
  393. break;
  394. }
  395. defines.CONTRAST = this.contrast !== 1.0;
  396. defines.EXPOSURE = this.exposure !== 1.0;
  397. defines.COLORCURVES = this.colorCurvesEnabled && !!this.colorCurves;
  398. defines.COLORGRADING = this.colorGradingEnabled && !!this.colorGradingTexture;
  399. if (defines.COLORGRADING) {
  400. defines.COLORGRADING3D = this.colorGradingTexture.is3D;
  401. }
  402. else {
  403. defines.COLORGRADING3D = false;
  404. }
  405. defines.SAMPLER3DGREENDEPTH = this.colorGradingWithGreenDepth;
  406. defines.SAMPLER3DBGRMAP = this.colorGradingBGR;
  407. defines.DITHER = this._ditheringEnabled;
  408. defines.IMAGEPROCESSINGPOSTPROCESS = this.applyByPostProcess;
  409. defines.SKIPFINALCOLORCLAMP = this.skipFinalColorClamp;
  410. defines.IMAGEPROCESSING = defines.VIGNETTE || defines.TONEMAPPING || defines.CONTRAST || defines.EXPOSURE || defines.COLORCURVES || defines.COLORGRADING || defines.DITHER;
  411. }
  412. /**
  413. * Returns true if all the image processing information are ready.
  414. * @returns True if ready, otherwise, false
  415. */
  416. isReady() {
  417. // Color Grading texture 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 overrideAspectRatio Override the aspect ratio of the effect
  424. */
  425. bind(effect, overrideAspectRatio) {
  426. // Color Curves
  427. if (this._colorCurvesEnabled && this.colorCurves) {
  428. ColorCurves.Bind(this.colorCurves, effect);
  429. }
  430. // Vignette and dither handled together due to common uniform.
  431. if (this._vignetteEnabled || this._ditheringEnabled) {
  432. const inverseWidth = 1 / effect.getEngine().getRenderWidth();
  433. const inverseHeight = 1 / effect.getEngine().getRenderHeight();
  434. effect.setFloat2("vInverseScreenSize", inverseWidth, inverseHeight);
  435. if (this._ditheringEnabled) {
  436. effect.setFloat("ditherIntensity", 0.5 * this._ditheringIntensity);
  437. }
  438. if (this._vignetteEnabled) {
  439. const aspectRatio = overrideAspectRatio != null ? overrideAspectRatio : inverseHeight / inverseWidth;
  440. let vignetteScaleY = Math.tan(this.vignetteCameraFov * 0.5);
  441. let vignetteScaleX = vignetteScaleY * aspectRatio;
  442. const vignetteScaleGeometricMean = Math.sqrt(vignetteScaleX * vignetteScaleY);
  443. vignetteScaleX = Mix(vignetteScaleX, vignetteScaleGeometricMean, this.vignetteStretch);
  444. vignetteScaleY = Mix(vignetteScaleY, vignetteScaleGeometricMean, this.vignetteStretch);
  445. effect.setFloat4("vignetteSettings1", vignetteScaleX, vignetteScaleY, -vignetteScaleX * this.vignetteCenterX, -vignetteScaleY * this.vignetteCenterY);
  446. const vignettePower = -2.0 * this.vignetteWeight;
  447. effect.setFloat4("vignetteSettings2", this.vignetteColor.r, this.vignetteColor.g, this.vignetteColor.b, vignettePower);
  448. }
  449. }
  450. // Exposure
  451. effect.setFloat("exposureLinear", this.exposure);
  452. // Contrast
  453. effect.setFloat("contrast", this.contrast);
  454. // Color transform settings
  455. if (this.colorGradingTexture) {
  456. effect.setTexture("txColorTransform", this.colorGradingTexture);
  457. const textureSize = this.colorGradingTexture.getSize().height;
  458. effect.setFloat4("colorTransformSettings", (textureSize - 1) / textureSize, // textureScale
  459. 0.5 / textureSize, // textureOffset
  460. textureSize, // textureSize
  461. this.colorGradingTexture.level // weight
  462. );
  463. }
  464. }
  465. /**
  466. * Clones the current image processing instance.
  467. * @returns The cloned image processing
  468. */
  469. clone() {
  470. return SerializationHelper.Clone(() => new ImageProcessingConfiguration(), this);
  471. }
  472. /**
  473. * Serializes the current image processing instance to a json representation.
  474. * @returns a JSON representation
  475. */
  476. serialize() {
  477. return SerializationHelper.Serialize(this);
  478. }
  479. /**
  480. * Parses the image processing from a json representation.
  481. * @param source the JSON source to parse
  482. * @returns The parsed image processing
  483. */
  484. static Parse(source) {
  485. const parsed = SerializationHelper.Parse(() => new ImageProcessingConfiguration(), source, null, null);
  486. // Backward compatibility
  487. if (source.vignetteCentreX !== undefined) {
  488. parsed.vignetteCenterX = source.vignetteCentreX;
  489. }
  490. if (source.vignetteCentreY !== undefined) {
  491. parsed.vignetteCenterY = source.vignetteCentreY;
  492. }
  493. return parsed;
  494. }
  495. /**
  496. * Used to apply the vignette as a mix with the pixel color.
  497. */
  498. static get VIGNETTEMODE_MULTIPLY() {
  499. return this._VIGNETTEMODE_MULTIPLY;
  500. }
  501. /**
  502. * Used to apply the vignette as a replacement of the pixel color.
  503. */
  504. static get VIGNETTEMODE_OPAQUE() {
  505. return this._VIGNETTEMODE_OPAQUE;
  506. }
  507. }
  508. /**
  509. * Default tone mapping applied in BabylonJS.
  510. */
  511. ImageProcessingConfiguration.TONEMAPPING_STANDARD = 0;
  512. /**
  513. * ACES Tone mapping (used by default in unreal and unity). This can help getting closer
  514. * to other engines rendering to increase portability.
  515. */
  516. ImageProcessingConfiguration.TONEMAPPING_ACES = 1;
  517. /**
  518. * Prepare the list of uniforms associated with the Image Processing effects.
  519. * @param uniforms The list of uniforms used in the effect
  520. * @param defines the list of defines currently in use
  521. */
  522. ImageProcessingConfiguration.PrepareUniforms = PrepareUniformsForImageProcessing;
  523. /**
  524. * Prepare the list of samplers associated with the Image Processing effects.
  525. * @param samplersList The list of uniforms used in the effect
  526. * @param defines the list of defines currently in use
  527. */
  528. ImageProcessingConfiguration.PrepareSamplers = PrepareSamplersForImageProcessing;
  529. // Static constants associated to the image processing.
  530. ImageProcessingConfiguration._VIGNETTEMODE_MULTIPLY = 0;
  531. ImageProcessingConfiguration._VIGNETTEMODE_OPAQUE = 1;
  532. __decorate([
  533. serializeAsColorCurves()
  534. ], ImageProcessingConfiguration.prototype, "colorCurves", void 0);
  535. __decorate([
  536. serialize()
  537. ], ImageProcessingConfiguration.prototype, "_colorCurvesEnabled", void 0);
  538. __decorate([
  539. serializeAsTexture("colorGradingTexture")
  540. ], ImageProcessingConfiguration.prototype, "_colorGradingTexture", void 0);
  541. __decorate([
  542. serialize()
  543. ], ImageProcessingConfiguration.prototype, "_colorGradingEnabled", void 0);
  544. __decorate([
  545. serialize()
  546. ], ImageProcessingConfiguration.prototype, "_colorGradingWithGreenDepth", void 0);
  547. __decorate([
  548. serialize()
  549. ], ImageProcessingConfiguration.prototype, "_colorGradingBGR", void 0);
  550. __decorate([
  551. serialize()
  552. ], ImageProcessingConfiguration.prototype, "_exposure", void 0);
  553. __decorate([
  554. serialize()
  555. ], ImageProcessingConfiguration.prototype, "_toneMappingEnabled", void 0);
  556. __decorate([
  557. serialize()
  558. ], ImageProcessingConfiguration.prototype, "_toneMappingType", void 0);
  559. __decorate([
  560. serialize()
  561. ], ImageProcessingConfiguration.prototype, "_contrast", void 0);
  562. __decorate([
  563. serialize()
  564. ], ImageProcessingConfiguration.prototype, "vignetteStretch", void 0);
  565. __decorate([
  566. serialize()
  567. ], ImageProcessingConfiguration.prototype, "vignetteCenterX", void 0);
  568. __decorate([
  569. serialize()
  570. ], ImageProcessingConfiguration.prototype, "vignetteCenterY", void 0);
  571. __decorate([
  572. serialize()
  573. ], ImageProcessingConfiguration.prototype, "vignetteWeight", void 0);
  574. __decorate([
  575. serializeAsColor4()
  576. ], ImageProcessingConfiguration.prototype, "vignetteColor", void 0);
  577. __decorate([
  578. serialize()
  579. ], ImageProcessingConfiguration.prototype, "vignetteCameraFov", void 0);
  580. __decorate([
  581. serialize()
  582. ], ImageProcessingConfiguration.prototype, "_vignetteBlendMode", void 0);
  583. __decorate([
  584. serialize()
  585. ], ImageProcessingConfiguration.prototype, "_vignetteEnabled", void 0);
  586. __decorate([
  587. serialize()
  588. ], ImageProcessingConfiguration.prototype, "_ditheringEnabled", void 0);
  589. __decorate([
  590. serialize()
  591. ], ImageProcessingConfiguration.prototype, "_ditheringIntensity", void 0);
  592. __decorate([
  593. serialize()
  594. ], ImageProcessingConfiguration.prototype, "_skipFinalColorClamp", void 0);
  595. __decorate([
  596. serialize()
  597. ], ImageProcessingConfiguration.prototype, "_applyByPostProcess", void 0);
  598. __decorate([
  599. serialize()
  600. ], ImageProcessingConfiguration.prototype, "_isEnabled", void 0);
  601. // References the dependencies.
  602. SerializationHelper._ImageProcessingConfigurationParser = ImageProcessingConfiguration.Parse;
  603. //# sourceMappingURL=imageProcessingConfiguration.js.map