babylon.shaderMaterial.ts 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. module BABYLON {
  2. export class ShaderMaterial extends Material {
  3. private _shaderPath: any;
  4. private _options: any;
  5. private _textures = new Array<Texture>();
  6. private _floats = new Array<number>();
  7. private _floatsArrays = {};
  8. private _colors3 = new Array<Color3>();
  9. private _colors4 = new Array<Color4>();
  10. private _vectors2 = new Array<Vector2>();
  11. private _vectors3 = new Array<Vector3>();
  12. private _vectors4 = new Array<Vector4>();
  13. private _matrices = new Array<Matrix>();
  14. private _matrices3x3 = new Array<Float32Array>();
  15. private _matrices2x2 = new Array<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. this._options = options;
  27. }
  28. public needAlphaBlending(): boolean {
  29. return this._options.needAlphaBlending;
  30. }
  31. public needAlphaTesting(): boolean {
  32. return this._options.needAlphaTesting;
  33. }
  34. private _checkUniform(uniformName): void {
  35. if (this._options.uniforms.indexOf(uniformName) === -1) {
  36. this._options.uniforms.push(uniformName);
  37. }
  38. }
  39. public setTexture(name: string, texture: Texture): ShaderMaterial {
  40. if (this._options.samplers.indexOf(name) === -1) {
  41. this._options.samplers.push(name);
  42. }
  43. this._textures[name] = texture;
  44. return this;
  45. }
  46. public setFloat(name: string, value: number): ShaderMaterial {
  47. this._checkUniform(name);
  48. this._floats[name] = value;
  49. return this;
  50. }
  51. public setFloats(name: string, value: number[]): ShaderMaterial {
  52. this._checkUniform(name);
  53. this._floatsArrays[name] = value;
  54. return this;
  55. }
  56. public setColor3(name: string, value: Color3): ShaderMaterial {
  57. this._checkUniform(name);
  58. this._colors3[name] = value;
  59. return this;
  60. }
  61. public setColor4(name: string, value: Color4): ShaderMaterial {
  62. this._checkUniform(name);
  63. this._colors4[name] = value;
  64. return this;
  65. }
  66. public setVector2(name: string, value: Vector2): ShaderMaterial {
  67. this._checkUniform(name);
  68. this._vectors2[name] = value;
  69. return this;
  70. }
  71. public setVector3(name: string, value: Vector3): ShaderMaterial {
  72. this._checkUniform(name);
  73. this._vectors3[name] = value;
  74. return this;
  75. }
  76. public setVector4(name: string, value: Vector4): ShaderMaterial {
  77. this._checkUniform(name);
  78. this._vectors4[name] = value;
  79. return this;
  80. }
  81. public setMatrix(name: string, value: Matrix): ShaderMaterial {
  82. this._checkUniform(name);
  83. this._matrices[name] = value;
  84. return this;
  85. }
  86. public setMatrix3x3(name: string, value: Float32Array): ShaderMaterial {
  87. this._checkUniform(name);
  88. this._matrices3x3[name] = value;
  89. return this;
  90. }
  91. public setMatrix2x2(name: string, value: Float32Array): ShaderMaterial {
  92. this._checkUniform(name);
  93. this._matrices2x2[name] = value;
  94. return this;
  95. }
  96. public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
  97. var scene = this.getScene();
  98. var engine = scene.getEngine();
  99. if (!this.checkReadyOnEveryCall) {
  100. if (this._renderId === scene.getRenderId()) {
  101. return true;
  102. }
  103. }
  104. // Instances
  105. var defines = [];
  106. var fallbacks = new EffectFallbacks();
  107. if (useInstances) {
  108. defines.push("#define INSTANCES");
  109. }
  110. // Bones
  111. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
  112. defines.push("#define BONES");
  113. defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
  114. defines.push("#define BONES4");
  115. fallbacks.addFallback(0, "BONES4");
  116. }
  117. // Alpha test
  118. if (engine.getAlphaTesting()) {
  119. defines.push("#define ALPHATEST");
  120. }
  121. var previousEffect = this._effect;
  122. var join = defines.join("\n");
  123. this._effect = engine.createEffect(this._shaderPath,
  124. this._options.attributes,
  125. this._options.uniforms,
  126. this._options.samplers,
  127. join, fallbacks, this.onCompiled, this.onError);
  128. if (!this._effect.isReady()) {
  129. return false;
  130. }
  131. if (previousEffect !== this._effect) {
  132. scene.resetCachedMaterial();
  133. }
  134. this._renderId = scene.getRenderId();
  135. return true;
  136. }
  137. public bindOnlyWorldMatrix(world: Matrix): void {
  138. var scene = this.getScene();
  139. if (this._options.uniforms.indexOf("world") !== -1) {
  140. this._effect.setMatrix("world", world);
  141. }
  142. if (this._options.uniforms.indexOf("worldView") !== -1) {
  143. world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
  144. this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
  145. }
  146. if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
  147. this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
  148. }
  149. }
  150. public bind(world: Matrix, mesh?: Mesh): void {
  151. // Std values
  152. this.bindOnlyWorldMatrix(world);
  153. if (this.getScene().getCachedMaterial() !== this) {
  154. if (this._options.uniforms.indexOf("view") !== -1) {
  155. this._effect.setMatrix("view", this.getScene().getViewMatrix());
  156. }
  157. if (this._options.uniforms.indexOf("projection") !== -1) {
  158. this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
  159. }
  160. if (this._options.uniforms.indexOf("viewProjection") !== -1) {
  161. this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
  162. }
  163. // Bones
  164. if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
  165. this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
  166. }
  167. // Texture
  168. for (var name in this._textures) {
  169. this._effect.setTexture(name, this._textures[name]);
  170. }
  171. // Float
  172. for (name in this._floats) {
  173. this._effect.setFloat(name, this._floats[name]);
  174. }
  175. // Float s
  176. for (name in this._floatsArrays) {
  177. this._effect.setArray(name, this._floatsArrays[name]);
  178. }
  179. // Color3
  180. for (name in this._colors3) {
  181. this._effect.setColor3(name, this._colors3[name]);
  182. }
  183. // Color4
  184. for (name in this._colors4) {
  185. var color = this._colors4[name];
  186. this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
  187. }
  188. // Vector2
  189. for (name in this._vectors2) {
  190. this._effect.setVector2(name, this._vectors2[name]);
  191. }
  192. // Vector3
  193. for (name in this._vectors3) {
  194. this._effect.setVector3(name, this._vectors3[name]);
  195. }
  196. // Vector4
  197. for (name in this._vectors4) {
  198. this._effect.setVector4(name, this._vectors4[name]);
  199. }
  200. // Matrix
  201. for (name in this._matrices) {
  202. this._effect.setMatrix(name, this._matrices[name]);
  203. }
  204. // Matrix 3x3
  205. for (name in this._matrices3x3) {
  206. this._effect.setMatrix3x3(name, this._matrices3x3[name]);
  207. }
  208. // Matrix 2x2
  209. for (name in this._matrices2x2) {
  210. this._effect.setMatrix2x2(name, this._matrices2x2[name]);
  211. }
  212. }
  213. super.bind(world, mesh);
  214. }
  215. public clone(name: string): ShaderMaterial {
  216. var newShaderMaterial = new ShaderMaterial(name, this.getScene(), this._shaderPath, this._options);
  217. return newShaderMaterial;
  218. }
  219. public dispose(forceDisposeEffect?: boolean): void {
  220. for (var name in this._textures) {
  221. this._textures[name].dispose();
  222. }
  223. this._textures = [];
  224. super.dispose(forceDisposeEffect);
  225. }
  226. }
  227. }