pbrSheenConfiguration.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. import { SerializationHelper, serialize, expandToProperty, serializeAsColor3, serializeAsTexture } from "../../Misc/decorators";
  2. import { UniformBuffer } from "../../Materials/uniformBuffer";
  3. import { Color3 } from '../../Maths/math.color';
  4. import { Scene } from "../../scene";
  5. import { MaterialFlags } from "../../Materials/materialFlags";
  6. import { MaterialHelper } from "../../Materials/materialHelper";
  7. import { BaseTexture } from "../../Materials/Textures/baseTexture";
  8. import { Nullable } from "../../types";
  9. import { IAnimatable } from '../../Animations/animatable.interface';
  10. import { EffectFallbacks } from '../effectFallbacks';
  11. /**
  12. * @hidden
  13. */
  14. export interface IMaterialSheenDefines {
  15. SHEEN: boolean;
  16. SHEEN_TEXTURE: boolean;
  17. SHEEN_TEXTURE_ROUGHNESS: boolean;
  18. SHEEN_TEXTUREDIRECTUV: number;
  19. SHEEN_LINKWITHALBEDO: boolean;
  20. SHEEN_ROUGHNESS: boolean;
  21. SHEEN_ALBEDOSCALING: boolean;
  22. SHEEN_USE_ROUGHNESS_FROM_TEXTURE: boolean;
  23. SHEEN_TEXTURE_ROUGHNESS_IDENTICAL: boolean;
  24. /** @hidden */
  25. _areTexturesDirty: boolean;
  26. }
  27. /**
  28. * Define the code related to the Sheen parameters of the pbr material.
  29. */
  30. export class PBRSheenConfiguration {
  31. private _isEnabled = false;
  32. /**
  33. * Defines if the material uses sheen.
  34. */
  35. @serialize()
  36. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  37. public isEnabled = false;
  38. private _linkSheenWithAlbedo = false;
  39. /**
  40. * Defines if the sheen is linked to the sheen color.
  41. */
  42. @serialize()
  43. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  44. public linkSheenWithAlbedo = false;
  45. /**
  46. * Defines the sheen intensity.
  47. */
  48. @serialize()
  49. public intensity = 1;
  50. /**
  51. * Defines the sheen color.
  52. */
  53. @serializeAsColor3()
  54. public color = Color3.White();
  55. private _texture: Nullable<BaseTexture> = null;
  56. /**
  57. * Stores the sheen tint values in a texture.
  58. * rgb is tint
  59. * a is a intensity or roughness if the roughness property has been defined and useRoughnessFromTexture is true (in that case, textureRoughness won't be used)
  60. * If the roughness property has been defined and useRoughnessFromTexture is false then the alpha channel is not used to modulate roughness
  61. */
  62. @serializeAsTexture()
  63. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  64. public texture: Nullable<BaseTexture> = null;
  65. private _useRoughnessFromMainTexture = true;
  66. /**
  67. * Indicates that the alpha channel of the texture property will be used for roughness.
  68. * Has no effect if the roughness (and texture!) property is not defined
  69. */
  70. @serialize()
  71. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  72. public useRoughnessFromMainTexture = true;
  73. private _roughness: Nullable<number> = null;
  74. /**
  75. * Defines the sheen roughness.
  76. * It is not taken into account if linkSheenWithAlbedo is true.
  77. * To stay backward compatible, material roughness is used instead if sheen roughness = null
  78. */
  79. @serialize()
  80. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  81. public roughness: Nullable<number> = null;
  82. private _textureRoughness: Nullable<BaseTexture> = null;
  83. /**
  84. * Stores the sheen roughness in a texture.
  85. * alpha channel is the roughness. This texture won't be used if the texture property is not empty and useRoughnessFromTexture is true
  86. */
  87. @serializeAsTexture()
  88. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  89. public textureRoughness: Nullable<BaseTexture> = null;
  90. private _albedoScaling = false;
  91. /**
  92. * If true, the sheen effect is layered above the base BRDF with the albedo-scaling technique.
  93. * It allows the strength of the sheen effect to not depend on the base color of the material,
  94. * making it easier to setup and tweak the effect
  95. */
  96. @serialize()
  97. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  98. public albedoScaling = false;
  99. /** @hidden */
  100. private _internalMarkAllSubMeshesAsTexturesDirty: () => void;
  101. /** @hidden */
  102. public _markAllSubMeshesAsTexturesDirty(): void {
  103. this._internalMarkAllSubMeshesAsTexturesDirty();
  104. }
  105. /**
  106. * Instantiate a new istance of clear coat configuration.
  107. * @param markAllSubMeshesAsTexturesDirty Callback to flag the material to dirty
  108. */
  109. constructor(markAllSubMeshesAsTexturesDirty: () => void) {
  110. this._internalMarkAllSubMeshesAsTexturesDirty = markAllSubMeshesAsTexturesDirty;
  111. }
  112. /**
  113. * Specifies that the submesh is ready to be used.
  114. * @param defines the list of "defines" to update.
  115. * @param scene defines the scene the material belongs to.
  116. * @returns - boolean indicating that the submesh is ready or not.
  117. */
  118. public isReadyForSubMesh(defines: IMaterialSheenDefines, scene: Scene): boolean {
  119. if (defines._areTexturesDirty) {
  120. if (scene.texturesEnabled) {
  121. if (this._texture && MaterialFlags.SheenTextureEnabled) {
  122. if (!this._texture.isReadyOrNotBlocking()) {
  123. return false;
  124. }
  125. }
  126. if (this._textureRoughness && MaterialFlags.SheenTextureEnabled) {
  127. if (!this._textureRoughness.isReadyOrNotBlocking()) {
  128. return false;
  129. }
  130. }
  131. }
  132. }
  133. return true;
  134. }
  135. /**
  136. * Checks to see if a texture is used in the material.
  137. * @param defines the list of "defines" to update.
  138. * @param scene defines the scene the material belongs to.
  139. */
  140. public prepareDefines(defines: IMaterialSheenDefines, scene: Scene): void {
  141. if (this._isEnabled) {
  142. defines.SHEEN = this._isEnabled;
  143. defines.SHEEN_LINKWITHALBEDO = this._linkSheenWithAlbedo;
  144. defines.SHEEN_ROUGHNESS = this._roughness !== null;
  145. defines.SHEEN_ALBEDOSCALING = this._albedoScaling;
  146. defines.SHEEN_USE_ROUGHNESS_FROM_TEXTURE = this._useRoughnessFromMainTexture;
  147. defines.SHEEN_TEXTURE_ROUGHNESS_IDENTICAL = this.texture !== null && this.texture._texture === this.textureRoughness?._texture;
  148. if (defines._areTexturesDirty) {
  149. if (scene.texturesEnabled) {
  150. if (this._texture && MaterialFlags.SheenTextureEnabled) {
  151. MaterialHelper.PrepareDefinesForMergedUV(this._texture, defines, "SHEEN_TEXTURE");
  152. } else {
  153. defines.SHEEN_TEXTURE = false;
  154. }
  155. if (this._textureRoughness && MaterialFlags.SheenTextureEnabled) {
  156. MaterialHelper.PrepareDefinesForMergedUV(this._textureRoughness, defines, "SHEEN_TEXTURE_ROUGHNESS");
  157. } else {
  158. defines.SHEEN_TEXTURE_ROUGHNESS = false;
  159. }
  160. }
  161. }
  162. }
  163. else {
  164. defines.SHEEN = false;
  165. defines.SHEEN_TEXTURE = false;
  166. defines.SHEEN_LINKWITHALBEDO = false;
  167. defines.SHEEN_ROUGHNESS = false;
  168. defines.SHEEN_ALBEDOSCALING = false;
  169. defines.SHEEN_USE_ROUGHNESS_FROM_TEXTURE = false;
  170. defines.SHEEN_TEXTURE_ROUGHNESS_IDENTICAL = false;
  171. }
  172. }
  173. /**
  174. * Binds the material data.
  175. * @param uniformBuffer defines the Uniform buffer to fill in.
  176. * @param scene defines the scene the material belongs to.
  177. * @param isFrozen defines wether the material is frozen or not.
  178. */
  179. public bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, isFrozen: boolean): void {
  180. if (!uniformBuffer.useUbo || !isFrozen || !uniformBuffer.isSync) {
  181. if ((this._texture || this._textureRoughness) && MaterialFlags.SheenTextureEnabled) {
  182. uniformBuffer.updateFloat4("vSheenInfos", this._texture?.coordinatesIndex ?? this._textureRoughness?.coordinatesIndex ?? 0, this._texture?.level ?? 0, 0 /* not used */, this._textureRoughness?.level ?? 0);
  183. if (this._texture) {
  184. MaterialHelper.BindTextureMatrix(this._texture, uniformBuffer, "sheen");
  185. } else if (this._textureRoughness) {
  186. MaterialHelper.BindTextureMatrix(this._textureRoughness, uniformBuffer, "sheen");
  187. }
  188. }
  189. // Sheen
  190. uniformBuffer.updateFloat4("vSheenColor",
  191. this.color.r,
  192. this.color.g,
  193. this.color.b,
  194. this.intensity);
  195. if (this._roughness !== null) {
  196. uniformBuffer.updateFloat("vSheenRoughness", this._roughness);
  197. }
  198. }
  199. // Textures
  200. if (scene.texturesEnabled) {
  201. if (this._texture && MaterialFlags.SheenTextureEnabled) {
  202. uniformBuffer.setTexture("sheenSampler", this._texture);
  203. }
  204. if (this.textureRoughness && (this.texture === null || this.texture._texture !== this.textureRoughness._texture) && MaterialFlags.SheenTextureEnabled) {
  205. uniformBuffer.setTexture("sheenRoughnessSampler", this._textureRoughness);
  206. }
  207. }
  208. }
  209. /**
  210. * Checks to see if a texture is used in the material.
  211. * @param texture - Base texture to use.
  212. * @returns - Boolean specifying if a texture is used in the material.
  213. */
  214. public hasTexture(texture: BaseTexture): boolean {
  215. if (this._texture === texture) {
  216. return true;
  217. }
  218. if (this._textureRoughness === texture) {
  219. return true;
  220. }
  221. return false;
  222. }
  223. /**
  224. * Returns an array of the actively used textures.
  225. * @param activeTextures Array of BaseTextures
  226. */
  227. public getActiveTextures(activeTextures: BaseTexture[]): void {
  228. if (this._texture) {
  229. activeTextures.push(this._texture);
  230. }
  231. if (this._textureRoughness) {
  232. activeTextures.push(this._textureRoughness);
  233. }
  234. }
  235. /**
  236. * Returns the animatable textures.
  237. * @param animatables Array of animatable textures.
  238. */
  239. public getAnimatables(animatables: IAnimatable[]): void {
  240. if (this._texture && this._texture.animations && this._texture.animations.length > 0) {
  241. animatables.push(this._texture);
  242. }
  243. if (this._textureRoughness && this._textureRoughness.animations && this._textureRoughness.animations.length > 0) {
  244. animatables.push(this._textureRoughness);
  245. }
  246. }
  247. /**
  248. * Disposes the resources of the material.
  249. * @param forceDisposeTextures - Forces the disposal of all textures.
  250. */
  251. public dispose(forceDisposeTextures?: boolean): void {
  252. if (forceDisposeTextures) {
  253. this._texture?.dispose();
  254. this._textureRoughness?.dispose();
  255. }
  256. }
  257. /**
  258. * Get the current class name of the texture useful for serialization or dynamic coding.
  259. * @returns "PBRSheenConfiguration"
  260. */
  261. public getClassName(): string {
  262. return "PBRSheenConfiguration";
  263. }
  264. /**
  265. * Add fallbacks to the effect fallbacks list.
  266. * @param defines defines the Base texture to use.
  267. * @param fallbacks defines the current fallback list.
  268. * @param currentRank defines the current fallback rank.
  269. * @returns the new fallback rank.
  270. */
  271. public static AddFallbacks(defines: IMaterialSheenDefines, fallbacks: EffectFallbacks, currentRank: number): number {
  272. if (defines.SHEEN) {
  273. fallbacks.addFallback(currentRank++, "SHEEN");
  274. }
  275. return currentRank;
  276. }
  277. /**
  278. * Add the required uniforms to the current list.
  279. * @param uniforms defines the current uniform list.
  280. */
  281. public static AddUniforms(uniforms: string[]): void {
  282. uniforms.push("vSheenColor", "vSheenRoughness", "vSheenInfos", "sheenMatrix");
  283. }
  284. /**
  285. * Add the required uniforms to the current buffer.
  286. * @param uniformBuffer defines the current uniform buffer.
  287. */
  288. public static PrepareUniformBuffer(uniformBuffer: UniformBuffer): void {
  289. uniformBuffer.addUniform("vSheenColor", 4);
  290. uniformBuffer.addUniform("vSheenRoughness", 1);
  291. uniformBuffer.addUniform("vSheenInfos", 4);
  292. uniformBuffer.addUniform("sheenMatrix", 16);
  293. }
  294. /**
  295. * Add the required samplers to the current list.
  296. * @param samplers defines the current sampler list.
  297. */
  298. public static AddSamplers(samplers: string[]): void {
  299. samplers.push("sheenSampler");
  300. samplers.push("sheenRoughnessSampler");
  301. }
  302. /**
  303. * Makes a duplicate of the current configuration into another one.
  304. * @param sheenConfiguration define the config where to copy the info
  305. */
  306. public copyTo(sheenConfiguration: PBRSheenConfiguration): void {
  307. SerializationHelper.Clone(() => sheenConfiguration, this);
  308. }
  309. /**
  310. * Serializes this BRDF configuration.
  311. * @returns - An object with the serialized config.
  312. */
  313. public serialize(): any {
  314. return SerializationHelper.Serialize(this);
  315. }
  316. /**
  317. * Parses a anisotropy Configuration from a serialized object.
  318. * @param source - Serialized object.
  319. * @param scene Defines the scene we are parsing for
  320. * @param rootUrl Defines the rootUrl to load from
  321. */
  322. public parse(source: any, scene: Scene, rootUrl: string): void {
  323. SerializationHelper.Parse(() => this, source, scene, rootUrl);
  324. }
  325. }