material.detailMapConfiguration.ts 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. import { Nullable } from "../types";
  2. import { Scene } from "../scene";
  3. import { Material } from "./material";
  4. import { _TypeStore } from "../Misc/typeStore";
  5. import { serialize, expandToProperty, serializeAsTexture, SerializationHelper } from '../Misc/decorators';
  6. import { MaterialFlags } from './materialFlags';
  7. import { MaterialHelper } from './materialHelper';
  8. import { BaseTexture } from './Textures/baseTexture';
  9. import { UniformBuffer } from './uniformBuffer';
  10. import { IAnimatable } from '../Animations/animatable.interface';
  11. /**
  12. * @hidden
  13. */
  14. export interface IMaterialDetailMapDefines {
  15. DETAIL: boolean;
  16. DETAILDIRECTUV : number;
  17. DETAIL_NORMALBLENDMETHOD: number;
  18. /** @hidden */
  19. _areTexturesDirty: boolean;
  20. }
  21. /**
  22. * Define the code related to the detail map parameters of a material
  23. *
  24. * Inspired from:
  25. * Unity: https://docs.unity3d.com/Packages/com.unity.render-pipelines.high-definition@9.0/manual/Mask-Map-and-Detail-Map.html and https://docs.unity3d.com/Manual/StandardShaderMaterialParameterDetail.html
  26. * Unreal: https://docs.unrealengine.com/en-US/Engine/Rendering/Materials/HowTo/DetailTexturing/index.html
  27. * Cryengine: https://docs.cryengine.com/display/SDKDOC2/Detail+Maps
  28. */
  29. export class DetailMapConfiguration {
  30. private _texture: Nullable<BaseTexture> = null;
  31. /**
  32. * The detail texture of the material.
  33. */
  34. @serializeAsTexture("detailTexture")
  35. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  36. public texture: Nullable<BaseTexture>;
  37. /**
  38. * Defines how strongly the detail diffuse/albedo channel is blended with the regular diffuse/albedo texture
  39. * Bigger values mean stronger blending
  40. */
  41. @serialize()
  42. public diffuseBlendLevel = 1;
  43. /**
  44. * Defines how strongly the detail roughness channel is blended with the regular roughness value
  45. * Bigger values mean stronger blending. Only used with PBR materials
  46. */
  47. @serialize()
  48. public roughnessBlendLevel = 1;
  49. /**
  50. * Defines how strong the bump effect from the detail map is
  51. * Bigger values mean stronger effect
  52. */
  53. @serialize()
  54. public bumpLevel = 1;
  55. private _normalBlendMethod = Material.MATERIAL_NORMALBLENDMETHOD_WHITEOUT;
  56. /**
  57. * The method used to blend the bump and detail normals together
  58. */
  59. @serialize()
  60. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  61. public normalBlendMethod: number;
  62. private _isEnabled = false;
  63. /**
  64. * Enable or disable the detail map on this material
  65. */
  66. @serialize()
  67. @expandToProperty("_markAllSubMeshesAsTexturesDirty")
  68. public isEnabled = false;
  69. /** @hidden */
  70. private _internalMarkAllSubMeshesAsTexturesDirty: () => void;
  71. /** @hidden */
  72. public _markAllSubMeshesAsTexturesDirty(): void {
  73. this._internalMarkAllSubMeshesAsTexturesDirty();
  74. }
  75. /**
  76. * Instantiate a new detail map
  77. * @param markAllSubMeshesAsTexturesDirty Callback to flag the material to dirty
  78. */
  79. constructor(markAllSubMeshesAsTexturesDirty: () => void) {
  80. this._internalMarkAllSubMeshesAsTexturesDirty = markAllSubMeshesAsTexturesDirty;
  81. }
  82. /**
  83. * Gets whether the submesh is ready to be used or not.
  84. * @param defines the list of "defines" to update.
  85. * @param scene defines the scene the material belongs to.
  86. * @returns - boolean indicating that the submesh is ready or not.
  87. */
  88. public isReadyForSubMesh(defines: IMaterialDetailMapDefines, scene: Scene): boolean {
  89. const engine = scene.getEngine();
  90. if (defines._areTexturesDirty && scene.texturesEnabled) {
  91. if (engine.getCaps().standardDerivatives && this._texture && MaterialFlags.DetailTextureEnabled) {
  92. // Detail texture cannot be not blocking.
  93. if (!this._texture.isReady()) {
  94. return false;
  95. }
  96. }
  97. }
  98. return true;
  99. }
  100. /**
  101. * Update the defines for detail map usage
  102. * @param defines the list of "defines" to update.
  103. * @param scene defines the scene the material belongs to.
  104. */
  105. public prepareDefines(defines: IMaterialDetailMapDefines, scene: Scene): void {
  106. if (this._isEnabled) {
  107. defines.DETAIL_NORMALBLENDMETHOD = this._normalBlendMethod;
  108. const engine = scene.getEngine();
  109. if (defines._areTexturesDirty) {
  110. if (engine.getCaps().standardDerivatives && this._texture && MaterialFlags.DetailTextureEnabled && this._isEnabled) {
  111. MaterialHelper.PrepareDefinesForMergedUV(this._texture, defines, "DETAIL");
  112. defines.DETAIL_NORMALBLENDMETHOD = this._normalBlendMethod;
  113. } else {
  114. defines.DETAIL = false;
  115. }
  116. }
  117. } else {
  118. defines.DETAIL = false;
  119. }
  120. }
  121. /**
  122. * Binds the material data.
  123. * @param uniformBuffer defines the Uniform buffer to fill in.
  124. * @param scene defines the scene the material belongs to.
  125. * @param isFrozen defines whether the material is frozen or not.
  126. */
  127. public bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, isFrozen: boolean): void {
  128. if (!this._isEnabled) {
  129. return;
  130. }
  131. if (!uniformBuffer.useUbo || !isFrozen || !uniformBuffer.isSync) {
  132. if (this._texture && MaterialFlags.DetailTextureEnabled) {
  133. uniformBuffer.updateFloat4("vDetailInfos", this._texture.coordinatesIndex, this.diffuseBlendLevel, this.bumpLevel, this.roughnessBlendLevel);
  134. MaterialHelper.BindTextureMatrix(this._texture, uniformBuffer, "detail");
  135. }
  136. }
  137. // Textures
  138. if (scene.texturesEnabled) {
  139. if (this._texture && MaterialFlags.DetailTextureEnabled) {
  140. uniformBuffer.setTexture("detailSampler", this._texture);
  141. }
  142. }
  143. }
  144. /**
  145. * Checks to see if a texture is used in the material.
  146. * @param texture - Base texture to use.
  147. * @returns - Boolean specifying if a texture is used in the material.
  148. */
  149. public hasTexture(texture: BaseTexture): boolean {
  150. if (this._texture === texture) {
  151. return true;
  152. }
  153. return false;
  154. }
  155. /**
  156. * Returns an array of the actively used textures.
  157. * @param activeTextures Array of BaseTextures
  158. */
  159. public getActiveTextures(activeTextures: BaseTexture[]): void {
  160. if (this._texture) {
  161. activeTextures.push(this._texture);
  162. }
  163. }
  164. /**
  165. * Returns the animatable textures.
  166. * @param animatables Array of animatable textures.
  167. */
  168. public getAnimatables(animatables: IAnimatable[]): void {
  169. if (this._texture && this._texture.animations && this._texture.animations.length > 0) {
  170. animatables.push(this._texture);
  171. }
  172. }
  173. /**
  174. * Disposes the resources of the material.
  175. * @param forceDisposeTextures - Forces the disposal of all textures.
  176. */
  177. public dispose(forceDisposeTextures?: boolean): void {
  178. if (forceDisposeTextures) {
  179. this._texture?.dispose();
  180. }
  181. }
  182. /**
  183. * Get the current class name useful for serialization or dynamic coding.
  184. * @returns "DetailMap"
  185. */
  186. public getClassName(): string {
  187. return "DetailMap";
  188. }
  189. /**
  190. * Add the required uniforms to the current list.
  191. * @param uniforms defines the current uniform list.
  192. */
  193. public static AddUniforms(uniforms: string[]): void {
  194. uniforms.push("vDetailInfos");
  195. }
  196. /**
  197. * Add the required samplers to the current list.
  198. * @param samplers defines the current sampler list.
  199. */
  200. public static AddSamplers(samplers: string[]): void {
  201. samplers.push("detailSampler");
  202. }
  203. /**
  204. * Add the required uniforms to the current buffer.
  205. * @param uniformBuffer defines the current uniform buffer.
  206. */
  207. public static PrepareUniformBuffer(uniformBuffer: UniformBuffer): void {
  208. uniformBuffer.addUniform("vDetailInfos", 4);
  209. uniformBuffer.addUniform("detailMatrix", 16);
  210. }
  211. /**
  212. * Makes a duplicate of the current instance into another one.
  213. * @param detailMap define the instance where to copy the info
  214. */
  215. public copyTo(detailMap: DetailMapConfiguration): void {
  216. SerializationHelper.Clone(() => detailMap, this);
  217. }
  218. /**
  219. * Serializes this detail map instance
  220. * @returns - An object with the serialized instance.
  221. */
  222. public serialize(): any {
  223. return SerializationHelper.Serialize(this);
  224. }
  225. /**
  226. * Parses a detail map setting from a serialized object.
  227. * @param source - Serialized object.
  228. * @param scene Defines the scene we are parsing for
  229. * @param rootUrl Defines the rootUrl to load from
  230. */
  231. public parse(source: any, scene: Scene, rootUrl: string): void {
  232. SerializationHelper.Parse(() => this, source, scene, rootUrl);
  233. }
  234. }