babylon.shaderMaterial.ts 22 KB

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