babylon.shaderMaterial.ts 20 KB

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