babylon.shaderMaterial.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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 _floats: { [name: string]: number } = {};
  7. private _floatsArrays: { [name: string]: number[] } = {};
  8. private _colors3: { [name: string]: Color3 } = {};
  9. private _colors4: { [name: string]: Color4 } = {};
  10. private _vectors2: { [name: string]: Vector2 } = {};
  11. private _vectors3: { [name: string]: Vector3 } = {};
  12. private _vectors4: { [name: string]: Vector4 } = {};
  13. private _matrices: { [name: string]: Matrix } = {};
  14. private _matrices3x3: { [name: string]: Float32Array } = {};
  15. private _matrices2x2: { [name: string]: Float32Array } = {};
  16. private _cachedWorldViewMatrix = new Matrix();
  17. private _renderId: number;
  18. constructor(name: string, scene: Scene, shaderPath: any, options: any) {
  19. super(name, scene);
  20. this._shaderPath = shaderPath;
  21. options.needAlphaBlending = options.needAlphaBlending || false;
  22. options.needAlphaTesting = options.needAlphaTesting || false;
  23. options.attributes = options.attributes || ["position", "normal", "uv"];
  24. options.uniforms = options.uniforms || ["worldViewProjection"];
  25. options.samplers = options.samplers || [];
  26. options.defines = options.defines || [];
  27. this._options = options;
  28. }
  29. public needAlphaBlending(): boolean {
  30. return this._options.needAlphaBlending;
  31. }
  32. public needAlphaTesting(): boolean {
  33. return this._options.needAlphaTesting;
  34. }
  35. private _checkUniform(uniformName): void {
  36. if (this._options.uniforms.indexOf(uniformName) === -1) {
  37. this._options.uniforms.push(uniformName);
  38. }
  39. }
  40. public setTexture(name: string, texture: Texture): ShaderMaterial {
  41. if (this._options.samplers.indexOf(name) === -1) {
  42. this._options.samplers.push(name);
  43. }
  44. this._textures[name] = texture;
  45. return this;
  46. }
  47. public setFloat(name: string, value: number): ShaderMaterial {
  48. this._checkUniform(name);
  49. this._floats[name] = value;
  50. return this;
  51. }
  52. public setFloats(name: string, value: number[]): ShaderMaterial {
  53. this._checkUniform(name);
  54. this._floatsArrays[name] = value;
  55. return this;
  56. }
  57. public setColor3(name: string, value: Color3): ShaderMaterial {
  58. this._checkUniform(name);
  59. this._colors3[name] = value;
  60. return this;
  61. }
  62. public setColor4(name: string, value: Color4): ShaderMaterial {
  63. this._checkUniform(name);
  64. this._colors4[name] = value;
  65. return this;
  66. }
  67. public setVector2(name: string, value: Vector2): ShaderMaterial {
  68. this._checkUniform(name);
  69. this._vectors2[name] = value;
  70. return this;
  71. }
  72. public setVector3(name: string, value: Vector3): ShaderMaterial {
  73. this._checkUniform(name);
  74. this._vectors3[name] = value;
  75. return this;
  76. }
  77. public setVector4(name: string, value: Vector4): ShaderMaterial {
  78. this._checkUniform(name);
  79. this._vectors4[name] = value;
  80. return this;
  81. }
  82. public setMatrix(name: string, value: Matrix): ShaderMaterial {
  83. this._checkUniform(name);
  84. this._matrices[name] = value;
  85. return this;
  86. }
  87. public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
  88. this._checkUniform(name);
  89. this._matrices3x3[name] = value;
  90. return this;
  91. }
  92. public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
  93. this._checkUniform(name);
  94. this._matrices2x2[name] = value;
  95. return this;
  96. }
  97. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  98. var scene = this.getScene();
  99. var engine = scene.getEngine();
  100. if (!this.checkReadyOnEveryCall) {
  101. if (this._renderId === scene.getRenderId()) {
  102. return true;
  103. }
  104. }
  105. // Instances
  106. var defines = [];
  107. var fallbacks = new EffectFallbacks();
  108. if (useInstances) {
  109. defines.push("#define INSTANCES");
  110. }
  111. for (var index = 0; index < this._options.defines.length; index++) {
  112. defines.push(this._options.defines[index]);
  113. }
  114. // Bones
  115. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
  116. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  117. defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
  118. fallbacks.addCPUSkinningFallback(0, mesh);
  119. }
  120. // Alpha test
  121. if (engine.getAlphaTesting()) {
  122. defines.push("#define ALPHATEST");
  123. }
  124. var previousEffect = this._effect;
  125. var join = defines.join("\n");
  126. this._effect = engine.createEffect(this._shaderPath,
  127. this._options.attributes,
  128. this._options.uniforms,
  129. this._options.samplers,
  130. join, fallbacks, this.onCompiled, this.onError);
  131. if (!this._effect.isReady()) {
  132. return false;
  133. }
  134. if (previousEffect !== this._effect) {
  135. scene.resetCachedMaterial();
  136. }
  137. this._renderId = scene.getRenderId();
  138. return true;
  139. }
  140. public bindOnlyWorldMatrix(world: Matrix): void {
  141. var scene = this.getScene();
  142. if (this._options.uniforms.indexOf("world") !== -1) {
  143. this._effect.setMatrix("world", world);
  144. }
  145. if (this._options.uniforms.indexOf("worldView") !== -1) {
  146. world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
  147. this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
  148. }
  149. if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
  150. this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
  151. }
  152. }
  153. public bind(world: Matrix, mesh?: Mesh): void {
  154. // Std values
  155. this.bindOnlyWorldMatrix(world);
  156. if (this.getScene().getCachedMaterial() !== this) {
  157. if (this._options.uniforms.indexOf("view") !== -1) {
  158. this._effect.setMatrix("view", this.getScene().getViewMatrix());
  159. }
  160. if (this._options.uniforms.indexOf("projection") !== -1) {
  161. this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
  162. }
  163. if (this._options.uniforms.indexOf("viewProjection") !== -1) {
  164. this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  165. }
  166. // Bones
  167. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
  168. this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
  169. }
  170. // Texture
  171. for (var name in this._textures) {
  172. this._effect.setTexture(name, this._textures[name]);
  173. }
  174. // Float
  175. for (name in this._floats) {
  176. this._effect.setFloat(name, this._floats[name]);
  177. }
  178. // Float s
  179. for (name in this._floatsArrays) {
  180. this._effect.setArray(name, this._floatsArrays[name]);
  181. }
  182. // Color3
  183. for (name in this._colors3) {
  184. this._effect.setColor3(name, this._colors3[name]);
  185. }
  186. // Color4
  187. for (name in this._colors4) {
  188. var color = this._colors4[name];
  189. this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
  190. }
  191. // Vector2
  192. for (name in this._vectors2) {
  193. this._effect.setVector2(name, this._vectors2[name]);
  194. }
  195. // Vector3
  196. for (name in this._vectors3) {
  197. this._effect.setVector3(name, this._vectors3[name]);
  198. }
  199. // Vector4
  200. for (name in this._vectors4) {
  201. this._effect.setVector4(name, this._vectors4[name]);
  202. }
  203. // Matrix
  204. for (name in this._matrices) {
  205. this._effect.setMatrix(name, this._matrices[name]);
  206. }
  207. // Matrix 3x3
  208. for (name in this._matrices3x3) {
  209. this._effect.setMatrix3x3(name, this._matrices3x3[name]);
  210. }
  211. // Matrix 2x2
  212. for (name in this._matrices2x2) {
  213. this._effect.setMatrix2x2(name, this._matrices2x2[name]);
  214. }
  215. }
  216. super.bind(world, mesh);
  217. }
  218. public clone(name: string): ShaderMaterial {
  219. var newShaderMaterial = new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options);
  220. return newShaderMaterial;
  221. }
  222. public dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean): void {
  223. if (forceDisposeTextures) {
  224. for (var name in this._textures) {
  225. this._textures[name].dispose();
  226. }
  227. }
  228. this._textures = {};
  229. super.dispose(forceDisposeEffect, forceDisposeTextures);
  230. }
  231. public serialize(): any {
  232. var serializationObject = SerializationHelper.Serialize(this);
  233. serializationObject.customType = "BABYLON.ShaderMaterial";
  234. serializationObject.options = this._options;
  235. serializationObject.shaderPath = this._shaderPath;
  236. // Texture
  237. serializationObject.textures = {};
  238. for (var name in this._textures) {
  239. serializationObject.textures[name] = this._textures[name].serialize();
  240. }
  241. // Float
  242. serializationObject.floats = {};
  243. for (name in this._floats) {
  244. serializationObject.floats[name] = this._floats[name];
  245. }
  246. // Float s
  247. serializationObject.floatArrays = {};
  248. for (name in this._floatsArrays) {
  249. serializationObject.floatArrays[name] = this._floatsArrays[name];
  250. }
  251. // Color3
  252. serializationObject.colors3 = {};
  253. for (name in this._colors3) {
  254. serializationObject.colors3[name] = this._colors3[name].asArray();
  255. }
  256. // Color4
  257. serializationObject.colors4 = {};
  258. for (name in this._colors4) {
  259. serializationObject.colors4[name] = this._colors4[name].asArray();
  260. }
  261. // Vector2
  262. serializationObject.vectors2 = {};
  263. for (name in this._vectors2) {
  264. serializationObject.vectors2[name] = this._vectors2[name].asArray();
  265. }
  266. // Vector3
  267. serializationObject.vectors3 = {};
  268. for (name in this._vectors3) {
  269. serializationObject.vectors3[name] = this._vectors3[name].asArray();
  270. }
  271. // Vector4
  272. serializationObject.vectors4 = {};
  273. for (name in this._vectors4) {
  274. serializationObject.vectors4[name] = this._vectors4[name].asArray();
  275. }
  276. // Matrix
  277. serializationObject.matrices = {};
  278. for (name in this._matrices) {
  279. serializationObject.matrices[name] = this._matrices[name].asArray();
  280. }
  281. // Matrix 3x3
  282. serializationObject.matrices3x3 = {};
  283. for (name in this._matrices3x3) {
  284. serializationObject.matrices3x3[name] = this._matrices3x3[name];
  285. }
  286. // Matrix 2x2
  287. serializationObject.matrices2x2 = {};
  288. for (name in this._matrices2x2) {
  289. serializationObject.matrices2x2[name] = this._matrices2x2[name];
  290. }
  291. return serializationObject;
  292. }
  293. public static Parse(source: any, scene: Scene, rootUrl: string): ShaderMaterial {
  294. var material = SerializationHelper.Parse(() => new ShaderMaterial(source.name, scene, source.shaderPath, source.options), source, scene, rootUrl);
  295. // Texture
  296. for (var name in source.textures) {
  297. material.setTexture(name, <Texture>Texture.Parse(source.textures[name], scene, rootUrl));
  298. }
  299. // Float
  300. for (name in source.floats) {
  301. material.setFloat(name, source.floats[name]);
  302. }
  303. // Float s
  304. for (name in source.floatsArrays) {
  305. material.setFloats(name, source.floatsArrays[name]);
  306. }
  307. // Color3
  308. for (name in source.colors3) {
  309. material.setColor3(name, Color3.FromArray(source.colors3[name]));
  310. }
  311. // Color4
  312. for (name in source.colors4) {
  313. material.setColor4(name, Color4.FromArray(source.colors4[name]));
  314. }
  315. // Vector2
  316. for (name in source.vectors2) {
  317. material.setVector2(name, Vector2.FromArray(source.vectors2[name]));
  318. }
  319. // Vector3
  320. for (name in source.vectors3) {
  321. material.setVector3(name, Vector3.FromArray(source.vectors3[name]));
  322. }
  323. // Vector4
  324. for (name in source.vectors4) {
  325. material.setVector4(name, Vector4.FromArray(source.vectors4[name]));
  326. }
  327. // Matrix
  328. for (name in source.matrices) {
  329. material.setMatrix(name, Matrix.FromArray(source.matrices[name]));
  330. }
  331. // Matrix 3x3
  332. for (name in source.matrices3x3) {
  333. material.setMatrix3x3(name, source.matrices3x3[name]);
  334. }
  335. // Matrix 2x2
  336. for (name in source.matrices2x2) {
  337. material.setMatrix2x2(name, source.matrices2x2[name]);
  338. }
  339. return material;
  340. }
  341. }
  342. }