effect.ts 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270
  1. import { Observable } from "../Misc/observable";
  2. import { Nullable } from "../types";
  3. import { Constants } from "../Engines/constants";
  4. import { DomManagement } from "../Misc/domManagement";
  5. import { Logger } from "../Misc/logger";
  6. import { IDisposable } from '../scene';
  7. import { IPipelineContext } from '../Engines/IPipelineContext';
  8. import { DataBuffer } from '../Meshes/dataBuffer';
  9. import { ShaderProcessor } from '../Engines/Processors/shaderProcessor';
  10. import { IMatrixLike, IVector2Like, IVector3Like, IVector4Like, IColor3Like, IColor4Like } from '../Maths/math.like';
  11. import { ThinEngine } from '../Engines/thinEngine';
  12. import { IEffectFallbacks } from './iEffectFallbacks';
  13. declare type Engine = import("../Engines/engine").Engine;
  14. declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
  15. declare type BaseTexture = import("../Materials/Textures/baseTexture").BaseTexture;
  16. declare type RenderTargetTexture = import("../Materials/Textures/renderTargetTexture").RenderTargetTexture;
  17. declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
  18. /**
  19. * Options to be used when creating an effect.
  20. */
  21. export interface IEffectCreationOptions {
  22. /**
  23. * Atrributes that will be used in the shader.
  24. */
  25. attributes: string[];
  26. /**
  27. * Uniform varible names that will be set in the shader.
  28. */
  29. uniformsNames: string[];
  30. /**
  31. * Uniform buffer varible names that will be set in the shader.
  32. */
  33. uniformBuffersNames: string[];
  34. /**
  35. * Sampler texture variable names that will be set in the shader.
  36. */
  37. samplers: string[];
  38. /**
  39. * Define statements that will be set in the shader.
  40. */
  41. defines: any;
  42. /**
  43. * Possible fallbacks for this effect to improve performance when needed.
  44. */
  45. fallbacks: Nullable<IEffectFallbacks>;
  46. /**
  47. * Callback that will be called when the shader is compiled.
  48. */
  49. onCompiled: Nullable<(effect: Effect) => void>;
  50. /**
  51. * Callback that will be called if an error occurs during shader compilation.
  52. */
  53. onError: Nullable<(effect: Effect, errors: string) => void>;
  54. /**
  55. * Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
  56. */
  57. indexParameters?: any;
  58. /**
  59. * Max number of lights that can be used in the shader.
  60. */
  61. maxSimultaneousLights?: number;
  62. /**
  63. * See https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/transformFeedbackVaryings
  64. */
  65. transformFeedbackVaryings?: Nullable<string[]>;
  66. }
  67. /**
  68. * Effect containing vertex and fragment shader that can be executed on an object.
  69. */
  70. export class Effect implements IDisposable {
  71. /**
  72. * Gets or sets the relative url used to load shaders if using the engine in non-minified mode
  73. */
  74. public static ShadersRepository = "src/Shaders/";
  75. /**
  76. * Name of the effect.
  77. */
  78. public name: any = null;
  79. /**
  80. * String container all the define statements that should be set on the shader.
  81. */
  82. public defines: string = "";
  83. /**
  84. * Callback that will be called when the shader is compiled.
  85. */
  86. public onCompiled: Nullable<(effect: Effect) => void> = null;
  87. /**
  88. * Callback that will be called if an error occurs during shader compilation.
  89. */
  90. public onError: Nullable<(effect: Effect, errors: string) => void> = null;
  91. /**
  92. * Callback that will be called when effect is bound.
  93. */
  94. public onBind: Nullable<(effect: Effect) => void> = null;
  95. /**
  96. * Unique ID of the effect.
  97. */
  98. public uniqueId = 0;
  99. /**
  100. * Observable that will be called when the shader is compiled.
  101. * It is recommended to use executeWhenCompile() or to make sure that scene.isReady() is called to get this observable raised.
  102. */
  103. public onCompileObservable = new Observable<Effect>();
  104. /**
  105. * Observable that will be called if an error occurs during shader compilation.
  106. */
  107. public onErrorObservable = new Observable<Effect>();
  108. /** @hidden */
  109. public _onBindObservable: Nullable<Observable<Effect>> = null;
  110. /**
  111. * Observable that will be called when effect is bound.
  112. */
  113. public get onBindObservable(): Observable<Effect> {
  114. if (!this._onBindObservable) {
  115. this._onBindObservable = new Observable<Effect>();
  116. }
  117. return this._onBindObservable;
  118. }
  119. /** @hidden */
  120. public _bonesComputationForcedToCPU = false;
  121. private static _uniqueIdSeed = 0;
  122. private _engine: Engine;
  123. private _uniformBuffersNames: { [key: string]: number } = {};
  124. private _uniformsNames: string[];
  125. private _samplerList: string[];
  126. private _samplers: { [key: string]: number } = {};
  127. private _isReady = false;
  128. private _compilationError = "";
  129. private _allFallbacksProcessed = false;
  130. private _attributesNames: string[];
  131. private _attributes: number[];
  132. private _uniforms: { [key: string]: Nullable<WebGLUniformLocation> } = {};
  133. /**
  134. * Key for the effect.
  135. * @hidden
  136. */
  137. public _key: string = "";
  138. private _indexParameters: any;
  139. private _fallbacks: Nullable<IEffectFallbacks> = null;
  140. private _vertexSourceCode: string = "";
  141. private _fragmentSourceCode: string = "";
  142. private _vertexSourceCodeOverride: string = "";
  143. private _fragmentSourceCodeOverride: string = "";
  144. private _transformFeedbackVaryings: Nullable<string[]> = null;
  145. /**
  146. * Compiled shader to webGL program.
  147. * @hidden
  148. */
  149. public _pipelineContext: Nullable<IPipelineContext> = null;
  150. private _valueCache: { [key: string]: any } = {};
  151. private static _baseCache: { [key: number]: DataBuffer } = {};
  152. /**
  153. * Instantiates an effect.
  154. * An effect can be used to create/manage/execute vertex and fragment shaders.
  155. * @param baseName Name of the effect.
  156. * @param attributesNamesOrOptions List of attribute names that will be passed to the shader or set of all options to create the effect.
  157. * @param uniformsNamesOrEngine List of uniform variable names that will be passed to the shader or the engine that will be used to render effect.
  158. * @param samplers List of sampler variables that will be passed to the shader.
  159. * @param engine Engine to be used to render the effect
  160. * @param defines Define statements to be added to the shader.
  161. * @param fallbacks Possible fallbacks for this effect to improve performance when needed.
  162. * @param onCompiled Callback that will be called when the shader is compiled.
  163. * @param onError Callback that will be called if an error occurs during shader compilation.
  164. * @param indexParameters Parameters to be used with Babylons include syntax to iterate over an array (eg. {lights: 10})
  165. */
  166. constructor(baseName: any, attributesNamesOrOptions: string[] | IEffectCreationOptions, uniformsNamesOrEngine: string[] | ThinEngine, samplers: Nullable<string[]> = null,
  167. engine?: ThinEngine, defines: Nullable<string> = null,
  168. fallbacks: Nullable<IEffectFallbacks> = null, onCompiled: Nullable<(effect: Effect) => void> = null, onError: Nullable<(effect: Effect, errors: string) => void> = null, indexParameters?: any) {
  169. this.name = baseName;
  170. if ((<IEffectCreationOptions>attributesNamesOrOptions).attributes) {
  171. var options = <IEffectCreationOptions>attributesNamesOrOptions;
  172. this._engine = <Engine>uniformsNamesOrEngine;
  173. this._attributesNames = options.attributes;
  174. this._uniformsNames = options.uniformsNames.concat(options.samplers);
  175. this._samplerList = options.samplers.slice();
  176. this.defines = options.defines;
  177. this.onError = options.onError;
  178. this.onCompiled = options.onCompiled;
  179. this._fallbacks = options.fallbacks;
  180. this._indexParameters = options.indexParameters;
  181. this._transformFeedbackVaryings = options.transformFeedbackVaryings || null;
  182. if (options.uniformBuffersNames) {
  183. for (var i = 0; i < options.uniformBuffersNames.length; i++) {
  184. this._uniformBuffersNames[options.uniformBuffersNames[i]] = i;
  185. }
  186. }
  187. } else {
  188. this._engine = <Engine>engine;
  189. this.defines = (defines == null ? "" : defines);
  190. this._uniformsNames = (<string[]>uniformsNamesOrEngine).concat(<string[]>samplers);
  191. this._samplerList = samplers ? <string[]>samplers.slice() : [];
  192. this._attributesNames = (<string[]>attributesNamesOrOptions);
  193. this.onError = onError;
  194. this.onCompiled = onCompiled;
  195. this._indexParameters = indexParameters;
  196. this._fallbacks = fallbacks;
  197. }
  198. this.uniqueId = Effect._uniqueIdSeed++;
  199. var vertexSource: any;
  200. var fragmentSource: any;
  201. if (baseName.vertexSource) {
  202. vertexSource = "source:" + baseName.vertexSource;
  203. } else if (baseName.vertexElement) {
  204. vertexSource = document.getElementById(baseName.vertexElement);
  205. if (!vertexSource) {
  206. vertexSource = baseName.vertexElement;
  207. }
  208. } else {
  209. vertexSource = baseName.vertex || baseName;
  210. }
  211. if (baseName.fragmentSource) {
  212. fragmentSource = "source:" + baseName.fragmentSource;
  213. } else if (baseName.fragmentElement) {
  214. fragmentSource = document.getElementById(baseName.fragmentElement);
  215. if (!fragmentSource) {
  216. fragmentSource = baseName.fragmentElement;
  217. }
  218. } else {
  219. fragmentSource = baseName.fragment || baseName;
  220. }
  221. let processorOptions = {
  222. defines: this.defines.split("\n"),
  223. indexParameters: this._indexParameters,
  224. isFragment: false,
  225. shouldUseHighPrecisionShader: this._engine._shouldUseHighPrecisionShader,
  226. processor: this._engine._shaderProcessor,
  227. supportsUniformBuffers: this._engine.supportsUniformBuffers,
  228. shadersRepository: Effect.ShadersRepository,
  229. includesShadersStore: Effect.IncludesShadersStore,
  230. version: (this._engine.webGLVersion * 100).toString(),
  231. platformName: this._engine.webGLVersion >= 2 ? "WEBGL2" : "WEBGL1"
  232. };
  233. this._loadShader(vertexSource, "Vertex", "", (vertexCode) => {
  234. this._loadShader(fragmentSource, "Fragment", "Pixel", (fragmentCode) => {
  235. ShaderProcessor.Process(vertexCode, processorOptions, (migratedVertexCode) => {
  236. processorOptions.isFragment = true;
  237. ShaderProcessor.Process(fragmentCode, processorOptions, (migratedFragmentCode) => {
  238. this._useFinalCode(migratedVertexCode, migratedFragmentCode, baseName);
  239. });
  240. });
  241. });
  242. });
  243. }
  244. private _useFinalCode(migratedVertexCode: string, migratedFragmentCode: string, baseName: any) {
  245. if (baseName) {
  246. var vertex = baseName.vertexElement || baseName.vertex || baseName.spectorName || baseName;
  247. var fragment = baseName.fragmentElement || baseName.fragment || baseName.spectorName || baseName;
  248. this._vertexSourceCode = "#define SHADER_NAME vertex:" + vertex + "\n" + migratedVertexCode;
  249. this._fragmentSourceCode = "#define SHADER_NAME fragment:" + fragment + "\n" + migratedFragmentCode;
  250. } else {
  251. this._vertexSourceCode = migratedVertexCode;
  252. this._fragmentSourceCode = migratedFragmentCode;
  253. }
  254. this._prepareEffect();
  255. }
  256. /**
  257. * Unique key for this effect
  258. */
  259. public get key(): string {
  260. return this._key;
  261. }
  262. /**
  263. * If the effect has been compiled and prepared.
  264. * @returns if the effect is compiled and prepared.
  265. */
  266. public isReady(): boolean {
  267. try {
  268. return this._isReadyInternal();
  269. }
  270. catch {
  271. return false;
  272. }
  273. }
  274. private _isReadyInternal(): boolean {
  275. if (this._isReady) {
  276. return true;
  277. }
  278. if (this._pipelineContext) {
  279. return this._pipelineContext.isReady;
  280. }
  281. return false;
  282. }
  283. /**
  284. * The engine the effect was initialized with.
  285. * @returns the engine.
  286. */
  287. public getEngine(): Engine {
  288. return this._engine;
  289. }
  290. /**
  291. * The pipeline context for this effect
  292. * @returns the associated pipeline context
  293. */
  294. public getPipelineContext(): Nullable<IPipelineContext> {
  295. return this._pipelineContext;
  296. }
  297. /**
  298. * The set of names of attribute variables for the shader.
  299. * @returns An array of attribute names.
  300. */
  301. public getAttributesNames(): string[] {
  302. return this._attributesNames;
  303. }
  304. /**
  305. * Returns the attribute at the given index.
  306. * @param index The index of the attribute.
  307. * @returns The location of the attribute.
  308. */
  309. public getAttributeLocation(index: number): number {
  310. return this._attributes[index];
  311. }
  312. /**
  313. * Returns the attribute based on the name of the variable.
  314. * @param name of the attribute to look up.
  315. * @returns the attribute location.
  316. */
  317. public getAttributeLocationByName(name: string): number {
  318. var index = this._attributesNames.indexOf(name);
  319. return this._attributes[index];
  320. }
  321. /**
  322. * The number of attributes.
  323. * @returns the numnber of attributes.
  324. */
  325. public getAttributesCount(): number {
  326. return this._attributes.length;
  327. }
  328. /**
  329. * Gets the index of a uniform variable.
  330. * @param uniformName of the uniform to look up.
  331. * @returns the index.
  332. */
  333. public getUniformIndex(uniformName: string): number {
  334. return this._uniformsNames.indexOf(uniformName);
  335. }
  336. /**
  337. * Returns the attribute based on the name of the variable.
  338. * @param uniformName of the uniform to look up.
  339. * @returns the location of the uniform.
  340. */
  341. public getUniform(uniformName: string): Nullable<WebGLUniformLocation> {
  342. return this._uniforms[uniformName];
  343. }
  344. /**
  345. * Returns an array of sampler variable names
  346. * @returns The array of sampler variable neames.
  347. */
  348. public getSamplers(): string[] {
  349. return this._samplerList;
  350. }
  351. /**
  352. * The error from the last compilation.
  353. * @returns the error string.
  354. */
  355. public getCompilationError(): string {
  356. return this._compilationError;
  357. }
  358. /**
  359. * Gets a boolean indicating that all fallbacks were used during compilation
  360. * @returns true if all fallbacks were used
  361. */
  362. public allFallbacksProcessed(): boolean {
  363. return this._allFallbacksProcessed;
  364. }
  365. /**
  366. * Adds a callback to the onCompiled observable and call the callback imediatly if already ready.
  367. * @param func The callback to be used.
  368. */
  369. public executeWhenCompiled(func: (effect: Effect) => void): void {
  370. if (this.isReady()) {
  371. func(this);
  372. return;
  373. }
  374. this.onCompileObservable.add((effect) => {
  375. func(effect);
  376. });
  377. if (!this._pipelineContext || this._pipelineContext.isAsync) {
  378. setTimeout(() => {
  379. this._checkIsReady();
  380. }, 16);
  381. }
  382. }
  383. private _checkIsReady() {
  384. try {
  385. if (this._isReadyInternal()) {
  386. return;
  387. }
  388. } catch (e) {
  389. this._processCompilationErrors(e);
  390. return;
  391. }
  392. setTimeout(() => {
  393. this._checkIsReady();
  394. }, 16);
  395. }
  396. private _loadShader(shader: any, key: string, optionalKey: string, callback: (data: any) => void): void {
  397. if (typeof(HTMLElement) !== "undefined") {
  398. // DOM element ?
  399. if (shader instanceof HTMLElement) {
  400. var shaderCode = DomManagement.GetDOMTextContent(shader);
  401. callback(shaderCode);
  402. return;
  403. }
  404. }
  405. // Direct source ?
  406. if (shader.substr(0, 7) === "source:") {
  407. callback(shader.substr(7));
  408. return;
  409. }
  410. // Base64 encoded ?
  411. if (shader.substr(0, 7) === "base64:") {
  412. var shaderBinary = window.atob(shader.substr(7));
  413. callback(shaderBinary);
  414. return;
  415. }
  416. // Is in local store ?
  417. if (Effect.ShadersStore[shader + key + "Shader"]) {
  418. callback(Effect.ShadersStore[shader + key + "Shader"]);
  419. return;
  420. }
  421. if (optionalKey && Effect.ShadersStore[shader + optionalKey + "Shader"]) {
  422. callback(Effect.ShadersStore[shader + optionalKey + "Shader"]);
  423. return;
  424. }
  425. var shaderUrl;
  426. if (shader[0] === "." || shader[0] === "/" || shader.indexOf("http") > -1) {
  427. shaderUrl = shader;
  428. } else {
  429. shaderUrl = Effect.ShadersRepository + shader;
  430. }
  431. // Vertex shader
  432. this._engine._loadFile(shaderUrl + "." + key.toLowerCase() + ".fx", callback);
  433. }
  434. /**
  435. * Recompiles the webGL program
  436. * @param vertexSourceCode The source code for the vertex shader.
  437. * @param fragmentSourceCode The source code for the fragment shader.
  438. * @param onCompiled Callback called when completed.
  439. * @param onError Callback called on error.
  440. * @hidden
  441. */
  442. public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (pipelineContext: IPipelineContext) => void, onError: (message: string) => void) {
  443. this._isReady = false;
  444. this._vertexSourceCodeOverride = vertexSourceCode;
  445. this._fragmentSourceCodeOverride = fragmentSourceCode;
  446. this.onError = (effect, error) => {
  447. if (onError) {
  448. onError(error);
  449. }
  450. };
  451. this.onCompiled = () => {
  452. var scenes = this.getEngine().scenes;
  453. for (var i = 0; i < scenes.length; i++) {
  454. scenes[i].markAllMaterialsAsDirty(Constants.MATERIAL_AllDirtyFlag);
  455. }
  456. this._pipelineContext!._handlesSpectorRebuildCallback(onCompiled);
  457. };
  458. this._fallbacks = null;
  459. this._prepareEffect();
  460. }
  461. /**
  462. * Prepares the effect
  463. * @hidden
  464. */
  465. public _prepareEffect() {
  466. let attributesNames = this._attributesNames;
  467. let defines = this.defines;
  468. this._valueCache = {};
  469. var previousPipelineContext = this._pipelineContext;
  470. try {
  471. let engine = this._engine;
  472. this._pipelineContext = engine.createPipelineContext();
  473. let rebuildRebind = this._rebuildProgram.bind(this);
  474. if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
  475. engine._preparePipelineContext(this._pipelineContext, this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, true, rebuildRebind, null, this._transformFeedbackVaryings);
  476. }
  477. else {
  478. engine._preparePipelineContext(this._pipelineContext, this._vertexSourceCode, this._fragmentSourceCode, false, rebuildRebind, defines, this._transformFeedbackVaryings);
  479. }
  480. engine._executeWhenRenderingStateIsCompiled(this._pipelineContext, () => {
  481. if (engine.supportsUniformBuffers) {
  482. for (var name in this._uniformBuffersNames) {
  483. this.bindUniformBlock(name, this._uniformBuffersNames[name]);
  484. }
  485. }
  486. let uniforms = engine.getUniforms(this._pipelineContext!, this._uniformsNames);
  487. uniforms.forEach((uniform, index) => {
  488. this._uniforms[this._uniformsNames[index]] = uniform;
  489. });
  490. this._attributes = engine.getAttributes(this._pipelineContext!, attributesNames);
  491. var index: number;
  492. for (index = 0; index < this._samplerList.length; index++) {
  493. var sampler = this.getUniform(this._samplerList[index]);
  494. if (sampler == null) {
  495. this._samplerList.splice(index, 1);
  496. index--;
  497. }
  498. }
  499. this._samplerList.forEach((name, index) => {
  500. this._samplers[name] = index;
  501. });
  502. engine.bindSamplers(this);
  503. this._compilationError = "";
  504. this._isReady = true;
  505. if (this.onCompiled) {
  506. this.onCompiled(this);
  507. }
  508. this.onCompileObservable.notifyObservers(this);
  509. this.onCompileObservable.clear();
  510. // Unbind mesh reference in fallbacks
  511. if (this._fallbacks) {
  512. this._fallbacks.unBindMesh();
  513. }
  514. if (previousPipelineContext) {
  515. this.getEngine()._deletePipelineContext(previousPipelineContext);
  516. }
  517. });
  518. if (this._pipelineContext.isAsync) {
  519. this._checkIsReady();
  520. }
  521. } catch (e) {
  522. this._processCompilationErrors(e, previousPipelineContext);
  523. }
  524. }
  525. private _processCompilationErrors(e: any, previousPipelineContext: Nullable<IPipelineContext> = null) {
  526. this._compilationError = e.message;
  527. let attributesNames = this._attributesNames;
  528. let fallbacks = this._fallbacks;
  529. // Let's go through fallbacks then
  530. Logger.Error("Unable to compile effect:");
  531. Logger.Error("Uniforms: " + this._uniformsNames.map(function(uniform) {
  532. return " " + uniform;
  533. }));
  534. Logger.Error("Attributes: " + attributesNames.map(function(attribute) {
  535. return " " + attribute;
  536. }));
  537. Logger.Error("Defines:\r\n" + this.defines);
  538. Logger.Error("Error: " + this._compilationError);
  539. if (previousPipelineContext) {
  540. this._pipelineContext = previousPipelineContext;
  541. this._isReady = true;
  542. if (this.onError) {
  543. this.onError(this, this._compilationError);
  544. }
  545. this.onErrorObservable.notifyObservers(this);
  546. }
  547. if (fallbacks) {
  548. this._pipelineContext = null;
  549. if (fallbacks.hasMoreFallbacks) {
  550. this._allFallbacksProcessed = false;
  551. Logger.Error("Trying next fallback.");
  552. this.defines = fallbacks.reduce(this.defines, this);
  553. this._prepareEffect();
  554. } else { // Sorry we did everything we can
  555. this._allFallbacksProcessed = true;
  556. if (this.onError) {
  557. this.onError(this, this._compilationError);
  558. }
  559. this.onErrorObservable.notifyObservers(this);
  560. this.onErrorObservable.clear();
  561. // Unbind mesh reference in fallbacks
  562. if (this._fallbacks) {
  563. this._fallbacks.unBindMesh();
  564. }
  565. }
  566. } else {
  567. this._allFallbacksProcessed = true;
  568. }
  569. }
  570. /**
  571. * Checks if the effect is supported. (Must be called after compilation)
  572. */
  573. public get isSupported(): boolean {
  574. return this._compilationError === "";
  575. }
  576. /**
  577. * Binds a texture to the engine to be used as output of the shader.
  578. * @param channel Name of the output variable.
  579. * @param texture Texture to bind.
  580. * @hidden
  581. */
  582. public _bindTexture(channel: string, texture: InternalTexture): void {
  583. this._engine._bindTexture(this._samplers[channel], texture);
  584. }
  585. /**
  586. * Sets a texture on the engine to be used in the shader.
  587. * @param channel Name of the sampler variable.
  588. * @param texture Texture to set.
  589. */
  590. public setTexture(channel: string, texture: Nullable<BaseTexture>): void {
  591. this._engine.setTexture(this._samplers[channel], this._uniforms[channel], texture);
  592. }
  593. /**
  594. * Sets a depth stencil texture from a render target on the engine to be used in the shader.
  595. * @param channel Name of the sampler variable.
  596. * @param texture Texture to set.
  597. */
  598. public setDepthStencilTexture(channel: string, texture: Nullable<RenderTargetTexture>): void {
  599. this._engine.setDepthStencilTexture(this._samplers[channel], this._uniforms[channel], texture);
  600. }
  601. /**
  602. * Sets an array of textures on the engine to be used in the shader.
  603. * @param channel Name of the variable.
  604. * @param textures Textures to set.
  605. */
  606. public setTextureArray(channel: string, textures: BaseTexture[]): void {
  607. let exName = channel + "Ex";
  608. if (this._samplerList.indexOf(exName + "0") === -1) {
  609. const initialPos = this._samplerList.indexOf(channel);
  610. for (var index = 1; index < textures.length; index++) {
  611. const currentExName = exName + (index - 1).toString();
  612. this._samplerList.splice(initialPos + index, 0, currentExName);
  613. }
  614. // Reset every channels
  615. let channelIndex = 0;
  616. for (var key of this._samplerList) {
  617. this._samplers[key] = channelIndex;
  618. channelIndex += 1;
  619. }
  620. }
  621. this._engine.setTextureArray(this._samplers[channel], this._uniforms[channel], textures);
  622. }
  623. /**
  624. * Sets a texture to be the input of the specified post process. (To use the output, pass in the next post process in the pipeline)
  625. * @param channel Name of the sampler variable.
  626. * @param postProcess Post process to get the input texture from.
  627. */
  628. public setTextureFromPostProcess(channel: string, postProcess: Nullable<PostProcess>): void {
  629. this._engine.setTextureFromPostProcess(this._samplers[channel], postProcess);
  630. }
  631. /**
  632. * (Warning! setTextureFromPostProcessOutput may be desired instead)
  633. * Sets the input texture of the passed in post process to be input of this effect. (To use the output of the passed in post process use setTextureFromPostProcessOutput)
  634. * @param channel Name of the sampler variable.
  635. * @param postProcess Post process to get the output texture from.
  636. */
  637. public setTextureFromPostProcessOutput(channel: string, postProcess: Nullable<PostProcess>): void {
  638. this._engine.setTextureFromPostProcessOutput(this._samplers[channel], postProcess);
  639. }
  640. /** @hidden */
  641. public _cacheMatrix(uniformName: string, matrix: IMatrixLike): boolean {
  642. var cache = this._valueCache[uniformName];
  643. var flag = matrix.updateFlag;
  644. if (cache !== undefined && cache === flag) {
  645. return false;
  646. }
  647. this._valueCache[uniformName] = flag;
  648. return true;
  649. }
  650. /** @hidden */
  651. public _cacheFloat2(uniformName: string, x: number, y: number): boolean {
  652. var cache = this._valueCache[uniformName];
  653. if (!cache) {
  654. cache = [x, y];
  655. this._valueCache[uniformName] = cache;
  656. return true;
  657. }
  658. var changed = false;
  659. if (cache[0] !== x) {
  660. cache[0] = x;
  661. changed = true;
  662. }
  663. if (cache[1] !== y) {
  664. cache[1] = y;
  665. changed = true;
  666. }
  667. return changed;
  668. }
  669. /** @hidden */
  670. public _cacheFloat3(uniformName: string, x: number, y: number, z: number): boolean {
  671. var cache = this._valueCache[uniformName];
  672. if (!cache) {
  673. cache = [x, y, z];
  674. this._valueCache[uniformName] = cache;
  675. return true;
  676. }
  677. var changed = false;
  678. if (cache[0] !== x) {
  679. cache[0] = x;
  680. changed = true;
  681. }
  682. if (cache[1] !== y) {
  683. cache[1] = y;
  684. changed = true;
  685. }
  686. if (cache[2] !== z) {
  687. cache[2] = z;
  688. changed = true;
  689. }
  690. return changed;
  691. }
  692. /** @hidden */
  693. public _cacheFloat4(uniformName: string, x: number, y: number, z: number, w: number): boolean {
  694. var cache = this._valueCache[uniformName];
  695. if (!cache) {
  696. cache = [x, y, z, w];
  697. this._valueCache[uniformName] = cache;
  698. return true;
  699. }
  700. var changed = false;
  701. if (cache[0] !== x) {
  702. cache[0] = x;
  703. changed = true;
  704. }
  705. if (cache[1] !== y) {
  706. cache[1] = y;
  707. changed = true;
  708. }
  709. if (cache[2] !== z) {
  710. cache[2] = z;
  711. changed = true;
  712. }
  713. if (cache[3] !== w) {
  714. cache[3] = w;
  715. changed = true;
  716. }
  717. return changed;
  718. }
  719. /**
  720. * Binds a buffer to a uniform.
  721. * @param buffer Buffer to bind.
  722. * @param name Name of the uniform variable to bind to.
  723. */
  724. public bindUniformBuffer(buffer: DataBuffer, name: string): void {
  725. let bufferName = this._uniformBuffersNames[name];
  726. if (bufferName === undefined || Effect._baseCache[bufferName] === buffer) {
  727. return;
  728. }
  729. Effect._baseCache[bufferName] = buffer;
  730. this._engine.bindUniformBufferBase(buffer, bufferName);
  731. }
  732. /**
  733. * Binds block to a uniform.
  734. * @param blockName Name of the block to bind.
  735. * @param index Index to bind.
  736. */
  737. public bindUniformBlock(blockName: string, index: number): void {
  738. this._engine.bindUniformBlock(this._pipelineContext!, blockName, index);
  739. }
  740. /**
  741. * Sets an interger value on a uniform variable.
  742. * @param uniformName Name of the variable.
  743. * @param value Value to be set.
  744. * @returns this effect.
  745. */
  746. public setInt(uniformName: string, value: number): Effect {
  747. var cache = this._valueCache[uniformName];
  748. if (cache !== undefined && cache === value) {
  749. return this;
  750. }
  751. this._valueCache[uniformName] = value;
  752. this._engine.setInt(this._uniforms[uniformName], value);
  753. return this;
  754. }
  755. /**
  756. * Sets an int array on a uniform variable.
  757. * @param uniformName Name of the variable.
  758. * @param array array to be set.
  759. * @returns this effect.
  760. */
  761. public setIntArray(uniformName: string, array: Int32Array): Effect {
  762. this._valueCache[uniformName] = null;
  763. this._engine.setIntArray(this._uniforms[uniformName], array);
  764. return this;
  765. }
  766. /**
  767. * Sets an int array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
  768. * @param uniformName Name of the variable.
  769. * @param array array to be set.
  770. * @returns this effect.
  771. */
  772. public setIntArray2(uniformName: string, array: Int32Array): Effect {
  773. this._valueCache[uniformName] = null;
  774. this._engine.setIntArray2(this._uniforms[uniformName], array);
  775. return this;
  776. }
  777. /**
  778. * Sets an int array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
  779. * @param uniformName Name of the variable.
  780. * @param array array to be set.
  781. * @returns this effect.
  782. */
  783. public setIntArray3(uniformName: string, array: Int32Array): Effect {
  784. this._valueCache[uniformName] = null;
  785. this._engine.setIntArray3(this._uniforms[uniformName], array);
  786. return this;
  787. }
  788. /**
  789. * Sets an int array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
  790. * @param uniformName Name of the variable.
  791. * @param array array to be set.
  792. * @returns this effect.
  793. */
  794. public setIntArray4(uniformName: string, array: Int32Array): Effect {
  795. this._valueCache[uniformName] = null;
  796. this._engine.setIntArray4(this._uniforms[uniformName], array);
  797. return this;
  798. }
  799. /**
  800. * Sets an float array on a uniform variable.
  801. * @param uniformName Name of the variable.
  802. * @param array array to be set.
  803. * @returns this effect.
  804. */
  805. public setFloatArray(uniformName: string, array: Float32Array): Effect {
  806. this._valueCache[uniformName] = null;
  807. this._engine.setFloatArray(this._uniforms[uniformName], array);
  808. return this;
  809. }
  810. /**
  811. * Sets an float array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
  812. * @param uniformName Name of the variable.
  813. * @param array array to be set.
  814. * @returns this effect.
  815. */
  816. public setFloatArray2(uniformName: string, array: Float32Array): Effect {
  817. this._valueCache[uniformName] = null;
  818. this._engine.setFloatArray2(this._uniforms[uniformName], array);
  819. return this;
  820. }
  821. /**
  822. * Sets an float array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
  823. * @param uniformName Name of the variable.
  824. * @param array array to be set.
  825. * @returns this effect.
  826. */
  827. public setFloatArray3(uniformName: string, array: Float32Array): Effect {
  828. this._valueCache[uniformName] = null;
  829. this._engine.setFloatArray3(this._uniforms[uniformName], array);
  830. return this;
  831. }
  832. /**
  833. * Sets an float array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
  834. * @param uniformName Name of the variable.
  835. * @param array array to be set.
  836. * @returns this effect.
  837. */
  838. public setFloatArray4(uniformName: string, array: Float32Array): Effect {
  839. this._valueCache[uniformName] = null;
  840. this._engine.setFloatArray4(this._uniforms[uniformName], array);
  841. return this;
  842. }
  843. /**
  844. * Sets an array on a uniform variable.
  845. * @param uniformName Name of the variable.
  846. * @param array array to be set.
  847. * @returns this effect.
  848. */
  849. public setArray(uniformName: string, array: number[]): Effect {
  850. this._valueCache[uniformName] = null;
  851. this._engine.setArray(this._uniforms[uniformName], array);
  852. return this;
  853. }
  854. /**
  855. * Sets an array 2 on a uniform variable. (Array is specified as single array eg. [1,2,3,4] will result in [[1,2],[3,4]] in the shader)
  856. * @param uniformName Name of the variable.
  857. * @param array array to be set.
  858. * @returns this effect.
  859. */
  860. public setArray2(uniformName: string, array: number[]): Effect {
  861. this._valueCache[uniformName] = null;
  862. this._engine.setArray2(this._uniforms[uniformName], array);
  863. return this;
  864. }
  865. /**
  866. * Sets an array 3 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6] will result in [[1,2,3],[4,5,6]] in the shader)
  867. * @param uniformName Name of the variable.
  868. * @param array array to be set.
  869. * @returns this effect.
  870. */
  871. public setArray3(uniformName: string, array: number[]): Effect {
  872. this._valueCache[uniformName] = null;
  873. this._engine.setArray3(this._uniforms[uniformName], array);
  874. return this;
  875. }
  876. /**
  877. * Sets an array 4 on a uniform variable. (Array is specified as single array eg. [1,2,3,4,5,6,7,8] will result in [[1,2,3,4],[5,6,7,8]] in the shader)
  878. * @param uniformName Name of the variable.
  879. * @param array array to be set.
  880. * @returns this effect.
  881. */
  882. public setArray4(uniformName: string, array: number[]): Effect {
  883. this._valueCache[uniformName] = null;
  884. this._engine.setArray4(this._uniforms[uniformName], array);
  885. return this;
  886. }
  887. /**
  888. * Sets matrices on a uniform variable.
  889. * @param uniformName Name of the variable.
  890. * @param matrices matrices to be set.
  891. * @returns this effect.
  892. */
  893. public setMatrices(uniformName: string, matrices: Float32Array): Effect {
  894. if (!matrices) {
  895. return this;
  896. }
  897. this._valueCache[uniformName] = null;
  898. this._engine.setMatrices(this._uniforms[uniformName], matrices);
  899. return this;
  900. }
  901. /**
  902. * Sets matrix on a uniform variable.
  903. * @param uniformName Name of the variable.
  904. * @param matrix matrix to be set.
  905. * @returns this effect.
  906. */
  907. public setMatrix(uniformName: string, matrix: IMatrixLike): Effect {
  908. if (this._cacheMatrix(uniformName, matrix)) {
  909. this._engine.setMatrices(this._uniforms[uniformName], matrix.toArray() as Float32Array);
  910. }
  911. return this;
  912. }
  913. /**
  914. * Sets a 3x3 matrix on a uniform variable. (Speicified as [1,2,3,4,5,6,7,8,9] will result in [1,2,3][4,5,6][7,8,9] matrix)
  915. * @param uniformName Name of the variable.
  916. * @param matrix matrix to be set.
  917. * @returns this effect.
  918. */
  919. public setMatrix3x3(uniformName: string, matrix: Float32Array): Effect {
  920. this._valueCache[uniformName] = null;
  921. this._engine.setMatrix3x3(this._uniforms[uniformName], matrix);
  922. return this;
  923. }
  924. /**
  925. * Sets a 2x2 matrix on a uniform variable. (Speicified as [1,2,3,4] will result in [1,2][3,4] matrix)
  926. * @param uniformName Name of the variable.
  927. * @param matrix matrix to be set.
  928. * @returns this effect.
  929. */
  930. public setMatrix2x2(uniformName: string, matrix: Float32Array): Effect {
  931. this._valueCache[uniformName] = null;
  932. this._engine.setMatrix2x2(this._uniforms[uniformName], matrix);
  933. return this;
  934. }
  935. /**
  936. * Sets a float on a uniform variable.
  937. * @param uniformName Name of the variable.
  938. * @param value value to be set.
  939. * @returns this effect.
  940. */
  941. public setFloat(uniformName: string, value: number): Effect {
  942. var cache = this._valueCache[uniformName];
  943. if (cache !== undefined && cache === value) {
  944. return this;
  945. }
  946. this._valueCache[uniformName] = value;
  947. this._engine.setFloat(this._uniforms[uniformName], value);
  948. return this;
  949. }
  950. /**
  951. * Sets a boolean on a uniform variable.
  952. * @param uniformName Name of the variable.
  953. * @param bool value to be set.
  954. * @returns this effect.
  955. */
  956. public setBool(uniformName: string, bool: boolean): Effect {
  957. var cache = this._valueCache[uniformName];
  958. if (cache !== undefined && cache === bool) {
  959. return this;
  960. }
  961. this._valueCache[uniformName] = bool;
  962. this._engine.setBool(this._uniforms[uniformName], bool ? 1 : 0);
  963. return this;
  964. }
  965. /**
  966. * Sets a Vector2 on a uniform variable.
  967. * @param uniformName Name of the variable.
  968. * @param vector2 vector2 to be set.
  969. * @returns this effect.
  970. */
  971. public setVector2(uniformName: string, vector2: IVector2Like): Effect {
  972. if (this._cacheFloat2(uniformName, vector2.x, vector2.y)) {
  973. this._engine.setFloat2(this._uniforms[uniformName], vector2.x, vector2.y);
  974. }
  975. return this;
  976. }
  977. /**
  978. * Sets a float2 on a uniform variable.
  979. * @param uniformName Name of the variable.
  980. * @param x First float in float2.
  981. * @param y Second float in float2.
  982. * @returns this effect.
  983. */
  984. public setFloat2(uniformName: string, x: number, y: number): Effect {
  985. if (this._cacheFloat2(uniformName, x, y)) {
  986. this._engine.setFloat2(this._uniforms[uniformName], x, y);
  987. }
  988. return this;
  989. }
  990. /**
  991. * Sets a Vector3 on a uniform variable.
  992. * @param uniformName Name of the variable.
  993. * @param vector3 Value to be set.
  994. * @returns this effect.
  995. */
  996. public setVector3(uniformName: string, vector3: IVector3Like): Effect {
  997. if (this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z)) {
  998. this._engine.setFloat3(this._uniforms[uniformName], vector3.x, vector3.y, vector3.z);
  999. }
  1000. return this;
  1001. }
  1002. /**
  1003. * Sets a float3 on a uniform variable.
  1004. * @param uniformName Name of the variable.
  1005. * @param x First float in float3.
  1006. * @param y Second float in float3.
  1007. * @param z Third float in float3.
  1008. * @returns this effect.
  1009. */
  1010. public setFloat3(uniformName: string, x: number, y: number, z: number): Effect {
  1011. if (this._cacheFloat3(uniformName, x, y, z)) {
  1012. this._engine.setFloat3(this._uniforms[uniformName], x, y, z);
  1013. }
  1014. return this;
  1015. }
  1016. /**
  1017. * Sets a Vector4 on a uniform variable.
  1018. * @param uniformName Name of the variable.
  1019. * @param vector4 Value to be set.
  1020. * @returns this effect.
  1021. */
  1022. public setVector4(uniformName: string, vector4: IVector4Like): Effect {
  1023. if (this._cacheFloat4(uniformName, vector4.x, vector4.y, vector4.z, vector4.w)) {
  1024. this._engine.setFloat4(this._uniforms[uniformName], vector4.x, vector4.y, vector4.z, vector4.w);
  1025. }
  1026. return this;
  1027. }
  1028. /**
  1029. * Sets a float4 on a uniform variable.
  1030. * @param uniformName Name of the variable.
  1031. * @param x First float in float4.
  1032. * @param y Second float in float4.
  1033. * @param z Third float in float4.
  1034. * @param w Fourth float in float4.
  1035. * @returns this effect.
  1036. */
  1037. public setFloat4(uniformName: string, x: number, y: number, z: number, w: number): Effect {
  1038. if (this._cacheFloat4(uniformName, x, y, z, w)) {
  1039. this._engine.setFloat4(this._uniforms[uniformName], x, y, z, w);
  1040. }
  1041. return this;
  1042. }
  1043. /**
  1044. * Sets a Color3 on a uniform variable.
  1045. * @param uniformName Name of the variable.
  1046. * @param color3 Value to be set.
  1047. * @returns this effect.
  1048. */
  1049. public setColor3(uniformName: string, color3: IColor3Like): Effect {
  1050. if (this._cacheFloat3(uniformName, color3.r, color3.g, color3.b)) {
  1051. this._engine.setFloat3(this._uniforms[uniformName], color3.r, color3.g, color3.b);
  1052. }
  1053. return this;
  1054. }
  1055. /**
  1056. * Sets a Color4 on a uniform variable.
  1057. * @param uniformName Name of the variable.
  1058. * @param color3 Value to be set.
  1059. * @param alpha Alpha value to be set.
  1060. * @returns this effect.
  1061. */
  1062. public setColor4(uniformName: string, color3: IColor3Like, alpha: number): Effect {
  1063. if (this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha)) {
  1064. this._engine.setFloat4(this._uniforms[uniformName], color3.r, color3.g, color3.b, alpha);
  1065. }
  1066. return this;
  1067. }
  1068. /**
  1069. * Sets a Color4 on a uniform variable
  1070. * @param uniformName defines the name of the variable
  1071. * @param color4 defines the value to be set
  1072. * @returns this effect.
  1073. */
  1074. public setDirectColor4(uniformName: string, color4: IColor4Like): Effect {
  1075. if (this._cacheFloat4(uniformName, color4.r, color4.g, color4.b, color4.a)) {
  1076. this._engine.setDirectColor4(this._uniforms[uniformName], color4);
  1077. }
  1078. return this;
  1079. }
  1080. /** Release all associated resources */
  1081. public dispose() {
  1082. this._engine._releaseEffect(this);
  1083. }
  1084. /**
  1085. * This function will add a new shader to the shader store
  1086. * @param name the name of the shader
  1087. * @param pixelShader optional pixel shader content
  1088. * @param vertexShader optional vertex shader content
  1089. */
  1090. public static RegisterShader(name: string, pixelShader?: string, vertexShader?: string) {
  1091. if (pixelShader) {
  1092. Effect.ShadersStore[`${name}PixelShader`] = pixelShader;
  1093. }
  1094. if (vertexShader) {
  1095. Effect.ShadersStore[`${name}VertexShader`] = vertexShader;
  1096. }
  1097. }
  1098. /**
  1099. * Store of each shader (The can be looked up using effect.key)
  1100. */
  1101. public static ShadersStore: { [key: string]: string } = {};
  1102. /**
  1103. * Store of each included file for a shader (The can be looked up using effect.key)
  1104. */
  1105. public static IncludesShadersStore: { [key: string]: string } = {};
  1106. /**
  1107. * Resets the cache of effects.
  1108. */
  1109. public static ResetCache() {
  1110. Effect._baseCache = {};
  1111. }
  1112. }