shaderMaterial.js 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473
  1. import { SerializationHelper } from "../Misc/decorators.serialization.js";
  2. import { Scene } from "../scene.js";
  3. import { Matrix, Vector3, Vector2, Vector4, Quaternion } from "../Maths/math.vector.js";
  4. import { VertexBuffer } from "../Buffers/buffer.js";
  5. import { Texture } from "../Materials/Textures/texture.js";
  6. import { RegisterClass } from "../Misc/typeStore.js";
  7. import { Color3, Color4 } from "../Maths/math.color.js";
  8. import { EffectFallbacks } from "./effectFallbacks.js";
  9. import { WebRequest } from "../Misc/webRequest.js";
  10. import { PushMaterial } from "./pushMaterial.js";
  11. import { EngineStore } from "../Engines/engineStore.js";
  12. import { addClipPlaneUniforms, bindClipPlane, prepareStringDefinesForClipPlanes } from "./clipPlaneMaterialHelper.js";
  13. import { BindBonesParameters, BindFogParameters, BindLogDepth, BindMorphTargetParameters, BindSceneUniformBuffer, PrepareAttributesForBakedVertexAnimation, PushAttributesForInstances, } from "./materialHelper.functions.js";
  14. const onCreatedEffectParameters = { effect: null, subMesh: null };
  15. /**
  16. * The ShaderMaterial object has the necessary methods to pass data from your scene to the Vertex and Fragment Shaders and returns a material that can be applied to any mesh.
  17. *
  18. * This returned material effects how the mesh will look based on the code in the shaders.
  19. *
  20. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/shaders/shaderMaterial
  21. */
  22. export class ShaderMaterial extends PushMaterial {
  23. /**
  24. * Instantiate a new shader material.
  25. * The ShaderMaterial object has the necessary methods to pass data from your scene to the Vertex and Fragment Shaders and returns a material that can be applied to any mesh.
  26. * This returned material effects how the mesh will look based on the code in the shaders.
  27. * @see https://doc.babylonjs.com/features/featuresDeepDive/materials/shaders/shaderMaterial
  28. * @param name Define the name of the material in the scene
  29. * @param scene Define the scene the material belongs to
  30. * @param shaderPath Defines the route to the shader code.
  31. * @param options Define the options used to create the shader
  32. * @param storeEffectOnSubMeshes true to store effect on submeshes, false to store the effect directly in the material class.
  33. */
  34. constructor(name, scene, shaderPath, options = {}, storeEffectOnSubMeshes = true) {
  35. super(name, scene, storeEffectOnSubMeshes);
  36. this._textures = {};
  37. this._textureArrays = {};
  38. this._externalTextures = {};
  39. this._floats = {};
  40. this._ints = {};
  41. this._uints = {};
  42. this._floatsArrays = {};
  43. this._colors3 = {};
  44. this._colors3Arrays = {};
  45. this._colors4 = {};
  46. this._colors4Arrays = {};
  47. this._vectors2 = {};
  48. this._vectors3 = {};
  49. this._vectors4 = {};
  50. this._quaternions = {};
  51. this._quaternionsArrays = {};
  52. this._matrices = {};
  53. this._matrixArrays = {};
  54. this._matrices3x3 = {};
  55. this._matrices2x2 = {};
  56. this._vectors2Arrays = {};
  57. this._vectors3Arrays = {};
  58. this._vectors4Arrays = {};
  59. this._uniformBuffers = {};
  60. this._textureSamplers = {};
  61. this._storageBuffers = {};
  62. this._cachedWorldViewMatrix = new Matrix();
  63. this._cachedWorldViewProjectionMatrix = new Matrix();
  64. this._multiview = false;
  65. /**
  66. * @internal
  67. */
  68. this._materialHelperNeedsPreviousMatrices = false;
  69. this._shaderPath = shaderPath;
  70. this._options = {
  71. needAlphaBlending: false,
  72. needAlphaTesting: false,
  73. attributes: ["position", "normal", "uv"],
  74. uniforms: ["worldViewProjection"],
  75. uniformBuffers: [],
  76. samplers: [],
  77. externalTextures: [],
  78. samplerObjects: [],
  79. storageBuffers: [],
  80. defines: [],
  81. useClipPlane: false,
  82. ...options,
  83. };
  84. }
  85. /**
  86. * Gets the shader path used to define the shader code
  87. * It can be modified to trigger a new compilation
  88. */
  89. get shaderPath() {
  90. return this._shaderPath;
  91. }
  92. /**
  93. * Sets the shader path used to define the shader code
  94. * It can be modified to trigger a new compilation
  95. */
  96. set shaderPath(shaderPath) {
  97. this._shaderPath = shaderPath;
  98. }
  99. /**
  100. * Gets the options used to compile the shader.
  101. * They can be modified to trigger a new compilation
  102. */
  103. get options() {
  104. return this._options;
  105. }
  106. /**
  107. * is multiview set to true?
  108. */
  109. get isMultiview() {
  110. return this._multiview;
  111. }
  112. /**
  113. * Gets the current class name of the material e.g. "ShaderMaterial"
  114. * Mainly use in serialization.
  115. * @returns the class name
  116. */
  117. getClassName() {
  118. return "ShaderMaterial";
  119. }
  120. /**
  121. * Specifies if the material will require alpha blending
  122. * @returns a boolean specifying if alpha blending is needed
  123. */
  124. needAlphaBlending() {
  125. return this.alpha < 1.0 || this._options.needAlphaBlending;
  126. }
  127. /**
  128. * Specifies if this material should be rendered in alpha test mode
  129. * @returns a boolean specifying if an alpha test is needed.
  130. */
  131. needAlphaTesting() {
  132. return this._options.needAlphaTesting;
  133. }
  134. _checkUniform(uniformName) {
  135. if (this._options.uniforms.indexOf(uniformName) === -1) {
  136. this._options.uniforms.push(uniformName);
  137. }
  138. }
  139. /**
  140. * Set a texture in the shader.
  141. * @param name Define the name of the uniform samplers as defined in the shader
  142. * @param texture Define the texture to bind to this sampler
  143. * @returns the material itself allowing "fluent" like uniform updates
  144. */
  145. setTexture(name, texture) {
  146. if (this._options.samplers.indexOf(name) === -1) {
  147. this._options.samplers.push(name);
  148. }
  149. this._textures[name] = texture;
  150. return this;
  151. }
  152. /**
  153. * Set a texture array in the shader.
  154. * @param name Define the name of the uniform sampler array as defined in the shader
  155. * @param textures Define the list of textures to bind to this sampler
  156. * @returns the material itself allowing "fluent" like uniform updates
  157. */
  158. setTextureArray(name, textures) {
  159. if (this._options.samplers.indexOf(name) === -1) {
  160. this._options.samplers.push(name);
  161. }
  162. this._checkUniform(name);
  163. this._textureArrays[name] = textures;
  164. return this;
  165. }
  166. /**
  167. * Set an internal texture in the shader.
  168. * @param name Define the name of the uniform samplers as defined in the shader
  169. * @param texture Define the texture to bind to this sampler
  170. * @returns the material itself allowing "fluent" like uniform updates
  171. */
  172. setExternalTexture(name, texture) {
  173. if (this._options.externalTextures.indexOf(name) === -1) {
  174. this._options.externalTextures.push(name);
  175. }
  176. this._externalTextures[name] = texture;
  177. return this;
  178. }
  179. /**
  180. * Set a float in the shader.
  181. * @param name Define the name of the uniform as defined in the shader
  182. * @param value Define the value to give to the uniform
  183. * @returns the material itself allowing "fluent" like uniform updates
  184. */
  185. setFloat(name, value) {
  186. this._checkUniform(name);
  187. this._floats[name] = value;
  188. return this;
  189. }
  190. /**
  191. * Set a int in the shader.
  192. * @param name Define the name of the uniform as defined in the shader
  193. * @param value Define the value to give to the uniform
  194. * @returns the material itself allowing "fluent" like uniform updates
  195. */
  196. setInt(name, value) {
  197. this._checkUniform(name);
  198. this._ints[name] = value;
  199. return this;
  200. }
  201. /**
  202. * Set a unsigned int in the shader.
  203. * @param name Define the name of the uniform as defined in the shader
  204. * @param value Define the value to give to the uniform
  205. * @returns the material itself allowing "fluent" like uniform updates
  206. */
  207. setUInt(name, value) {
  208. this._checkUniform(name);
  209. this._uints[name] = value;
  210. return this;
  211. }
  212. /**
  213. * Set an array of floats in the shader.
  214. * @param name Define the name of the uniform as defined in the shader
  215. * @param value Define the value to give to the uniform
  216. * @returns the material itself allowing "fluent" like uniform updates
  217. */
  218. setFloats(name, value) {
  219. this._checkUniform(name);
  220. this._floatsArrays[name] = value;
  221. return this;
  222. }
  223. /**
  224. * Set a vec3 in the shader from a Color3.
  225. * @param name Define the name of the uniform as defined in the shader
  226. * @param value Define the value to give to the uniform
  227. * @returns the material itself allowing "fluent" like uniform updates
  228. */
  229. setColor3(name, value) {
  230. this._checkUniform(name);
  231. this._colors3[name] = value;
  232. return this;
  233. }
  234. /**
  235. * Set a vec3 array in the shader from a Color3 array.
  236. * @param name Define the name of the uniform as defined in the shader
  237. * @param value Define the value to give to the uniform
  238. * @returns the material itself allowing "fluent" like uniform updates
  239. */
  240. setColor3Array(name, value) {
  241. this._checkUniform(name);
  242. this._colors3Arrays[name] = value.reduce((arr, color) => {
  243. color.toArray(arr, arr.length);
  244. return arr;
  245. }, []);
  246. return this;
  247. }
  248. /**
  249. * Set a vec4 in the shader from a Color4.
  250. * @param name Define the name of the uniform as defined in the shader
  251. * @param value Define the value to give to the uniform
  252. * @returns the material itself allowing "fluent" like uniform updates
  253. */
  254. setColor4(name, value) {
  255. this._checkUniform(name);
  256. this._colors4[name] = value;
  257. return this;
  258. }
  259. /**
  260. * Set a vec4 array in the shader from a Color4 array.
  261. * @param name Define the name of the uniform as defined in the shader
  262. * @param value Define the value to give to the uniform
  263. * @returns the material itself allowing "fluent" like uniform updates
  264. */
  265. setColor4Array(name, value) {
  266. this._checkUniform(name);
  267. this._colors4Arrays[name] = value.reduce((arr, color) => {
  268. color.toArray(arr, arr.length);
  269. return arr;
  270. }, []);
  271. return this;
  272. }
  273. /**
  274. * Set a vec2 in the shader from a Vector2.
  275. * @param name Define the name of the uniform as defined in the shader
  276. * @param value Define the value to give to the uniform
  277. * @returns the material itself allowing "fluent" like uniform updates
  278. */
  279. setVector2(name, value) {
  280. this._checkUniform(name);
  281. this._vectors2[name] = value;
  282. return this;
  283. }
  284. /**
  285. * Set a vec3 in the shader from a Vector3.
  286. * @param name Define the name of the uniform as defined in the shader
  287. * @param value Define the value to give to the uniform
  288. * @returns the material itself allowing "fluent" like uniform updates
  289. */
  290. setVector3(name, value) {
  291. this._checkUniform(name);
  292. this._vectors3[name] = value;
  293. return this;
  294. }
  295. /**
  296. * Set a vec4 in the shader from a Vector4.
  297. * @param name Define the name of the uniform as defined in the shader
  298. * @param value Define the value to give to the uniform
  299. * @returns the material itself allowing "fluent" like uniform updates
  300. */
  301. setVector4(name, value) {
  302. this._checkUniform(name);
  303. this._vectors4[name] = value;
  304. return this;
  305. }
  306. /**
  307. * Set a vec4 in the shader from a Quaternion.
  308. * @param name Define the name of the uniform as defined in the shader
  309. * @param value Define the value to give to the uniform
  310. * @returns the material itself allowing "fluent" like uniform updates
  311. */
  312. setQuaternion(name, value) {
  313. this._checkUniform(name);
  314. this._quaternions[name] = value;
  315. return this;
  316. }
  317. /**
  318. * Set a vec4 array in the shader from a Quaternion array.
  319. * @param name Define the name of the uniform as defined in the shader
  320. * @param value Define the value to give to the uniform
  321. * @returns the material itself allowing "fluent" like uniform updates
  322. */
  323. setQuaternionArray(name, value) {
  324. this._checkUniform(name);
  325. this._quaternionsArrays[name] = value.reduce((arr, quaternion) => {
  326. quaternion.toArray(arr, arr.length);
  327. return arr;
  328. }, []);
  329. return this;
  330. }
  331. /**
  332. * Set a mat4 in the shader from a Matrix.
  333. * @param name Define the name of the uniform as defined in the shader
  334. * @param value Define the value to give to the uniform
  335. * @returns the material itself allowing "fluent" like uniform updates
  336. */
  337. setMatrix(name, value) {
  338. this._checkUniform(name);
  339. this._matrices[name] = value;
  340. return this;
  341. }
  342. /**
  343. * Set a float32Array in the shader from a matrix array.
  344. * @param name Define the name of the uniform as defined in the shader
  345. * @param value Define the value to give to the uniform
  346. * @returns the material itself allowing "fluent" like uniform updates
  347. */
  348. setMatrices(name, value) {
  349. this._checkUniform(name);
  350. const float32Array = new Float32Array(value.length * 16);
  351. for (let index = 0; index < value.length; index++) {
  352. const matrix = value[index];
  353. matrix.copyToArray(float32Array, index * 16);
  354. }
  355. this._matrixArrays[name] = float32Array;
  356. return this;
  357. }
  358. /**
  359. * Set a mat3 in the shader from a Float32Array.
  360. * @param name Define the name of the uniform as defined in the shader
  361. * @param value Define the value to give to the uniform
  362. * @returns the material itself allowing "fluent" like uniform updates
  363. */
  364. setMatrix3x3(name, value) {
  365. this._checkUniform(name);
  366. this._matrices3x3[name] = value;
  367. return this;
  368. }
  369. /**
  370. * Set a mat2 in the shader from a Float32Array.
  371. * @param name Define the name of the uniform as defined in the shader
  372. * @param value Define the value to give to the uniform
  373. * @returns the material itself allowing "fluent" like uniform updates
  374. */
  375. setMatrix2x2(name, value) {
  376. this._checkUniform(name);
  377. this._matrices2x2[name] = value;
  378. return this;
  379. }
  380. /**
  381. * Set a vec2 array in the shader from a number array.
  382. * @param name Define the name of the uniform as defined in the shader
  383. * @param value Define the value to give to the uniform
  384. * @returns the material itself allowing "fluent" like uniform updates
  385. */
  386. setArray2(name, value) {
  387. this._checkUniform(name);
  388. this._vectors2Arrays[name] = value;
  389. return this;
  390. }
  391. /**
  392. * Set a vec3 array in the shader from a number array.
  393. * @param name Define the name of the uniform as defined in the shader
  394. * @param value Define the value to give to the uniform
  395. * @returns the material itself allowing "fluent" like uniform updates
  396. */
  397. setArray3(name, value) {
  398. this._checkUniform(name);
  399. this._vectors3Arrays[name] = value;
  400. return this;
  401. }
  402. /**
  403. * Set a vec4 array in the shader from a number array.
  404. * @param name Define the name of the uniform as defined in the shader
  405. * @param value Define the value to give to the uniform
  406. * @returns the material itself allowing "fluent" like uniform updates
  407. */
  408. setArray4(name, value) {
  409. this._checkUniform(name);
  410. this._vectors4Arrays[name] = value;
  411. return this;
  412. }
  413. /**
  414. * Set a uniform buffer in the shader
  415. * @param name Define the name of the uniform as defined in the shader
  416. * @param buffer Define the value to give to the uniform
  417. * @returns the material itself allowing "fluent" like uniform updates
  418. */
  419. setUniformBuffer(name, buffer) {
  420. if (this._options.uniformBuffers.indexOf(name) === -1) {
  421. this._options.uniformBuffers.push(name);
  422. }
  423. this._uniformBuffers[name] = buffer;
  424. return this;
  425. }
  426. /**
  427. * Set a texture sampler in the shader
  428. * @param name Define the name of the uniform as defined in the shader
  429. * @param sampler Define the value to give to the uniform
  430. * @returns the material itself allowing "fluent" like uniform updates
  431. */
  432. setTextureSampler(name, sampler) {
  433. if (this._options.samplerObjects.indexOf(name) === -1) {
  434. this._options.samplerObjects.push(name);
  435. }
  436. this._textureSamplers[name] = sampler;
  437. return this;
  438. }
  439. /**
  440. * Set a storage buffer in the shader
  441. * @param name Define the name of the storage buffer as defined in the shader
  442. * @param buffer Define the value to give to the uniform
  443. * @returns the material itself allowing "fluent" like uniform updates
  444. */
  445. setStorageBuffer(name, buffer) {
  446. if (this._options.storageBuffers.indexOf(name) === -1) {
  447. this._options.storageBuffers.push(name);
  448. }
  449. this._storageBuffers[name] = buffer;
  450. return this;
  451. }
  452. /**
  453. * Adds, removes, or replaces the specified shader define and value.
  454. * * setDefine("MY_DEFINE", true); // enables a boolean define
  455. * * setDefine("MY_DEFINE", "0.5"); // adds "#define MY_DEFINE 0.5" to the shader (or sets and replaces the value of any existing define with that name)
  456. * * setDefine("MY_DEFINE", false); // disables and removes the define
  457. * Note if the active defines do change, the shader will be recompiled and this can be expensive.
  458. * @param define the define name e.g., "OUTPUT_TO_SRGB" or "#define OUTPUT_TO_SRGB". If the define was passed into the constructor already, the version used should match that, and in either case, it should not include any appended value.
  459. * @param value either the value of the define (e.g. a numerical value) or for booleans, true if the define should be enabled or false if it should be disabled
  460. * @returns the material itself allowing "fluent" like uniform updates
  461. */
  462. setDefine(define, value) {
  463. // First remove any existing define with this name.
  464. const defineName = define.trimEnd() + " ";
  465. const existingDefineIdx = this.options.defines.findIndex((x) => x === define || x.startsWith(defineName));
  466. if (existingDefineIdx >= 0) {
  467. this.options.defines.splice(existingDefineIdx, 1);
  468. }
  469. // Then add the new define value. (If it's a boolean value and false, don't add it.)
  470. if (typeof value !== "boolean" || value) {
  471. this.options.defines.push(defineName + value);
  472. }
  473. return this;
  474. }
  475. /**
  476. * Specifies that the submesh is ready to be used
  477. * @param mesh defines the mesh to check
  478. * @param subMesh defines which submesh to check
  479. * @param useInstances specifies that instances should be used
  480. * @returns a boolean indicating that the submesh is ready or not
  481. */
  482. isReadyForSubMesh(mesh, subMesh, useInstances) {
  483. return this.isReady(mesh, useInstances, subMesh);
  484. }
  485. /**
  486. * Checks if the material is ready to render the requested mesh
  487. * @param mesh Define the mesh to render
  488. * @param useInstances Define whether or not the material is used with instances
  489. * @param subMesh defines which submesh to render
  490. * @returns true if ready, otherwise false
  491. */
  492. isReady(mesh, useInstances, subMesh) {
  493. const storeEffectOnSubMeshes = subMesh && this._storeEffectOnSubMeshes;
  494. if (this.isFrozen) {
  495. const drawWrapper = storeEffectOnSubMeshes ? subMesh._drawWrapper : this._drawWrapper;
  496. if (drawWrapper.effect && drawWrapper._wasPreviouslyReady && drawWrapper._wasPreviouslyUsingInstances === useInstances) {
  497. return true;
  498. }
  499. }
  500. const scene = this.getScene();
  501. const engine = scene.getEngine();
  502. // Instances
  503. const defines = [];
  504. const attribs = [];
  505. const fallbacks = new EffectFallbacks();
  506. let shaderName = this._shaderPath, uniforms = this._options.uniforms, uniformBuffers = this._options.uniformBuffers, samplers = this._options.samplers;
  507. // global multiview
  508. if (engine.getCaps().multiview && scene.activeCamera && scene.activeCamera.outputRenderTarget && scene.activeCamera.outputRenderTarget.getViewCount() > 1) {
  509. this._multiview = true;
  510. defines.push("#define MULTIVIEW");
  511. if (uniforms.indexOf("viewProjection") !== -1 && uniforms.indexOf("viewProjectionR") === -1) {
  512. uniforms.push("viewProjectionR");
  513. }
  514. }
  515. for (let index = 0; index < this._options.defines.length; index++) {
  516. const defineToAdd = this._options.defines[index].indexOf("#define") === 0 ? this._options.defines[index] : `#define ${this._options.defines[index]}`;
  517. defines.push(defineToAdd);
  518. }
  519. for (let index = 0; index < this._options.attributes.length; index++) {
  520. attribs.push(this._options.attributes[index]);
  521. }
  522. if (mesh && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
  523. if (attribs.indexOf(VertexBuffer.ColorKind) === -1) {
  524. attribs.push(VertexBuffer.ColorKind);
  525. }
  526. defines.push("#define VERTEXCOLOR");
  527. }
  528. if (useInstances) {
  529. defines.push("#define INSTANCES");
  530. PushAttributesForInstances(attribs, this._materialHelperNeedsPreviousMatrices);
  531. if (mesh?.hasThinInstances) {
  532. defines.push("#define THIN_INSTANCES");
  533. if (mesh && mesh.isVerticesDataPresent(VertexBuffer.ColorInstanceKind)) {
  534. attribs.push(VertexBuffer.ColorInstanceKind);
  535. defines.push("#define INSTANCESCOLOR");
  536. }
  537. }
  538. }
  539. // Bones
  540. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
  541. attribs.push(VertexBuffer.MatricesIndicesKind);
  542. attribs.push(VertexBuffer.MatricesWeightsKind);
  543. if (mesh.numBoneInfluencers > 4) {
  544. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  545. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  546. }
  547. const skeleton = mesh.skeleton;
  548. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  549. fallbacks.addCPUSkinningFallback(0, mesh);
  550. if (skeleton.isUsingTextureForMatrices) {
  551. defines.push("#define BONETEXTURE");
  552. if (uniforms.indexOf("boneTextureWidth") === -1) {
  553. uniforms.push("boneTextureWidth");
  554. }
  555. if (this._options.samplers.indexOf("boneSampler") === -1) {
  556. this._options.samplers.push("boneSampler");
  557. }
  558. }
  559. else {
  560. defines.push("#define BonesPerMesh " + (skeleton.bones.length + 1));
  561. if (uniforms.indexOf("mBones") === -1) {
  562. uniforms.push("mBones");
  563. }
  564. }
  565. }
  566. else {
  567. defines.push("#define NUM_BONE_INFLUENCERS 0");
  568. }
  569. // Morph
  570. let numInfluencers = 0;
  571. const manager = mesh ? mesh.morphTargetManager : null;
  572. if (manager) {
  573. const uv = manager.supportsUVs && defines.indexOf("#define UV1") !== -1;
  574. const tangent = manager.supportsTangents && defines.indexOf("#define TANGENT") !== -1;
  575. const normal = manager.supportsNormals && defines.indexOf("#define NORMAL") !== -1;
  576. numInfluencers = manager.numMaxInfluencers || manager.numInfluencers;
  577. if (uv) {
  578. defines.push("#define MORPHTARGETS_UV");
  579. }
  580. if (tangent) {
  581. defines.push("#define MORPHTARGETS_TANGENT");
  582. }
  583. if (normal) {
  584. defines.push("#define MORPHTARGETS_NORMAL");
  585. }
  586. if (numInfluencers > 0) {
  587. defines.push("#define MORPHTARGETS");
  588. }
  589. if (manager.isUsingTextureForTargets) {
  590. defines.push("#define MORPHTARGETS_TEXTURE");
  591. if (uniforms.indexOf("morphTargetTextureIndices") === -1) {
  592. uniforms.push("morphTargetTextureIndices");
  593. }
  594. if (this._options.samplers.indexOf("morphTargets") === -1) {
  595. this._options.samplers.push("morphTargets");
  596. }
  597. }
  598. defines.push("#define NUM_MORPH_INFLUENCERS " + numInfluencers);
  599. for (let index = 0; index < numInfluencers; index++) {
  600. attribs.push(VertexBuffer.PositionKind + index);
  601. if (normal) {
  602. attribs.push(VertexBuffer.NormalKind + index);
  603. }
  604. if (tangent) {
  605. attribs.push(VertexBuffer.TangentKind + index);
  606. }
  607. if (uv) {
  608. attribs.push(VertexBuffer.UVKind + "_" + index);
  609. }
  610. }
  611. if (numInfluencers > 0) {
  612. uniforms = uniforms.slice();
  613. uniforms.push("morphTargetInfluences");
  614. uniforms.push("morphTargetCount");
  615. uniforms.push("morphTargetTextureInfo");
  616. uniforms.push("morphTargetTextureIndices");
  617. }
  618. }
  619. else {
  620. defines.push("#define NUM_MORPH_INFLUENCERS 0");
  621. }
  622. // Baked Vertex Animation
  623. if (mesh) {
  624. const bvaManager = mesh.bakedVertexAnimationManager;
  625. if (bvaManager && bvaManager.isEnabled) {
  626. defines.push("#define BAKED_VERTEX_ANIMATION_TEXTURE");
  627. if (uniforms.indexOf("bakedVertexAnimationSettings") === -1) {
  628. uniforms.push("bakedVertexAnimationSettings");
  629. }
  630. if (uniforms.indexOf("bakedVertexAnimationTextureSizeInverted") === -1) {
  631. uniforms.push("bakedVertexAnimationTextureSizeInverted");
  632. }
  633. if (uniforms.indexOf("bakedVertexAnimationTime") === -1) {
  634. uniforms.push("bakedVertexAnimationTime");
  635. }
  636. if (this._options.samplers.indexOf("bakedVertexAnimationTexture") === -1) {
  637. this._options.samplers.push("bakedVertexAnimationTexture");
  638. }
  639. }
  640. PrepareAttributesForBakedVertexAnimation(attribs, mesh, defines);
  641. }
  642. // Textures
  643. for (const name in this._textures) {
  644. if (!this._textures[name].isReady()) {
  645. return false;
  646. }
  647. }
  648. // Alpha test
  649. if (mesh && this._shouldTurnAlphaTestOn(mesh)) {
  650. defines.push("#define ALPHATEST");
  651. }
  652. // Clip planes
  653. if (this._options.useClipPlane !== false) {
  654. addClipPlaneUniforms(uniforms);
  655. prepareStringDefinesForClipPlanes(this, scene, defines);
  656. }
  657. // Fog
  658. if (scene.fogEnabled && mesh?.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
  659. defines.push("#define FOG");
  660. if (uniforms.indexOf("view") === -1) {
  661. uniforms.push("view");
  662. }
  663. if (uniforms.indexOf("vFogInfos") === -1) {
  664. uniforms.push("vFogInfos");
  665. }
  666. if (uniforms.indexOf("vFogColor") === -1) {
  667. uniforms.push("vFogColor");
  668. }
  669. }
  670. // Misc
  671. if (this._useLogarithmicDepth) {
  672. defines.push("#define LOGARITHMICDEPTH");
  673. if (uniforms.indexOf("logarithmicDepthConstant") === -1) {
  674. uniforms.push("logarithmicDepthConstant");
  675. }
  676. }
  677. if (this.customShaderNameResolve) {
  678. uniforms = uniforms.slice();
  679. uniformBuffers = uniformBuffers.slice();
  680. samplers = samplers.slice();
  681. shaderName = this.customShaderNameResolve(this.name, uniforms, uniformBuffers, samplers, defines, attribs);
  682. }
  683. const drawWrapper = storeEffectOnSubMeshes ? subMesh._getDrawWrapper(undefined, true) : this._drawWrapper;
  684. const previousEffect = drawWrapper?.effect ?? null;
  685. const previousDefines = drawWrapper?.defines ?? null;
  686. const join = defines.join("\n");
  687. let effect = previousEffect;
  688. if (previousDefines !== join) {
  689. effect = engine.createEffect(shaderName, {
  690. attributes: attribs,
  691. uniformsNames: uniforms,
  692. uniformBuffersNames: uniformBuffers,
  693. samplers: samplers,
  694. defines: join,
  695. fallbacks: fallbacks,
  696. onCompiled: this.onCompiled,
  697. onError: this.onError,
  698. indexParameters: { maxSimultaneousMorphTargets: numInfluencers },
  699. shaderLanguage: this._options.shaderLanguage,
  700. }, engine);
  701. if (storeEffectOnSubMeshes) {
  702. subMesh.setEffect(effect, join, this._materialContext);
  703. }
  704. else if (drawWrapper) {
  705. drawWrapper.setEffect(effect, join);
  706. }
  707. if (this._onEffectCreatedObservable) {
  708. onCreatedEffectParameters.effect = effect;
  709. onCreatedEffectParameters.subMesh = subMesh ?? mesh?.subMeshes[0] ?? null;
  710. this._onEffectCreatedObservable.notifyObservers(onCreatedEffectParameters);
  711. }
  712. }
  713. drawWrapper._wasPreviouslyUsingInstances = !!useInstances;
  714. if (!effect?.isReady() ?? true) {
  715. return false;
  716. }
  717. if (previousEffect !== effect) {
  718. scene.resetCachedMaterial();
  719. }
  720. drawWrapper._wasPreviouslyReady = true;
  721. return true;
  722. }
  723. /**
  724. * Binds the world matrix to the material
  725. * @param world defines the world transformation matrix
  726. * @param effectOverride - If provided, use this effect instead of internal effect
  727. */
  728. bindOnlyWorldMatrix(world, effectOverride) {
  729. const scene = this.getScene();
  730. const effect = effectOverride ?? this.getEffect();
  731. if (!effect) {
  732. return;
  733. }
  734. if (this._options.uniforms.indexOf("world") !== -1) {
  735. effect.setMatrix("world", world);
  736. }
  737. if (this._options.uniforms.indexOf("worldView") !== -1) {
  738. world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
  739. effect.setMatrix("worldView", this._cachedWorldViewMatrix);
  740. }
  741. if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
  742. world.multiplyToRef(scene.getTransformMatrix(), this._cachedWorldViewProjectionMatrix);
  743. effect.setMatrix("worldViewProjection", this._cachedWorldViewProjectionMatrix);
  744. }
  745. if (this._options.uniforms.indexOf("view") !== -1) {
  746. effect.setMatrix("view", scene.getViewMatrix());
  747. }
  748. }
  749. /**
  750. * Binds the submesh to this material by preparing the effect and shader to draw
  751. * @param world defines the world transformation matrix
  752. * @param mesh defines the mesh containing the submesh
  753. * @param subMesh defines the submesh to bind the material to
  754. */
  755. bindForSubMesh(world, mesh, subMesh) {
  756. this.bind(world, mesh, subMesh._drawWrapperOverride?.effect, subMesh);
  757. }
  758. /**
  759. * Binds the material to the mesh
  760. * @param world defines the world transformation matrix
  761. * @param mesh defines the mesh to bind the material to
  762. * @param effectOverride - If provided, use this effect instead of internal effect
  763. * @param subMesh defines the submesh to bind the material to
  764. */
  765. bind(world, mesh, effectOverride, subMesh) {
  766. // Std values
  767. const storeEffectOnSubMeshes = subMesh && this._storeEffectOnSubMeshes;
  768. const effect = effectOverride ?? (storeEffectOnSubMeshes ? subMesh.effect : this.getEffect());
  769. if (!effect) {
  770. return;
  771. }
  772. const scene = this.getScene();
  773. this._activeEffect = effect;
  774. this.bindOnlyWorldMatrix(world, effectOverride);
  775. const uniformBuffers = this._options.uniformBuffers;
  776. let useSceneUBO = false;
  777. if (effect && uniformBuffers && uniformBuffers.length > 0 && scene.getEngine().supportsUniformBuffers) {
  778. for (let i = 0; i < uniformBuffers.length; ++i) {
  779. const bufferName = uniformBuffers[i];
  780. switch (bufferName) {
  781. case "Mesh":
  782. if (mesh) {
  783. mesh.getMeshUniformBuffer().bindToEffect(effect, "Mesh");
  784. mesh.transferToEffect(world);
  785. }
  786. break;
  787. case "Scene":
  788. BindSceneUniformBuffer(effect, scene.getSceneUniformBuffer());
  789. scene.finalizeSceneUbo();
  790. useSceneUBO = true;
  791. break;
  792. }
  793. }
  794. }
  795. const mustRebind = mesh && storeEffectOnSubMeshes ? this._mustRebind(scene, effect, subMesh, mesh.visibility) : scene.getCachedMaterial() !== this;
  796. if (effect && mustRebind) {
  797. if (!useSceneUBO && this._options.uniforms.indexOf("view") !== -1) {
  798. effect.setMatrix("view", scene.getViewMatrix());
  799. }
  800. if (!useSceneUBO && this._options.uniforms.indexOf("projection") !== -1) {
  801. effect.setMatrix("projection", scene.getProjectionMatrix());
  802. }
  803. if (!useSceneUBO && this._options.uniforms.indexOf("viewProjection") !== -1) {
  804. effect.setMatrix("viewProjection", scene.getTransformMatrix());
  805. if (this._multiview) {
  806. effect.setMatrix("viewProjectionR", scene._transformMatrixR);
  807. }
  808. }
  809. if (scene.activeCamera && this._options.uniforms.indexOf("cameraPosition") !== -1) {
  810. effect.setVector3("cameraPosition", scene.activeCamera.globalPosition);
  811. }
  812. // Bones
  813. BindBonesParameters(mesh, effect);
  814. // Clip plane
  815. bindClipPlane(effect, this, scene);
  816. // Misc
  817. if (this._useLogarithmicDepth) {
  818. BindLogDepth(storeEffectOnSubMeshes ? subMesh.materialDefines : effect.defines, effect, scene);
  819. }
  820. // Fog
  821. if (mesh) {
  822. BindFogParameters(scene, mesh, effect);
  823. }
  824. let name;
  825. // Texture
  826. for (name in this._textures) {
  827. effect.setTexture(name, this._textures[name]);
  828. }
  829. // Texture arrays
  830. for (name in this._textureArrays) {
  831. effect.setTextureArray(name, this._textureArrays[name]);
  832. }
  833. // External texture
  834. for (name in this._externalTextures) {
  835. effect.setExternalTexture(name, this._externalTextures[name]);
  836. }
  837. // Int
  838. for (name in this._ints) {
  839. effect.setInt(name, this._ints[name]);
  840. }
  841. // UInt
  842. for (name in this._uints) {
  843. effect.setUInt(name, this._uints[name]);
  844. }
  845. // Float
  846. for (name in this._floats) {
  847. effect.setFloat(name, this._floats[name]);
  848. }
  849. // Floats
  850. for (name in this._floatsArrays) {
  851. effect.setArray(name, this._floatsArrays[name]);
  852. }
  853. // Color3
  854. for (name in this._colors3) {
  855. effect.setColor3(name, this._colors3[name]);
  856. }
  857. // Color3Array
  858. for (name in this._colors3Arrays) {
  859. effect.setArray3(name, this._colors3Arrays[name]);
  860. }
  861. // Color4
  862. for (name in this._colors4) {
  863. const color = this._colors4[name];
  864. effect.setFloat4(name, color.r, color.g, color.b, color.a);
  865. }
  866. // Color4Array
  867. for (name in this._colors4Arrays) {
  868. effect.setArray4(name, this._colors4Arrays[name]);
  869. }
  870. // Vector2
  871. for (name in this._vectors2) {
  872. effect.setVector2(name, this._vectors2[name]);
  873. }
  874. // Vector3
  875. for (name in this._vectors3) {
  876. effect.setVector3(name, this._vectors3[name]);
  877. }
  878. // Vector4
  879. for (name in this._vectors4) {
  880. effect.setVector4(name, this._vectors4[name]);
  881. }
  882. // Quaternion
  883. for (name in this._quaternions) {
  884. effect.setQuaternion(name, this._quaternions[name]);
  885. }
  886. // Matrix
  887. for (name in this._matrices) {
  888. effect.setMatrix(name, this._matrices[name]);
  889. }
  890. // MatrixArray
  891. for (name in this._matrixArrays) {
  892. effect.setMatrices(name, this._matrixArrays[name]);
  893. }
  894. // Matrix 3x3
  895. for (name in this._matrices3x3) {
  896. effect.setMatrix3x3(name, this._matrices3x3[name]);
  897. }
  898. // Matrix 2x2
  899. for (name in this._matrices2x2) {
  900. effect.setMatrix2x2(name, this._matrices2x2[name]);
  901. }
  902. // Vector2Array
  903. for (name in this._vectors2Arrays) {
  904. effect.setArray2(name, this._vectors2Arrays[name]);
  905. }
  906. // Vector3Array
  907. for (name in this._vectors3Arrays) {
  908. effect.setArray3(name, this._vectors3Arrays[name]);
  909. }
  910. // Vector4Array
  911. for (name in this._vectors4Arrays) {
  912. effect.setArray4(name, this._vectors4Arrays[name]);
  913. }
  914. // QuaternionArray
  915. for (name in this._quaternionsArrays) {
  916. effect.setArray4(name, this._quaternionsArrays[name]);
  917. }
  918. // Uniform buffers
  919. for (name in this._uniformBuffers) {
  920. const buffer = this._uniformBuffers[name].getBuffer();
  921. if (buffer) {
  922. effect.bindUniformBuffer(buffer, name);
  923. }
  924. }
  925. // Samplers
  926. for (name in this._textureSamplers) {
  927. effect.setTextureSampler(name, this._textureSamplers[name]);
  928. }
  929. // Storage buffers
  930. for (name in this._storageBuffers) {
  931. effect.setStorageBuffer(name, this._storageBuffers[name]);
  932. }
  933. }
  934. if (effect && mesh && (mustRebind || !this.isFrozen)) {
  935. // Morph targets
  936. const manager = mesh.morphTargetManager;
  937. if (manager && manager.numInfluencers > 0) {
  938. BindMorphTargetParameters(mesh, effect);
  939. }
  940. const bvaManager = mesh.bakedVertexAnimationManager;
  941. if (bvaManager && bvaManager.isEnabled) {
  942. const drawWrapper = storeEffectOnSubMeshes ? subMesh._drawWrapper : this._drawWrapper;
  943. mesh.bakedVertexAnimationManager?.bind(effect, !!drawWrapper._wasPreviouslyUsingInstances);
  944. }
  945. }
  946. this._afterBind(mesh, effect, subMesh);
  947. }
  948. /**
  949. * Gets the active textures from the material
  950. * @returns an array of textures
  951. */
  952. getActiveTextures() {
  953. const activeTextures = super.getActiveTextures();
  954. for (const name in this._textures) {
  955. activeTextures.push(this._textures[name]);
  956. }
  957. for (const name in this._textureArrays) {
  958. const array = this._textureArrays[name];
  959. for (let index = 0; index < array.length; index++) {
  960. activeTextures.push(array[index]);
  961. }
  962. }
  963. return activeTextures;
  964. }
  965. /**
  966. * Specifies if the material uses a texture
  967. * @param texture defines the texture to check against the material
  968. * @returns a boolean specifying if the material uses the texture
  969. */
  970. hasTexture(texture) {
  971. if (super.hasTexture(texture)) {
  972. return true;
  973. }
  974. for (const name in this._textures) {
  975. if (this._textures[name] === texture) {
  976. return true;
  977. }
  978. }
  979. for (const name in this._textureArrays) {
  980. const array = this._textureArrays[name];
  981. for (let index = 0; index < array.length; index++) {
  982. if (array[index] === texture) {
  983. return true;
  984. }
  985. }
  986. }
  987. return false;
  988. }
  989. /**
  990. * Makes a duplicate of the material, and gives it a new name
  991. * @param name defines the new name for the duplicated material
  992. * @returns the cloned material
  993. */
  994. clone(name) {
  995. const result = SerializationHelper.Clone(() => new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options, this._storeEffectOnSubMeshes), this);
  996. result.name = name;
  997. result.id = name;
  998. // Shader code path
  999. if (typeof result._shaderPath === "object") {
  1000. result._shaderPath = { ...result._shaderPath };
  1001. }
  1002. // Options
  1003. this._options = { ...this._options };
  1004. Object.keys(this._options).forEach((propName) => {
  1005. const propValue = this._options[propName];
  1006. if (Array.isArray(propValue)) {
  1007. this._options[propName] = propValue.slice(0);
  1008. }
  1009. });
  1010. // Stencil
  1011. this.stencil.copyTo(result.stencil);
  1012. // Texture
  1013. for (const key in this._textures) {
  1014. result.setTexture(key, this._textures[key]);
  1015. }
  1016. // TextureArray
  1017. for (const key in this._textureArrays) {
  1018. result.setTextureArray(key, this._textureArrays[key]);
  1019. }
  1020. // External texture
  1021. for (const key in this._externalTextures) {
  1022. result.setExternalTexture(key, this._externalTextures[key]);
  1023. }
  1024. // Int
  1025. for (const key in this._ints) {
  1026. result.setInt(key, this._ints[key]);
  1027. }
  1028. // UInt
  1029. for (const key in this._uints) {
  1030. result.setUInt(key, this._uints[key]);
  1031. }
  1032. // Float
  1033. for (const key in this._floats) {
  1034. result.setFloat(key, this._floats[key]);
  1035. }
  1036. // Floats
  1037. for (const key in this._floatsArrays) {
  1038. result.setFloats(key, this._floatsArrays[key]);
  1039. }
  1040. // Color3
  1041. for (const key in this._colors3) {
  1042. result.setColor3(key, this._colors3[key]);
  1043. }
  1044. // Color3Array
  1045. for (const key in this._colors3Arrays) {
  1046. result._colors3Arrays[key] = this._colors3Arrays[key];
  1047. }
  1048. // Color4
  1049. for (const key in this._colors4) {
  1050. result.setColor4(key, this._colors4[key]);
  1051. }
  1052. // Color4Array
  1053. for (const key in this._colors4Arrays) {
  1054. result._colors4Arrays[key] = this._colors4Arrays[key];
  1055. }
  1056. // Vector2
  1057. for (const key in this._vectors2) {
  1058. result.setVector2(key, this._vectors2[key]);
  1059. }
  1060. // Vector3
  1061. for (const key in this._vectors3) {
  1062. result.setVector3(key, this._vectors3[key]);
  1063. }
  1064. // Vector4
  1065. for (const key in this._vectors4) {
  1066. result.setVector4(key, this._vectors4[key]);
  1067. }
  1068. // Quaternion
  1069. for (const key in this._quaternions) {
  1070. result.setQuaternion(key, this._quaternions[key]);
  1071. }
  1072. // QuaternionArray
  1073. for (const key in this._quaternionsArrays) {
  1074. result._quaternionsArrays[key] = this._quaternionsArrays[key];
  1075. }
  1076. // Matrix
  1077. for (const key in this._matrices) {
  1078. result.setMatrix(key, this._matrices[key]);
  1079. }
  1080. // MatrixArray
  1081. for (const key in this._matrixArrays) {
  1082. result._matrixArrays[key] = this._matrixArrays[key].slice();
  1083. }
  1084. // Matrix 3x3
  1085. for (const key in this._matrices3x3) {
  1086. result.setMatrix3x3(key, this._matrices3x3[key]);
  1087. }
  1088. // Matrix 2x2
  1089. for (const key in this._matrices2x2) {
  1090. result.setMatrix2x2(key, this._matrices2x2[key]);
  1091. }
  1092. // Vector2Array
  1093. for (const key in this._vectors2Arrays) {
  1094. result.setArray2(key, this._vectors2Arrays[key]);
  1095. }
  1096. // Vector3Array
  1097. for (const key in this._vectors3Arrays) {
  1098. result.setArray3(key, this._vectors3Arrays[key]);
  1099. }
  1100. // Vector4Array
  1101. for (const key in this._vectors4Arrays) {
  1102. result.setArray4(key, this._vectors4Arrays[key]);
  1103. }
  1104. // Uniform buffers
  1105. for (const key in this._uniformBuffers) {
  1106. result.setUniformBuffer(key, this._uniformBuffers[key]);
  1107. }
  1108. // Samplers
  1109. for (const key in this._textureSamplers) {
  1110. result.setTextureSampler(key, this._textureSamplers[key]);
  1111. }
  1112. // Storag buffers
  1113. for (const key in this._storageBuffers) {
  1114. result.setStorageBuffer(key, this._storageBuffers[key]);
  1115. }
  1116. return result;
  1117. }
  1118. /**
  1119. * Disposes the material
  1120. * @param forceDisposeEffect specifies if effects should be forcefully disposed
  1121. * @param forceDisposeTextures specifies if textures should be forcefully disposed
  1122. * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
  1123. */
  1124. dispose(forceDisposeEffect, forceDisposeTextures, notBoundToMesh) {
  1125. if (forceDisposeTextures) {
  1126. let name;
  1127. for (name in this._textures) {
  1128. this._textures[name].dispose();
  1129. }
  1130. for (name in this._textureArrays) {
  1131. const array = this._textureArrays[name];
  1132. for (let index = 0; index < array.length; index++) {
  1133. array[index].dispose();
  1134. }
  1135. }
  1136. }
  1137. this._textures = {};
  1138. super.dispose(forceDisposeEffect, forceDisposeTextures, notBoundToMesh);
  1139. }
  1140. /**
  1141. * Serializes this material in a JSON representation
  1142. * @returns the serialized material object
  1143. */
  1144. serialize() {
  1145. const serializationObject = SerializationHelper.Serialize(this);
  1146. serializationObject.customType = "BABYLON.ShaderMaterial";
  1147. serializationObject.uniqueId = this.uniqueId;
  1148. serializationObject.options = this._options;
  1149. serializationObject.shaderPath = this._shaderPath;
  1150. serializationObject.storeEffectOnSubMeshes = this._storeEffectOnSubMeshes;
  1151. let name;
  1152. // Stencil
  1153. serializationObject.stencil = this.stencil.serialize();
  1154. // Texture
  1155. serializationObject.textures = {};
  1156. for (name in this._textures) {
  1157. serializationObject.textures[name] = this._textures[name].serialize();
  1158. }
  1159. // Texture arrays
  1160. serializationObject.textureArrays = {};
  1161. for (name in this._textureArrays) {
  1162. serializationObject.textureArrays[name] = [];
  1163. const array = this._textureArrays[name];
  1164. for (let index = 0; index < array.length; index++) {
  1165. serializationObject.textureArrays[name].push(array[index].serialize());
  1166. }
  1167. }
  1168. // Int
  1169. serializationObject.ints = {};
  1170. for (name in this._ints) {
  1171. serializationObject.ints[name] = this._ints[name];
  1172. }
  1173. // UInt
  1174. serializationObject.uints = {};
  1175. for (name in this._uints) {
  1176. serializationObject.uints[name] = this._uints[name];
  1177. }
  1178. // Float
  1179. serializationObject.floats = {};
  1180. for (name in this._floats) {
  1181. serializationObject.floats[name] = this._floats[name];
  1182. }
  1183. // Floats
  1184. serializationObject.floatsArrays = {};
  1185. for (name in this._floatsArrays) {
  1186. serializationObject.floatsArrays[name] = this._floatsArrays[name];
  1187. }
  1188. // Color3
  1189. serializationObject.colors3 = {};
  1190. for (name in this._colors3) {
  1191. serializationObject.colors3[name] = this._colors3[name].asArray();
  1192. }
  1193. // Color3 array
  1194. serializationObject.colors3Arrays = {};
  1195. for (name in this._colors3Arrays) {
  1196. serializationObject.colors3Arrays[name] = this._colors3Arrays[name];
  1197. }
  1198. // Color4
  1199. serializationObject.colors4 = {};
  1200. for (name in this._colors4) {
  1201. serializationObject.colors4[name] = this._colors4[name].asArray();
  1202. }
  1203. // Color4 array
  1204. serializationObject.colors4Arrays = {};
  1205. for (name in this._colors4Arrays) {
  1206. serializationObject.colors4Arrays[name] = this._colors4Arrays[name];
  1207. }
  1208. // Vector2
  1209. serializationObject.vectors2 = {};
  1210. for (name in this._vectors2) {
  1211. serializationObject.vectors2[name] = this._vectors2[name].asArray();
  1212. }
  1213. // Vector3
  1214. serializationObject.vectors3 = {};
  1215. for (name in this._vectors3) {
  1216. serializationObject.vectors3[name] = this._vectors3[name].asArray();
  1217. }
  1218. // Vector4
  1219. serializationObject.vectors4 = {};
  1220. for (name in this._vectors4) {
  1221. serializationObject.vectors4[name] = this._vectors4[name].asArray();
  1222. }
  1223. // Quaternion
  1224. serializationObject.quaternions = {};
  1225. for (name in this._quaternions) {
  1226. serializationObject.quaternions[name] = this._quaternions[name].asArray();
  1227. }
  1228. // Matrix
  1229. serializationObject.matrices = {};
  1230. for (name in this._matrices) {
  1231. serializationObject.matrices[name] = this._matrices[name].asArray();
  1232. }
  1233. // MatrixArray
  1234. serializationObject.matrixArray = {};
  1235. for (name in this._matrixArrays) {
  1236. serializationObject.matrixArray[name] = this._matrixArrays[name];
  1237. }
  1238. // Matrix 3x3
  1239. serializationObject.matrices3x3 = {};
  1240. for (name in this._matrices3x3) {
  1241. serializationObject.matrices3x3[name] = this._matrices3x3[name];
  1242. }
  1243. // Matrix 2x2
  1244. serializationObject.matrices2x2 = {};
  1245. for (name in this._matrices2x2) {
  1246. serializationObject.matrices2x2[name] = this._matrices2x2[name];
  1247. }
  1248. // Vector2Array
  1249. serializationObject.vectors2Arrays = {};
  1250. for (name in this._vectors2Arrays) {
  1251. serializationObject.vectors2Arrays[name] = this._vectors2Arrays[name];
  1252. }
  1253. // Vector3Array
  1254. serializationObject.vectors3Arrays = {};
  1255. for (name in this._vectors3Arrays) {
  1256. serializationObject.vectors3Arrays[name] = this._vectors3Arrays[name];
  1257. }
  1258. // Vector4Array
  1259. serializationObject.vectors4Arrays = {};
  1260. for (name in this._vectors4Arrays) {
  1261. serializationObject.vectors4Arrays[name] = this._vectors4Arrays[name];
  1262. }
  1263. // QuaternionArray
  1264. serializationObject.quaternionsArrays = {};
  1265. for (name in this._quaternionsArrays) {
  1266. serializationObject.quaternionsArrays[name] = this._quaternionsArrays[name];
  1267. }
  1268. return serializationObject;
  1269. }
  1270. /**
  1271. * Creates a shader material from parsed shader material data
  1272. * @param source defines the JSON representation of the material
  1273. * @param scene defines the hosting scene
  1274. * @param rootUrl defines the root URL to use to load textures and relative dependencies
  1275. * @returns a new material
  1276. */
  1277. static Parse(source, scene, rootUrl) {
  1278. const material = SerializationHelper.Parse(() => new ShaderMaterial(source.name, scene, source.shaderPath, source.options, source.storeEffectOnSubMeshes), source, scene, rootUrl);
  1279. let name;
  1280. // Stencil
  1281. if (source.stencil) {
  1282. material.stencil.parse(source.stencil, scene, rootUrl);
  1283. }
  1284. // Texture
  1285. for (name in source.textures) {
  1286. material.setTexture(name, Texture.Parse(source.textures[name], scene, rootUrl));
  1287. }
  1288. // Texture arrays
  1289. for (name in source.textureArrays) {
  1290. const array = source.textureArrays[name];
  1291. const textureArray = [];
  1292. for (let index = 0; index < array.length; index++) {
  1293. textureArray.push(Texture.Parse(array[index], scene, rootUrl));
  1294. }
  1295. material.setTextureArray(name, textureArray);
  1296. }
  1297. // Int
  1298. for (name in source.ints) {
  1299. material.setInt(name, source.ints[name]);
  1300. }
  1301. // UInt
  1302. for (name in source.uints) {
  1303. material.setUInt(name, source.uints[name]);
  1304. }
  1305. // Float
  1306. for (name in source.floats) {
  1307. material.setFloat(name, source.floats[name]);
  1308. }
  1309. // Floats
  1310. for (name in source.floatsArrays) {
  1311. material.setFloats(name, source.floatsArrays[name]);
  1312. }
  1313. // Color3
  1314. for (name in source.colors3) {
  1315. material.setColor3(name, Color3.FromArray(source.colors3[name]));
  1316. }
  1317. // Color3 arrays
  1318. for (name in source.colors3Arrays) {
  1319. const colors = source.colors3Arrays[name]
  1320. .reduce((arr, num, i) => {
  1321. if (i % 3 === 0) {
  1322. arr.push([num]);
  1323. }
  1324. else {
  1325. arr[arr.length - 1].push(num);
  1326. }
  1327. return arr;
  1328. }, [])
  1329. .map((color) => Color3.FromArray(color));
  1330. material.setColor3Array(name, colors);
  1331. }
  1332. // Color4
  1333. for (name in source.colors4) {
  1334. material.setColor4(name, Color4.FromArray(source.colors4[name]));
  1335. }
  1336. // Color4 arrays
  1337. for (name in source.colors4Arrays) {
  1338. const colors = source.colors4Arrays[name]
  1339. .reduce((arr, num, i) => {
  1340. if (i % 4 === 0) {
  1341. arr.push([num]);
  1342. }
  1343. else {
  1344. arr[arr.length - 1].push(num);
  1345. }
  1346. return arr;
  1347. }, [])
  1348. .map((color) => Color4.FromArray(color));
  1349. material.setColor4Array(name, colors);
  1350. }
  1351. // Vector2
  1352. for (name in source.vectors2) {
  1353. material.setVector2(name, Vector2.FromArray(source.vectors2[name]));
  1354. }
  1355. // Vector3
  1356. for (name in source.vectors3) {
  1357. material.setVector3(name, Vector3.FromArray(source.vectors3[name]));
  1358. }
  1359. // Vector4
  1360. for (name in source.vectors4) {
  1361. material.setVector4(name, Vector4.FromArray(source.vectors4[name]));
  1362. }
  1363. // Quaternion
  1364. for (name in source.quaternions) {
  1365. material.setQuaternion(name, Quaternion.FromArray(source.quaternions[name]));
  1366. }
  1367. // Matrix
  1368. for (name in source.matrices) {
  1369. material.setMatrix(name, Matrix.FromArray(source.matrices[name]));
  1370. }
  1371. // MatrixArray
  1372. for (name in source.matrixArray) {
  1373. material._matrixArrays[name] = new Float32Array(source.matrixArray[name]);
  1374. }
  1375. // Matrix 3x3
  1376. for (name in source.matrices3x3) {
  1377. material.setMatrix3x3(name, source.matrices3x3[name]);
  1378. }
  1379. // Matrix 2x2
  1380. for (name in source.matrices2x2) {
  1381. material.setMatrix2x2(name, source.matrices2x2[name]);
  1382. }
  1383. // Vector2Array
  1384. for (name in source.vectors2Arrays) {
  1385. material.setArray2(name, source.vectors2Arrays[name]);
  1386. }
  1387. // Vector3Array
  1388. for (name in source.vectors3Arrays) {
  1389. material.setArray3(name, source.vectors3Arrays[name]);
  1390. }
  1391. // Vector4Array
  1392. for (name in source.vectors4Arrays) {
  1393. material.setArray4(name, source.vectors4Arrays[name]);
  1394. }
  1395. // QuaternionArray
  1396. for (name in source.quaternionsArrays) {
  1397. material.setArray4(name, source.quaternionsArrays[name]);
  1398. }
  1399. return material;
  1400. }
  1401. /**
  1402. * Creates a new ShaderMaterial from a snippet saved in a remote file
  1403. * @param name defines the name of the ShaderMaterial to create (can be null or empty to use the one from the json data)
  1404. * @param url defines the url to load from
  1405. * @param scene defines the hosting scene
  1406. * @param rootUrl defines the root URL to use to load textures and relative dependencies
  1407. * @returns a promise that will resolve to the new ShaderMaterial
  1408. */
  1409. static ParseFromFileAsync(name, url, scene, rootUrl = "") {
  1410. return new Promise((resolve, reject) => {
  1411. const request = new WebRequest();
  1412. request.addEventListener("readystatechange", () => {
  1413. if (request.readyState == 4) {
  1414. if (request.status == 200) {
  1415. const serializationObject = JSON.parse(request.responseText);
  1416. const output = this.Parse(serializationObject, scene || EngineStore.LastCreatedScene, rootUrl);
  1417. if (name) {
  1418. output.name = name;
  1419. }
  1420. resolve(output);
  1421. }
  1422. else {
  1423. reject("Unable to load the ShaderMaterial");
  1424. }
  1425. }
  1426. });
  1427. request.open("GET", url);
  1428. request.send();
  1429. });
  1430. }
  1431. /**
  1432. * Creates a ShaderMaterial from a snippet saved by the Inspector
  1433. * @param snippetId defines the snippet to load
  1434. * @param scene defines the hosting scene
  1435. * @param rootUrl defines the root URL to use to load textures and relative dependencies
  1436. * @returns a promise that will resolve to the new ShaderMaterial
  1437. */
  1438. static ParseFromSnippetAsync(snippetId, scene, rootUrl = "") {
  1439. return new Promise((resolve, reject) => {
  1440. const request = new WebRequest();
  1441. request.addEventListener("readystatechange", () => {
  1442. if (request.readyState == 4) {
  1443. if (request.status == 200) {
  1444. const snippet = JSON.parse(JSON.parse(request.responseText).jsonPayload);
  1445. const serializationObject = JSON.parse(snippet.shaderMaterial);
  1446. const output = this.Parse(serializationObject, scene || EngineStore.LastCreatedScene, rootUrl);
  1447. output.snippetId = snippetId;
  1448. resolve(output);
  1449. }
  1450. else {
  1451. reject("Unable to load the snippet " + snippetId);
  1452. }
  1453. }
  1454. });
  1455. request.open("GET", this.SnippetUrl + "/" + snippetId.replace(/#/g, "/"));
  1456. request.send();
  1457. });
  1458. }
  1459. }
  1460. /** Define the Url to load snippets */
  1461. ShaderMaterial.SnippetUrl = `https://snippet.babylonjs.com`;
  1462. /**
  1463. * Creates a ShaderMaterial from a snippet saved by the Inspector
  1464. * @deprecated Please use ParseFromSnippetAsync instead
  1465. * @param snippetId defines the snippet to load
  1466. * @param scene defines the hosting scene
  1467. * @param rootUrl defines the root URL to use to load textures and relative dependencies
  1468. * @returns a promise that will resolve to the new ShaderMaterial
  1469. */
  1470. ShaderMaterial.CreateFromSnippetAsync = ShaderMaterial.ParseFromSnippetAsync;
  1471. RegisterClass("BABYLON.ShaderMaterial", ShaderMaterial);
  1472. //# sourceMappingURL=shaderMaterial.js.map