shaderMaterial.ts 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. import { SerializationHelper } from "../Misc/decorators";
  2. import { Scene } from "../scene";
  3. import { Matrix, Vector3, Vector2, Vector4 } from "../Maths/math.vector";
  4. import { AbstractMesh } from "../Meshes/abstractMesh";
  5. import { Mesh } from "../Meshes/mesh";
  6. import { BaseSubMesh } from "../Meshes/subMesh";
  7. import { VertexBuffer } from "../Meshes/buffer";
  8. import { BaseTexture } from "../Materials/Textures/baseTexture";
  9. import { Texture } from "../Materials/Textures/texture";
  10. import { MaterialHelper } from "./materialHelper";
  11. import { IEffectCreationOptions } from "./effect";
  12. import { Material } from "./material";
  13. import { _TypeStore } from '../Misc/typeStore';
  14. import { Color3, Color4 } from '../Maths/math.color';
  15. import { EffectFallbacks } from './effectFallbacks';
  16. /**
  17. * Defines the options associated with the creation of a shader material.
  18. */
  19. export interface IShaderMaterialOptions {
  20. /**
  21. * Does the material work in alpha blend mode
  22. */
  23. needAlphaBlending: boolean;
  24. /**
  25. * Does the material work in alpha test mode
  26. */
  27. needAlphaTesting: boolean;
  28. /**
  29. * The list of attribute names used in the shader
  30. */
  31. attributes: string[];
  32. /**
  33. * The list of unifrom names used in the shader
  34. */
  35. uniforms: string[];
  36. /**
  37. * The list of UBO names used in the shader
  38. */
  39. uniformBuffers: string[];
  40. /**
  41. * The list of sampler names used in the shader
  42. */
  43. samplers: string[];
  44. /**
  45. * The list of defines used in the shader
  46. */
  47. defines: string[];
  48. }
  49. /**
  50. * 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.
  51. *
  52. * This returned material effects how the mesh will look based on the code in the shaders.
  53. *
  54. * @see http://doc.babylonjs.com/how_to/shader_material
  55. */
  56. export class ShaderMaterial extends Material {
  57. private _shaderPath: any;
  58. private _options: IShaderMaterialOptions;
  59. private _textures: { [name: string]: Texture } = {};
  60. private _textureArrays: { [name: string]: Texture[] } = {};
  61. private _floats: { [name: string]: number } = {};
  62. private _ints: { [name: string]: number } = {};
  63. private _floatsArrays: { [name: string]: number[] } = {};
  64. private _colors3: { [name: string]: Color3 } = {};
  65. private _colors3Arrays: { [name: string]: number[] } = {};
  66. private _colors4: { [name: string]: Color4 } = {};
  67. private _colors4Arrays: { [name: string]: number[] } = {};
  68. private _vectors2: { [name: string]: Vector2 } = {};
  69. private _vectors3: { [name: string]: Vector3 } = {};
  70. private _vectors4: { [name: string]: Vector4 } = {};
  71. private _matrices: { [name: string]: Matrix } = {};
  72. private _matrixArrays: { [name: string]: Float32Array } = {};
  73. private _matrices3x3: { [name: string]: Float32Array } = {};
  74. private _matrices2x2: { [name: string]: Float32Array } = {};
  75. private _vectors2Arrays: { [name: string]: number[] } = {};
  76. private _vectors3Arrays: { [name: string]: number[] } = {};
  77. private _vectors4Arrays: { [name: string]: number[] } = {};
  78. private _cachedWorldViewMatrix = new Matrix();
  79. private _cachedWorldViewProjectionMatrix = new Matrix();
  80. private _renderId: number;
  81. /**
  82. * Instantiate a new shader material.
  83. * 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.
  84. * This returned material effects how the mesh will look based on the code in the shaders.
  85. * @see http://doc.babylonjs.com/how_to/shader_material
  86. * @param name Define the name of the material in the scene
  87. * @param scene Define the scene the material belongs to
  88. * @param shaderPath Defines the route to the shader code in one of three ways:
  89. * * object: { vertex: "custom", fragment: "custom" }, used with Effect.ShadersStore["customVertexShader"] and Effect.ShadersStore["customFragmentShader"]
  90. * * object: { vertexElement: "vertexShaderCode", fragmentElement: "fragmentShaderCode" }, used with shader code in script tags
  91. * * object: { vertexSource: "vertex shader code string", fragmentSource: "fragment shader code string" } using with strings containing the shaders code
  92. * * string: "./COMMON_NAME", used with external files COMMON_NAME.vertex.fx and COMMON_NAME.fragment.fx in index.html folder.
  93. * @param options Define the options used to create the shader
  94. */
  95. constructor(name: string, scene: Scene, shaderPath: any, options: Partial<IShaderMaterialOptions> = {}) {
  96. super(name, scene);
  97. this._shaderPath = shaderPath;
  98. this._options = {
  99. needAlphaBlending: false,
  100. needAlphaTesting: false,
  101. attributes: ["position", "normal", "uv"],
  102. uniforms: ["worldViewProjection"],
  103. uniformBuffers: [],
  104. samplers: [],
  105. defines: [],
  106. ...options
  107. };
  108. }
  109. /**
  110. * Gets the options used to compile the shader.
  111. * They can be modified to trigger a new compilation
  112. */
  113. public get options(): IShaderMaterialOptions {
  114. return this._options;
  115. }
  116. /**
  117. * Gets the current class name of the material e.g. "ShaderMaterial"
  118. * Mainly use in serialization.
  119. * @returns the class name
  120. */
  121. public getClassName(): string {
  122. return "ShaderMaterial";
  123. }
  124. /**
  125. * Specifies if the material will require alpha blending
  126. * @returns a boolean specifying if alpha blending is needed
  127. */
  128. public needAlphaBlending(): boolean {
  129. return (this.alpha < 1.0) || this._options.needAlphaBlending;
  130. }
  131. /**
  132. * Specifies if this material should be rendered in alpha test mode
  133. * @returns a boolean specifying if an alpha test is needed.
  134. */
  135. public needAlphaTesting(): boolean {
  136. return this._options.needAlphaTesting;
  137. }
  138. private _checkUniform(uniformName: string): void {
  139. if (this._options.uniforms.indexOf(uniformName) === -1) {
  140. this._options.uniforms.push(uniformName);
  141. }
  142. }
  143. /**
  144. * Set a texture in the shader.
  145. * @param name Define the name of the uniform samplers as defined in the shader
  146. * @param texture Define the texture to bind to this sampler
  147. * @return the material itself allowing "fluent" like uniform updates
  148. */
  149. public setTexture(name: string, texture: Texture): ShaderMaterial {
  150. if (this._options.samplers.indexOf(name) === -1) {
  151. this._options.samplers.push(name);
  152. }
  153. this._textures[name] = texture;
  154. return this;
  155. }
  156. /**
  157. * Set a texture array in the shader.
  158. * @param name Define the name of the uniform sampler array as defined in the shader
  159. * @param textures Define the list of textures to bind to this sampler
  160. * @return the material itself allowing "fluent" like uniform updates
  161. */
  162. public setTextureArray(name: string, textures: Texture[]): ShaderMaterial {
  163. if (this._options.samplers.indexOf(name) === -1) {
  164. this._options.samplers.push(name);
  165. }
  166. this._checkUniform(name);
  167. this._textureArrays[name] = textures;
  168. return this;
  169. }
  170. /**
  171. * Set a float in the shader.
  172. * @param name Define the name of the uniform as defined in the shader
  173. * @param value Define the value to give to the uniform
  174. * @return the material itself allowing "fluent" like uniform updates
  175. */
  176. public setFloat(name: string, value: number): ShaderMaterial {
  177. this._checkUniform(name);
  178. this._floats[name] = value;
  179. return this;
  180. }
  181. /**
  182. * Set a int in the shader.
  183. * @param name Define the name of the uniform as defined in the shader
  184. * @param value Define the value to give to the uniform
  185. * @return the material itself allowing "fluent" like uniform updates
  186. */
  187. public setInt(name: string, value: number): ShaderMaterial {
  188. this._checkUniform(name);
  189. this._ints[name] = value;
  190. return this;
  191. }
  192. /**
  193. * Set an array of floats in the shader.
  194. * @param name Define the name of the uniform as defined in the shader
  195. * @param value Define the value to give to the uniform
  196. * @return the material itself allowing "fluent" like uniform updates
  197. */
  198. public setFloats(name: string, value: number[]): ShaderMaterial {
  199. this._checkUniform(name);
  200. this._floatsArrays[name] = value;
  201. return this;
  202. }
  203. /**
  204. * Set a vec3 in the shader from a Color3.
  205. * @param name Define the name of the uniform as defined in the shader
  206. * @param value Define the value to give to the uniform
  207. * @return the material itself allowing "fluent" like uniform updates
  208. */
  209. public setColor3(name: string, value: Color3): ShaderMaterial {
  210. this._checkUniform(name);
  211. this._colors3[name] = value;
  212. return this;
  213. }
  214. /**
  215. * Set a vec3 array in the shader from a Color3 array.
  216. * @param name Define the name of the uniform as defined in the shader
  217. * @param value Define the value to give to the uniform
  218. * @return the material itself allowing "fluent" like uniform updates
  219. */
  220. public setColor3Array(name: string, value: Color3[]): ShaderMaterial {
  221. this._checkUniform(name);
  222. this._colors3Arrays[name] = value.reduce((arr, color) => {
  223. color.toArray(arr, arr.length);
  224. return arr;
  225. }, []);
  226. return this;
  227. }
  228. /**
  229. * Set a vec4 in the shader from a Color4.
  230. * @param name Define the name of the uniform as defined in the shader
  231. * @param value Define the value to give to the uniform
  232. * @return the material itself allowing "fluent" like uniform updates
  233. */
  234. public setColor4(name: string, value: Color4): ShaderMaterial {
  235. this._checkUniform(name);
  236. this._colors4[name] = value;
  237. return this;
  238. }
  239. /**
  240. * Set a vec4 array in the shader from a Color4 array.
  241. * @param name Define the name of the uniform as defined in the shader
  242. * @param value Define the value to give to the uniform
  243. * @return the material itself allowing "fluent" like uniform updates
  244. */
  245. public setColor4Array(name: string, value: Color4[]): ShaderMaterial {
  246. this._checkUniform(name);
  247. this._colors4Arrays[name] = value.reduce((arr, color) => {
  248. color.toArray(arr, arr.length);
  249. return arr;
  250. }, []);
  251. return this;
  252. }
  253. /**
  254. * Set a vec2 in the shader from a Vector2.
  255. * @param name Define the name of the uniform as defined in the shader
  256. * @param value Define the value to give to the uniform
  257. * @return the material itself allowing "fluent" like uniform updates
  258. */
  259. public setVector2(name: string, value: Vector2): ShaderMaterial {
  260. this._checkUniform(name);
  261. this._vectors2[name] = value;
  262. return this;
  263. }
  264. /**
  265. * Set a vec3 in the shader from a Vector3.
  266. * @param name Define the name of the uniform as defined in the shader
  267. * @param value Define the value to give to the uniform
  268. * @return the material itself allowing "fluent" like uniform updates
  269. */
  270. public setVector3(name: string, value: Vector3): ShaderMaterial {
  271. this._checkUniform(name);
  272. this._vectors3[name] = value;
  273. return this;
  274. }
  275. /**
  276. * Set a vec4 in the shader from a Vector4.
  277. * @param name Define the name of the uniform as defined in the shader
  278. * @param value Define the value to give to the uniform
  279. * @return the material itself allowing "fluent" like uniform updates
  280. */
  281. public setVector4(name: string, value: Vector4): ShaderMaterial {
  282. this._checkUniform(name);
  283. this._vectors4[name] = value;
  284. return this;
  285. }
  286. /**
  287. * Set a mat4 in the shader from a Matrix.
  288. * @param name Define the name of the uniform as defined in the shader
  289. * @param value Define the value to give to the uniform
  290. * @return the material itself allowing "fluent" like uniform updates
  291. */
  292. public setMatrix(name: string, value: Matrix): ShaderMaterial {
  293. this._checkUniform(name);
  294. this._matrices[name] = value;
  295. return this;
  296. }
  297. /**
  298. * Set a float32Array in the shader from a matrix array.
  299. * @param name Define the name of the uniform as defined in the shader
  300. * @param value Define the value to give to the uniform
  301. * @return the material itself allowing "fluent" like uniform updates
  302. */
  303. public setMatrices(name: string, value: Matrix[]): ShaderMaterial {
  304. this._checkUniform(name);
  305. let float32Array = new Float32Array(value.length * 16);
  306. for (var index = 0; index < value.length; index++) {
  307. let matrix = value[index];
  308. matrix.copyToArray(float32Array, index * 16);
  309. }
  310. this._matrixArrays[name] = float32Array;
  311. return this;
  312. }
  313. /**
  314. * Set a mat3 in the shader from a Float32Array.
  315. * @param name Define the name of the uniform as defined in the shader
  316. * @param value Define the value to give to the uniform
  317. * @return the material itself allowing "fluent" like uniform updates
  318. */
  319. public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
  320. this._checkUniform(name);
  321. this._matrices3x3[name] = value;
  322. return this;
  323. }
  324. /**
  325. * Set a mat2 in the shader from a Float32Array.
  326. * @param name Define the name of the uniform as defined in the shader
  327. * @param value Define the value to give to the uniform
  328. * @return the material itself allowing "fluent" like uniform updates
  329. */
  330. public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
  331. this._checkUniform(name);
  332. this._matrices2x2[name] = value;
  333. return this;
  334. }
  335. /**
  336. * Set a vec2 array in the shader from a number array.
  337. * @param name Define the name of the uniform as defined in the shader
  338. * @param value Define the value to give to the uniform
  339. * @return the material itself allowing "fluent" like uniform updates
  340. */
  341. public setArray2(name: string, value: number[]): ShaderMaterial {
  342. this._checkUniform(name);
  343. this._vectors2Arrays[name] = value;
  344. return this;
  345. }
  346. /**
  347. * Set a vec3 array in the shader from a number array.
  348. * @param name Define the name of the uniform as defined in the shader
  349. * @param value Define the value to give to the uniform
  350. * @return the material itself allowing "fluent" like uniform updates
  351. */
  352. public setArray3(name: string, value: number[]): ShaderMaterial {
  353. this._checkUniform(name);
  354. this._vectors3Arrays[name] = value;
  355. return this;
  356. }
  357. /**
  358. * Set a vec4 array in the shader from a number array.
  359. * @param name Define the name of the uniform as defined in the shader
  360. * @param value Define the value to give to the uniform
  361. * @return the material itself allowing "fluent" like uniform updates
  362. */
  363. public setArray4(name: string, value: number[]): ShaderMaterial {
  364. this._checkUniform(name);
  365. this._vectors4Arrays[name] = value;
  366. return this;
  367. }
  368. private _checkCache(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  369. if (!mesh) {
  370. return true;
  371. }
  372. if (this._effect && (this._effect.defines.indexOf("#define INSTANCES") !== -1) !== useInstances) {
  373. return false;
  374. }
  375. return true;
  376. }
  377. /**
  378. * Specifies that the submesh is ready to be used
  379. * @param mesh defines the mesh to check
  380. * @param subMesh defines which submesh to check
  381. * @param useInstances specifies that instances should be used
  382. * @returns a boolean indicating that the submesh is ready or not
  383. */
  384. public isReadyForSubMesh(mesh: AbstractMesh, subMesh: BaseSubMesh, useInstances?: boolean): boolean {
  385. return this.isReady(mesh, useInstances);
  386. }
  387. /**
  388. * Checks if the material is ready to render the requested mesh
  389. * @param mesh Define the mesh to render
  390. * @param useInstances Define whether or not the material is used with instances
  391. * @returns true if ready, otherwise false
  392. */
  393. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  394. var scene = this.getScene();
  395. var engine = scene.getEngine();
  396. if (!this.checkReadyOnEveryCall) {
  397. if (this._renderId === scene.getRenderId()) {
  398. if (this._checkCache(mesh, useInstances)) {
  399. return true;
  400. }
  401. }
  402. }
  403. // Instances
  404. var defines = [];
  405. var attribs = [];
  406. var fallbacks = new EffectFallbacks();
  407. for (var index = 0; index < this._options.defines.length; index++) {
  408. defines.push(this._options.defines[index]);
  409. }
  410. for (var index = 0; index < this._options.attributes.length; index++) {
  411. attribs.push(this._options.attributes[index]);
  412. }
  413. if (mesh && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
  414. attribs.push(VertexBuffer.ColorKind);
  415. defines.push("#define VERTEXCOLOR");
  416. }
  417. if (useInstances) {
  418. defines.push("#define INSTANCES");
  419. MaterialHelper.PushAttributesForInstances(attribs);
  420. }
  421. // Bones
  422. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
  423. attribs.push(VertexBuffer.MatricesIndicesKind);
  424. attribs.push(VertexBuffer.MatricesWeightsKind);
  425. if (mesh.numBoneInfluencers > 4) {
  426. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  427. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  428. }
  429. const skeleton = mesh.skeleton;
  430. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  431. fallbacks.addCPUSkinningFallback(0, mesh);
  432. if (skeleton.isUsingTextureForMatrices) {
  433. defines.push("#define BONETEXTURE");
  434. if (this._options.uniforms.indexOf("boneTextureWidth") === -1) {
  435. this._options.uniforms.push("boneTextureWidth");
  436. }
  437. if (this._options.samplers.indexOf("boneSampler") === -1) {
  438. this._options.samplers.push("boneSampler");
  439. }
  440. } else {
  441. defines.push("#define BonesPerMesh " + (skeleton.bones.length + 1));
  442. if (this._options.uniforms.indexOf("mBones") === -1) {
  443. this._options.uniforms.push("mBones");
  444. }
  445. }
  446. } else {
  447. defines.push("#define NUM_BONE_INFLUENCERS 0");
  448. }
  449. // Textures
  450. for (var name in this._textures) {
  451. if (!this._textures[name].isReady()) {
  452. return false;
  453. }
  454. }
  455. // Alpha test
  456. if (mesh && this._shouldTurnAlphaTestOn(mesh)) {
  457. defines.push("#define ALPHATEST");
  458. }
  459. var previousEffect = this._effect;
  460. var join = defines.join("\n");
  461. this._effect = engine.createEffect(this._shaderPath, <IEffectCreationOptions>{
  462. attributes: attribs,
  463. uniformsNames: this._options.uniforms,
  464. uniformBuffersNames: this._options.uniformBuffers,
  465. samplers: this._options.samplers,
  466. defines: join,
  467. fallbacks: fallbacks,
  468. onCompiled: this.onCompiled,
  469. onError: this.onError
  470. }, engine);
  471. if (!this._effect.isReady()) {
  472. return false;
  473. }
  474. if (previousEffect !== this._effect) {
  475. scene.resetCachedMaterial();
  476. }
  477. this._renderId = scene.getRenderId();
  478. return true;
  479. }
  480. /**
  481. * Binds the world matrix to the material
  482. * @param world defines the world transformation matrix
  483. */
  484. public bindOnlyWorldMatrix(world: Matrix): void {
  485. var scene = this.getScene();
  486. if (!this._effect) {
  487. return;
  488. }
  489. if (this._options.uniforms.indexOf("world") !== -1) {
  490. this._effect.setMatrix("world", world);
  491. }
  492. if (this._options.uniforms.indexOf("worldView") !== -1) {
  493. world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
  494. this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
  495. }
  496. if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
  497. world.multiplyToRef(scene.getTransformMatrix(), this._cachedWorldViewProjectionMatrix);
  498. this._effect.setMatrix("worldViewProjection", this._cachedWorldViewProjectionMatrix);
  499. }
  500. }
  501. /**
  502. * Binds the material to the mesh
  503. * @param world defines the world transformation matrix
  504. * @param mesh defines the mesh to bind the material to
  505. */
  506. public bind(world: Matrix, mesh?: Mesh): void {
  507. // Std values
  508. this.bindOnlyWorldMatrix(world);
  509. if (this._effect && this.getScene().getCachedMaterial() !== this) {
  510. if (this._options.uniforms.indexOf("view") !== -1) {
  511. this._effect.setMatrix("view", this.getScene().getViewMatrix());
  512. }
  513. if (this._options.uniforms.indexOf("projection") !== -1) {
  514. this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
  515. }
  516. if (this._options.uniforms.indexOf("viewProjection") !== -1) {
  517. this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  518. }
  519. // Bones
  520. MaterialHelper.BindBonesParameters(mesh, this._effect);
  521. var name: string;
  522. // Texture
  523. for (name in this._textures) {
  524. this._effect.setTexture(name, this._textures[name]);
  525. }
  526. // Texture arrays
  527. for (name in this._textureArrays) {
  528. this._effect.setTextureArray(name, this._textureArrays[name]);
  529. }
  530. // Int
  531. for (name in this._ints) {
  532. this._effect.setInt(name, this._ints[name]);
  533. }
  534. // Float
  535. for (name in this._floats) {
  536. this._effect.setFloat(name, this._floats[name]);
  537. }
  538. // Floats
  539. for (name in this._floatsArrays) {
  540. this._effect.setArray(name, this._floatsArrays[name]);
  541. }
  542. // Color3
  543. for (name in this._colors3) {
  544. this._effect.setColor3(name, this._colors3[name]);
  545. }
  546. // Color3Array
  547. for (name in this._colors3Arrays) {
  548. this._effect.setArray3(name, this._colors3Arrays[name]);
  549. }
  550. // Color4
  551. for (name in this._colors4) {
  552. var color = this._colors4[name];
  553. this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
  554. }
  555. // Color4Array
  556. for (name in this._colors4Arrays) {
  557. this._effect.setArray4(name, this._colors4Arrays[name]);
  558. }
  559. // Vector2
  560. for (name in this._vectors2) {
  561. this._effect.setVector2(name, this._vectors2[name]);
  562. }
  563. // Vector3
  564. for (name in this._vectors3) {
  565. this._effect.setVector3(name, this._vectors3[name]);
  566. }
  567. // Vector4
  568. for (name in this._vectors4) {
  569. this._effect.setVector4(name, this._vectors4[name]);
  570. }
  571. // Matrix
  572. for (name in this._matrices) {
  573. this._effect.setMatrix(name, this._matrices[name]);
  574. }
  575. // MatrixArray
  576. for (name in this._matrixArrays) {
  577. this._effect.setMatrices(name, this._matrixArrays[name]);
  578. }
  579. // Matrix 3x3
  580. for (name in this._matrices3x3) {
  581. this._effect.setMatrix3x3(name, this._matrices3x3[name]);
  582. }
  583. // Matrix 2x2
  584. for (name in this._matrices2x2) {
  585. this._effect.setMatrix2x2(name, this._matrices2x2[name]);
  586. }
  587. // Vector2Array
  588. for (name in this._vectors2Arrays) {
  589. this._effect.setArray2(name, this._vectors2Arrays[name]);
  590. }
  591. // Vector3Array
  592. for (name in this._vectors3Arrays) {
  593. this._effect.setArray3(name, this._vectors3Arrays[name]);
  594. }
  595. // Vector4Array
  596. for (name in this._vectors4Arrays) {
  597. this._effect.setArray4(name, this._vectors4Arrays[name]);
  598. }
  599. }
  600. this._afterBind(mesh);
  601. }
  602. /**
  603. * Gets the active textures from the material
  604. * @returns an array of textures
  605. */
  606. public getActiveTextures(): BaseTexture[] {
  607. var activeTextures = super.getActiveTextures();
  608. for (var name in this._textures) {
  609. activeTextures.push(this._textures[name]);
  610. }
  611. for (var name in this._textureArrays) {
  612. var array = this._textureArrays[name];
  613. for (var index = 0; index < array.length; index++) {
  614. activeTextures.push(array[index]);
  615. }
  616. }
  617. return activeTextures;
  618. }
  619. /**
  620. * Specifies if the material uses a texture
  621. * @param texture defines the texture to check against the material
  622. * @returns a boolean specifying if the material uses the texture
  623. */
  624. public hasTexture(texture: BaseTexture): boolean {
  625. if (super.hasTexture(texture)) {
  626. return true;
  627. }
  628. for (var name in this._textures) {
  629. if (this._textures[name] === texture) {
  630. return true;
  631. }
  632. }
  633. for (var name in this._textureArrays) {
  634. var array = this._textureArrays[name];
  635. for (var index = 0; index < array.length; index++) {
  636. if (array[index] === texture) {
  637. return true;
  638. }
  639. }
  640. }
  641. return false;
  642. }
  643. /**
  644. * Makes a duplicate of the material, and gives it a new name
  645. * @param name defines the new name for the duplicated material
  646. * @returns the cloned material
  647. */
  648. public clone(name: string): ShaderMaterial {
  649. var result = SerializationHelper.Clone(() => new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options), this);
  650. result.name = name;
  651. result.id = name;
  652. // Texture
  653. for (var key in this._textures) {
  654. result.setTexture(key, this._textures[key]);
  655. }
  656. // Float
  657. for (var key in this._floats) {
  658. result.setFloat(key, this._floats[key]);
  659. }
  660. // Floats
  661. for (var key in this._floatsArrays) {
  662. result.setFloats(key, this._floatsArrays[key]);
  663. }
  664. // Color3
  665. for (var key in this._colors3) {
  666. result.setColor3(key, this._colors3[key]);
  667. }
  668. // Color4
  669. for (var key in this._colors4) {
  670. result.setColor4(key, this._colors4[key]);
  671. }
  672. // Vector2
  673. for (var key in this._vectors2) {
  674. result.setVector2(key, this._vectors2[key]);
  675. }
  676. // Vector3
  677. for (var key in this._vectors3) {
  678. result.setVector3(key, this._vectors3[key]);
  679. }
  680. // Vector4
  681. for (var key in this._vectors4) {
  682. result.setVector4(key, this._vectors4[key]);
  683. }
  684. // Matrix
  685. for (var key in this._matrices) {
  686. result.setMatrix(key, this._matrices[key]);
  687. }
  688. // Matrix 3x3
  689. for (var key in this._matrices3x3) {
  690. result.setMatrix3x3(key, this._matrices3x3[key]);
  691. }
  692. // Matrix 2x2
  693. for (var key in this._matrices2x2) {
  694. result.setMatrix2x2(key, this._matrices2x2[key]);
  695. }
  696. return result;
  697. }
  698. /**
  699. * Disposes the material
  700. * @param forceDisposeEffect specifies if effects should be forcefully disposed
  701. * @param forceDisposeTextures specifies if textures should be forcefully disposed
  702. * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
  703. */
  704. public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void {
  705. if (forceDisposeTextures) {
  706. var name: string;
  707. for (name in this._textures) {
  708. this._textures[name].dispose();
  709. }
  710. for (name in this._textureArrays) {
  711. var array = this._textureArrays[name];
  712. for (var index = 0; index < array.length; index++) {
  713. array[index].dispose();
  714. }
  715. }
  716. }
  717. this._textures = {};
  718. super.dispose(forceDisposeEffect, forceDisposeTextures, notBoundToMesh);
  719. }
  720. /**
  721. * Serializes this material in a JSON representation
  722. * @returns the serialized material object
  723. */
  724. public serialize(): any {
  725. var serializationObject = SerializationHelper.Serialize(this);
  726. serializationObject.customType = "BABYLON.ShaderMaterial";
  727. serializationObject.options = this._options;
  728. serializationObject.shaderPath = this._shaderPath;
  729. var name: string;
  730. // Texture
  731. serializationObject.textures = {};
  732. for (name in this._textures) {
  733. serializationObject.textures[name] = this._textures[name].serialize();
  734. }
  735. // Texture arrays
  736. serializationObject.textureArrays = {};
  737. for (name in this._textureArrays) {
  738. serializationObject.textureArrays[name] = [];
  739. var array = this._textureArrays[name];
  740. for (var index = 0; index < array.length; index++) {
  741. serializationObject.textureArrays[name].push(array[index].serialize());
  742. }
  743. }
  744. // Float
  745. serializationObject.floats = {};
  746. for (name in this._floats) {
  747. serializationObject.floats[name] = this._floats[name];
  748. }
  749. // Floats
  750. serializationObject.FloatArrays = {};
  751. for (name in this._floatsArrays) {
  752. serializationObject.FloatArrays[name] = this._floatsArrays[name];
  753. }
  754. // Color3
  755. serializationObject.colors3 = {};
  756. for (name in this._colors3) {
  757. serializationObject.colors3[name] = this._colors3[name].asArray();
  758. }
  759. // Color3 array
  760. serializationObject.colors3Arrays = {};
  761. for (name in this._colors3Arrays) {
  762. serializationObject.colors3Arrays[name] = this._colors3Arrays[name];
  763. }
  764. // Color4
  765. serializationObject.colors4 = {};
  766. for (name in this._colors4) {
  767. serializationObject.colors4[name] = this._colors4[name].asArray();
  768. }
  769. // Color4 array
  770. serializationObject.colors4Arrays = {};
  771. for (name in this._colors4Arrays) {
  772. serializationObject.colors4Arrays[name] = this._colors4Arrays[name];
  773. }
  774. // Vector2
  775. serializationObject.vectors2 = {};
  776. for (name in this._vectors2) {
  777. serializationObject.vectors2[name] = this._vectors2[name].asArray();
  778. }
  779. // Vector3
  780. serializationObject.vectors3 = {};
  781. for (name in this._vectors3) {
  782. serializationObject.vectors3[name] = this._vectors3[name].asArray();
  783. }
  784. // Vector4
  785. serializationObject.vectors4 = {};
  786. for (name in this._vectors4) {
  787. serializationObject.vectors4[name] = this._vectors4[name].asArray();
  788. }
  789. // Matrix
  790. serializationObject.matrices = {};
  791. for (name in this._matrices) {
  792. serializationObject.matrices[name] = this._matrices[name].asArray();
  793. }
  794. // MatrixArray
  795. serializationObject.matrixArray = {};
  796. for (name in this._matrixArrays) {
  797. serializationObject.matrixArray[name] = this._matrixArrays[name];
  798. }
  799. // Matrix 3x3
  800. serializationObject.matrices3x3 = {};
  801. for (name in this._matrices3x3) {
  802. serializationObject.matrices3x3[name] = this._matrices3x3[name];
  803. }
  804. // Matrix 2x2
  805. serializationObject.matrices2x2 = {};
  806. for (name in this._matrices2x2) {
  807. serializationObject.matrices2x2[name] = this._matrices2x2[name];
  808. }
  809. // Vector2Array
  810. serializationObject.vectors2Arrays = {};
  811. for (name in this._vectors2Arrays) {
  812. serializationObject.vectors2Arrays[name] = this._vectors2Arrays[name];
  813. }
  814. // Vector3Array
  815. serializationObject.vectors3Arrays = {};
  816. for (name in this._vectors3Arrays) {
  817. serializationObject.vectors3Arrays[name] = this._vectors3Arrays[name];
  818. }
  819. // Vector4Array
  820. serializationObject.vectors4Arrays = {};
  821. for (name in this._vectors4Arrays) {
  822. serializationObject.vectors4Arrays[name] = this._vectors4Arrays[name];
  823. }
  824. return serializationObject;
  825. }
  826. /**
  827. * Creates a shader material from parsed shader material data
  828. * @param source defines the JSON represnetation of the material
  829. * @param scene defines the hosting scene
  830. * @param rootUrl defines the root URL to use to load textures and relative dependencies
  831. * @returns a new material
  832. */
  833. public static Parse(source: any, scene: Scene, rootUrl: string): ShaderMaterial {
  834. var material = SerializationHelper.Parse(() => new ShaderMaterial(source.name, scene, source.shaderPath, source.options), source, scene, rootUrl);
  835. var name: string;
  836. // Texture
  837. for (name in source.textures) {
  838. material.setTexture(name, <Texture>Texture.Parse(source.textures[name], scene, rootUrl));
  839. }
  840. // Texture arrays
  841. for (name in source.textureArrays) {
  842. var array = source.textureArrays[name];
  843. var textureArray = new Array<Texture>();
  844. for (var index = 0; index < array.length; index++) {
  845. textureArray.push(<Texture>Texture.Parse(array[index], scene, rootUrl));
  846. }
  847. material.setTextureArray(name, textureArray);
  848. }
  849. // Float
  850. for (name in source.floats) {
  851. material.setFloat(name, source.floats[name]);
  852. }
  853. // Float s
  854. for (name in source.floatsArrays) {
  855. material.setFloats(name, source.floatsArrays[name]);
  856. }
  857. // Color3
  858. for (name in source.colors3) {
  859. material.setColor3(name, Color3.FromArray(source.colors3[name]));
  860. }
  861. // Color3 arrays
  862. for (name in source.colors3Arrays) {
  863. const colors: Color3[] = source.colors3Arrays[name].reduce((arr: Array<Array<number>>, num: number, i: number) => {
  864. if (i % 3 === 0) {
  865. arr.push([num]);
  866. } else {
  867. arr[arr.length - 1].push(num);
  868. }
  869. return arr;
  870. }, []).map((color: ArrayLike<number>) => Color3.FromArray(color));
  871. material.setColor3Array(name, colors);
  872. }
  873. // Color4
  874. for (name in source.colors4) {
  875. material.setColor4(name, Color4.FromArray(source.colors4[name]));
  876. }
  877. // Color4 arrays
  878. for (name in source.colors4Arrays) {
  879. const colors: Color4[] = source.colors4Arrays[name].reduce((arr: Array<Array<number>>, num: number, i: number) => {
  880. if (i % 4 === 0) {
  881. arr.push([num]);
  882. } else {
  883. arr[arr.length - 1].push(num);
  884. }
  885. return arr;
  886. }, []).map((color: ArrayLike<number>) => Color4.FromArray(color));
  887. material.setColor4Array(name, colors);
  888. }
  889. // Vector2
  890. for (name in source.vectors2) {
  891. material.setVector2(name, Vector2.FromArray(source.vectors2[name]));
  892. }
  893. // Vector3
  894. for (name in source.vectors3) {
  895. material.setVector3(name, Vector3.FromArray(source.vectors3[name]));
  896. }
  897. // Vector4
  898. for (name in source.vectors4) {
  899. material.setVector4(name, Vector4.FromArray(source.vectors4[name]));
  900. }
  901. // Matrix
  902. for (name in source.matrices) {
  903. material.setMatrix(name, Matrix.FromArray(source.matrices[name]));
  904. }
  905. // MatrixArray
  906. for (name in source.matrixArray) {
  907. material._matrixArrays[name] = new Float32Array(source.matrixArray[name]);
  908. }
  909. // Matrix 3x3
  910. for (name in source.matrices3x3) {
  911. material.setMatrix3x3(name, source.matrices3x3[name]);
  912. }
  913. // Matrix 2x2
  914. for (name in source.matrices2x2) {
  915. material.setMatrix2x2(name, source.matrices2x2[name]);
  916. }
  917. // Vector2Array
  918. for (name in source.vectors2Arrays) {
  919. material.setArray2(name, source.vectors2Arrays[name]);
  920. }
  921. // Vector3Array
  922. for (name in source.vectors3Arrays) {
  923. material.setArray3(name, source.vectors3Arrays[name]);
  924. }
  925. // Vector4Array
  926. for (name in source.vectors4Arrays) {
  927. material.setArray4(name, source.vectors4Arrays[name]);
  928. }
  929. return material;
  930. }
  931. }
  932. _TypeStore.RegisteredTypes["BABYLON.ShaderMaterial"] = ShaderMaterial;