babylon.shaderMaterial.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. module BABYLON {
  2. export class ShaderMaterial extends Material {
  3. private _shaderPath: any;
  4. private _options: any;
  5. private _textures: { [name: string]: Texture } = {};
  6. private _textureArrays: { [name: string]: Texture[] } = {};
  7. private _floats: { [name: string]: number } = {};
  8. private _ints: { [name: string]: number } = {};
  9. private _floatsArrays: { [name: string]: number[] } = {};
  10. private _colors3: { [name: string]: Color3 } = {};
  11. private _colors3Arrays: { [name: string]: number[] } = {};
  12. private _colors4: { [name: string]: Color4 } = {};
  13. private _vectors2: { [name: string]: Vector2 } = {};
  14. private _vectors3: { [name: string]: Vector3 } = {};
  15. private _vectors4: { [name: string]: Vector4 } = {};
  16. private _matrices: { [name: string]: Matrix } = {};
  17. private _matrices3x3: { [name: string]: Float32Array } = {};
  18. private _matrices2x2: { [name: string]: Float32Array } = {};
  19. private _vectors2Arrays: { [name: string]: number[] } = {};
  20. private _vectors3Arrays: { [name: string]: number[] } = {};
  21. private _cachedWorldViewMatrix = new Matrix();
  22. private _renderId: number;
  23. constructor(name: string, scene: Scene, shaderPath: any, options: any) {
  24. super(name, scene);
  25. this._shaderPath = shaderPath;
  26. options.needAlphaBlending = options.needAlphaBlending || false;
  27. options.needAlphaTesting = options.needAlphaTesting || false;
  28. options.attributes = options.attributes || ["position", "normal", "uv"];
  29. options.uniforms = options.uniforms || ["worldViewProjection"];
  30. options.uniformBuffers = options.uniformBuffers || [];
  31. options.samplers = options.samplers || [];
  32. options.defines = options.defines || [];
  33. this._options = options;
  34. }
  35. public getClassName(): string {
  36. return "ShaderMaterial";
  37. }
  38. public needAlphaBlending(): boolean {
  39. return this._options.needAlphaBlending;
  40. }
  41. public needAlphaTesting(): boolean {
  42. return this._options.needAlphaTesting;
  43. }
  44. private _checkUniform(uniformName: string): void {
  45. if (this._options.uniforms.indexOf(uniformName) === -1) {
  46. this._options.uniforms.push(uniformName);
  47. }
  48. }
  49. public setTexture(name: string, texture: Texture): ShaderMaterial {
  50. if (this._options.samplers.indexOf(name) === -1) {
  51. this._options.samplers.push(name);
  52. }
  53. this._textures[name] = texture;
  54. return this;
  55. }
  56. public setTextureArray(name: string, textures: Texture[]): ShaderMaterial {
  57. if (this._options.samplers.indexOf(name) === -1) {
  58. this._options.samplers.push(name);
  59. }
  60. this._checkUniform(name);
  61. this._textureArrays[name] = textures;
  62. return this;
  63. }
  64. public setFloat(name: string, value: number): ShaderMaterial {
  65. this._checkUniform(name);
  66. this._floats[name] = value;
  67. return this;
  68. }
  69. public setInt(name: string, value: number): ShaderMaterial {
  70. this._checkUniform(name);
  71. this._ints[name] = value;
  72. return this;
  73. }
  74. public setFloats(name: string, value: number[]): ShaderMaterial {
  75. this._checkUniform(name);
  76. this._floatsArrays[name] = value;
  77. return this;
  78. }
  79. public setColor3(name: string, value: Color3): ShaderMaterial {
  80. this._checkUniform(name);
  81. this._colors3[name] = value;
  82. return this;
  83. }
  84. public setColor3Array(name: string, value: Color3[]): ShaderMaterial {
  85. this._checkUniform(name);
  86. this._colors3Arrays[name] = value.reduce((arr, color) => {
  87. color.toArray(arr, arr.length);
  88. return arr;
  89. }, [])
  90. return this;
  91. }
  92. public setColor4(name: string, value: Color4): ShaderMaterial {
  93. this._checkUniform(name);
  94. this._colors4[name] = value;
  95. return this;
  96. }
  97. public setVector2(name: string, value: Vector2): ShaderMaterial {
  98. this._checkUniform(name);
  99. this._vectors2[name] = value;
  100. return this;
  101. }
  102. public setVector3(name: string, value: Vector3): ShaderMaterial {
  103. this._checkUniform(name);
  104. this._vectors3[name] = value;
  105. return this;
  106. }
  107. public setVector4(name: string, value: Vector4): ShaderMaterial {
  108. this._checkUniform(name);
  109. this._vectors4[name] = value;
  110. return this;
  111. }
  112. public setMatrix(name: string, value: Matrix): ShaderMaterial {
  113. this._checkUniform(name);
  114. this._matrices[name] = value;
  115. return this;
  116. }
  117. public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
  118. this._checkUniform(name);
  119. this._matrices3x3[name] = value;
  120. return this;
  121. }
  122. public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
  123. this._checkUniform(name);
  124. this._matrices2x2[name] = value;
  125. return this;
  126. }
  127. public setArray2(name: string, value: number[]): ShaderMaterial {
  128. this._checkUniform(name);
  129. this._vectors2Arrays[name] = value;
  130. return this;
  131. }
  132. public setArray3(name: string, value: number[]): ShaderMaterial {
  133. this._checkUniform(name);
  134. this._vectors3Arrays[name] = value;
  135. return this;
  136. }
  137. private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
  138. if (!mesh) {
  139. return true;
  140. }
  141. if (this._effect && (this._effect.defines.indexOf("#define INSTANCES") !== -1) !== useInstances) {
  142. return false;
  143. }
  144. return false;
  145. }
  146. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  147. var scene = this.getScene();
  148. var engine = scene.getEngine();
  149. if (!this.checkReadyOnEveryCall) {
  150. if (this._renderId === scene.getRenderId()) {
  151. if (this._checkCache(scene, mesh, useInstances)) {
  152. return true;
  153. }
  154. }
  155. }
  156. // Instances
  157. var defines = [];
  158. var attribs = [];
  159. var fallbacks = new EffectFallbacks();
  160. if (useInstances) {
  161. defines.push("#define INSTANCES");
  162. }
  163. for (var index = 0; index < this._options.defines.length; index++) {
  164. defines.push(this._options.defines[index]);
  165. }
  166. for (var index = 0; index < this._options.attributes.length; index++) {
  167. attribs.push(this._options.attributes[index]);
  168. }
  169. if (mesh && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
  170. attribs.push(VertexBuffer.ColorKind);
  171. defines.push("#define VERTEXCOLOR");
  172. }
  173. // Bones
  174. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
  175. attribs.push(VertexBuffer.MatricesIndicesKind);
  176. attribs.push(VertexBuffer.MatricesWeightsKind);
  177. if (mesh.numBoneInfluencers > 4) {
  178. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  179. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  180. }
  181. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  182. defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
  183. fallbacks.addCPUSkinningFallback(0, mesh);
  184. if (this._options.uniforms.indexOf("mBones") === -1) {
  185. this._options.uniforms.push("mBones");
  186. }
  187. } else {
  188. defines.push("#define NUM_BONE_INFLUENCERS 0");
  189. }
  190. // Textures
  191. for (var name in this._textures) {
  192. if (!this._textures[name].isReady()) {
  193. return false;
  194. }
  195. }
  196. // Alpha test
  197. if (mesh && this._shouldTurnAlphaTestOn(mesh)) {
  198. defines.push("#define ALPHATEST");
  199. }
  200. var previousEffect = this._effect;
  201. var join = defines.join("\n");
  202. this._effect = engine.createEffect(this._shaderPath, <EffectCreationOptions>{
  203. attributes: attribs,
  204. uniformsNames: this._options.uniforms,
  205. uniformBuffersNames: this._options.uniformBuffers,
  206. samplers: this._options.samplers,
  207. defines: join,
  208. fallbacks: fallbacks,
  209. onCompiled: this.onCompiled,
  210. onError: this.onError
  211. }, engine);
  212. if (!this._effect.isReady()) {
  213. return false;
  214. }
  215. if (previousEffect !== this._effect) {
  216. scene.resetCachedMaterial();
  217. }
  218. this._renderId = scene.getRenderId();
  219. return true;
  220. }
  221. public bindOnlyWorldMatrix(world: Matrix): void {
  222. var scene = this.getScene();
  223. if (!this._effect) {
  224. return;
  225. }
  226. if (this._options.uniforms.indexOf("world") !== -1) {
  227. this._effect.setMatrix("world", world);
  228. }
  229. if (this._options.uniforms.indexOf("worldView") !== -1) {
  230. world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
  231. this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
  232. }
  233. if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
  234. this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
  235. }
  236. }
  237. public bind(world: Matrix, mesh?: Mesh): void {
  238. // Std values
  239. this.bindOnlyWorldMatrix(world);
  240. if (this._effect && this.getScene().getCachedMaterial() !== this) {
  241. if (this._options.uniforms.indexOf("view") !== -1) {
  242. this._effect.setMatrix("view", this.getScene().getViewMatrix());
  243. }
  244. if (this._options.uniforms.indexOf("projection") !== -1) {
  245. this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
  246. }
  247. if (this._options.uniforms.indexOf("viewProjection") !== -1) {
  248. this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  249. }
  250. // Bones
  251. MaterialHelper.BindBonesParameters(mesh, this._effect);
  252. var name: string;
  253. // Texture
  254. for (name in this._textures) {
  255. this._effect.setTexture(name, this._textures[name]);
  256. }
  257. // Texture arrays
  258. for (name in this._textureArrays) {
  259. this._effect.setTextureArray(name, this._textureArrays[name]);
  260. }
  261. // Int
  262. for (name in this._ints) {
  263. this._effect.setInt(name, this._ints[name]);
  264. }
  265. // Float
  266. for (name in this._floats) {
  267. this._effect.setFloat(name, this._floats[name]);
  268. }
  269. // Floats
  270. for (name in this._floatsArrays) {
  271. this._effect.setArray(name, this._floatsArrays[name]);
  272. }
  273. // Color3
  274. for (name in this._colors3) {
  275. this._effect.setColor3(name, this._colors3[name]);
  276. }
  277. for (name in this._colors3Arrays) {
  278. this._effect.setArray3(name, this._colors3Arrays[name]);
  279. }
  280. // Color4
  281. for (name in this._colors4) {
  282. var color = this._colors4[name];
  283. this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
  284. }
  285. // Vector2
  286. for (name in this._vectors2) {
  287. this._effect.setVector2(name, this._vectors2[name]);
  288. }
  289. // Vector3
  290. for (name in this._vectors3) {
  291. this._effect.setVector3(name, this._vectors3[name]);
  292. }
  293. // Vector4
  294. for (name in this._vectors4) {
  295. this._effect.setVector4(name, this._vectors4[name]);
  296. }
  297. // Matrix
  298. for (name in this._matrices) {
  299. this._effect.setMatrix(name, this._matrices[name]);
  300. }
  301. // Matrix 3x3
  302. for (name in this._matrices3x3) {
  303. this._effect.setMatrix3x3(name, this._matrices3x3[name]);
  304. }
  305. // Matrix 2x2
  306. for (name in this._matrices2x2) {
  307. this._effect.setMatrix2x2(name, this._matrices2x2[name]);
  308. }
  309. // Vector2Array
  310. for (name in this._vectors2Arrays) {
  311. this._effect.setArray2(name, this._vectors2Arrays[name]);
  312. }
  313. // Vector3Array
  314. for (name in this._vectors3Arrays) {
  315. this._effect.setArray3(name, this._vectors3Arrays[name]);
  316. }
  317. }
  318. this._afterBind(mesh);
  319. }
  320. public getActiveTextures(): BaseTexture[] {
  321. var activeTextures = super.getActiveTextures();
  322. for (var name in this._textures) {
  323. activeTextures.push(this._textures[name]);
  324. }
  325. for (var name in this._textureArrays) {
  326. var array = this._textureArrays[name];
  327. for (var index = 0; index < array.length; index++) {
  328. activeTextures.push(array[index]);
  329. }
  330. }
  331. return activeTextures;
  332. }
  333. public hasTexture(texture: BaseTexture): boolean {
  334. if (super.hasTexture(texture)) {
  335. return true;
  336. }
  337. for (var name in this._textures) {
  338. if (this._textures[name] === texture) {
  339. return true;
  340. }
  341. }
  342. for (var name in this._textureArrays) {
  343. var array = this._textureArrays[name];
  344. for (var index = 0; index < array.length; index++) {
  345. if (array[index] === texture) {
  346. return true;
  347. }
  348. }
  349. }
  350. return false;
  351. }
  352. public clone(name: string): ShaderMaterial {
  353. var newShaderMaterial = new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options);
  354. return newShaderMaterial;
  355. }
  356. public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
  357. if (forceDisposeTextures) {
  358. var name: string;
  359. for (name in this._textures) {
  360. this._textures[name].dispose();
  361. }
  362. for (name in this._textureArrays) {
  363. var array = this._textureArrays[name];
  364. for (var index = 0; index < array.length; index++) {
  365. array[index].dispose();
  366. }
  367. }
  368. }
  369. this._textures = {};
  370. super.dispose(forceDisposeEffect, forceDisposeTextures);
  371. }
  372. public serialize(): any {
  373. var serializationObject = SerializationHelper.Serialize(this);
  374. serializationObject.customType = "BABYLON.ShaderMaterial";
  375. serializationObject.options = this._options;
  376. serializationObject.shaderPath = this._shaderPath;
  377. var name: string;
  378. // Texture
  379. serializationObject.textures = {};
  380. for (name in this._textures) {
  381. serializationObject.textures[name] = this._textures[name].serialize();
  382. }
  383. // Texture arrays
  384. serializationObject.textureArrays = {};
  385. for (name in this._textureArrays) {
  386. serializationObject.textureArrays[name] = [];
  387. var array = this._textureArrays[name];
  388. for (var index = 0; index < array.length; index++) {
  389. serializationObject.textureArrays[name].push(array[index].serialize());
  390. }
  391. }
  392. // Float
  393. serializationObject.floats = {};
  394. for (name in this._floats) {
  395. serializationObject.floats[name] = this._floats[name];
  396. }
  397. // Float s
  398. serializationObject.FloatArrays = {};
  399. for (name in this._floatsArrays) {
  400. serializationObject.FloatArrays[name] = this._floatsArrays[name];
  401. }
  402. // Color3
  403. serializationObject.colors3 = {};
  404. for (name in this._colors3) {
  405. serializationObject.colors3[name] = this._colors3[name].asArray();
  406. }
  407. // Color3 array
  408. serializationObject.colors3Arrays = {};
  409. for (name in this._colors3Arrays) {
  410. serializationObject.colors3Arrays[name] = this._colors3Arrays[name];
  411. }
  412. // Color4
  413. serializationObject.colors4 = {};
  414. for (name in this._colors4) {
  415. serializationObject.colors4[name] = this._colors4[name].asArray();
  416. }
  417. // Vector2
  418. serializationObject.vectors2 = {};
  419. for (name in this._vectors2) {
  420. serializationObject.vectors2[name] = this._vectors2[name].asArray();
  421. }
  422. // Vector3
  423. serializationObject.vectors3 = {};
  424. for (name in this._vectors3) {
  425. serializationObject.vectors3[name] = this._vectors3[name].asArray();
  426. }
  427. // Vector4
  428. serializationObject.vectors4 = {};
  429. for (name in this._vectors4) {
  430. serializationObject.vectors4[name] = this._vectors4[name].asArray();
  431. }
  432. // Matrix
  433. serializationObject.matrices = {};
  434. for (name in this._matrices) {
  435. serializationObject.matrices[name] = this._matrices[name].asArray();
  436. }
  437. // Matrix 3x3
  438. serializationObject.matrices3x3 = {};
  439. for (name in this._matrices3x3) {
  440. serializationObject.matrices3x3[name] = this._matrices3x3[name];
  441. }
  442. // Matrix 2x2
  443. serializationObject.matrices2x2 = {};
  444. for (name in this._matrices2x2) {
  445. serializationObject.matrices2x2[name] = this._matrices2x2[name];
  446. }
  447. // Vector2Array
  448. serializationObject.vectors2Arrays = {};
  449. for (name in this._vectors2Arrays) {
  450. serializationObject.vectors2Arrays[name] = this._vectors2Arrays[name];
  451. }
  452. // Vector3Array
  453. serializationObject.vectors3Arrays = {};
  454. for (name in this._vectors3Arrays) {
  455. serializationObject.vectors3Arrays[name] = this._vectors3Arrays[name];
  456. }
  457. return serializationObject;
  458. }
  459. public static Parse(source: any, scene: Scene, rootUrl: string): ShaderMaterial {
  460. var material = SerializationHelper.Parse(() => new ShaderMaterial(source.name, scene, source.shaderPath, source.options), source, scene, rootUrl);
  461. var name: string;
  462. // Texture
  463. for (name in source.textures) {
  464. material.setTexture(name, <Texture>Texture.Parse(source.textures[name], scene, rootUrl));
  465. }
  466. // Texture arrays
  467. for (name in source.textureArrays) {
  468. var array = source.textureArrays[name];
  469. var textureArray = new Array<Texture>();
  470. for (var index = 0; index < array.length; index++) {
  471. textureArray.push(<Texture>Texture.Parse(array[index], scene, rootUrl));
  472. }
  473. material.setTextureArray(name, textureArray);
  474. }
  475. // Float
  476. for (name in source.floats) {
  477. material.setFloat(name, source.floats[name]);
  478. }
  479. // Float s
  480. for (name in source.floatsArrays) {
  481. material.setFloats(name, source.floatsArrays[name]);
  482. }
  483. // Color3
  484. for (name in source.colors3) {
  485. material.setColor3(name, Color3.FromArray(source.colors3[name]));
  486. }
  487. // Color3 arrays
  488. for (name in source.colors3Arrays) {
  489. const colors: Color3[] = source.colors3Arrays[name].reduce((arr: Array<Array<number>>, num: number, i: number) => {
  490. if (i % 3 === 0) {
  491. arr.push([num]);
  492. } else {
  493. arr[arr.length - 1].push(num);
  494. }
  495. return arr;
  496. }, []).map((color: ArrayLike<number>) => Color3.FromArray(color));
  497. material.setColor3Array(name, colors);
  498. }
  499. // Color4
  500. for (name in source.colors4) {
  501. material.setColor4(name, Color4.FromArray(source.colors4[name]));
  502. }
  503. // Vector2
  504. for (name in source.vectors2) {
  505. material.setVector2(name, Vector2.FromArray(source.vectors2[name]));
  506. }
  507. // Vector3
  508. for (name in source.vectors3) {
  509. material.setVector3(name, Vector3.FromArray(source.vectors3[name]));
  510. }
  511. // Vector4
  512. for (name in source.vectors4) {
  513. material.setVector4(name, Vector4.FromArray(source.vectors4[name]));
  514. }
  515. // Matrix
  516. for (name in source.matrices) {
  517. material.setMatrix(name, Matrix.FromArray(source.matrices[name]));
  518. }
  519. // Matrix 3x3
  520. for (name in source.matrices3x3) {
  521. material.setMatrix3x3(name, source.matrices3x3[name]);
  522. }
  523. // Matrix 2x2
  524. for (name in source.matrices2x2) {
  525. material.setMatrix2x2(name, source.matrices2x2[name]);
  526. }
  527. // Vector2Array
  528. for (name in source.vectors2Arrays) {
  529. material.setArray2(name, source.vectors2Arrays[name]);
  530. }
  531. // Vector3Array
  532. for (name in source.vectors3Arrays) {
  533. material.setArray3(name, source.vectors3Arrays[name]);
  534. }
  535. return material;
  536. }
  537. }
  538. }