babylon.shadowGenerator.ts 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. module BABYLON {
  2. /**
  3. * Interface to implement to create a shadow generator compatible with BJS.
  4. */
  5. export interface IShadowGenerator {
  6. getShadowMap(): RenderTargetTexture;
  7. getShadowMapForRendering(): RenderTargetTexture;
  8. isReady(subMesh: SubMesh, useInstances: boolean): boolean;
  9. prepareDefines(defines: MaterialDefines, lightIndex: number): void;
  10. bindShadowLight(lightIndex: string, effect: Effect): void;
  11. getTransformMatrix(): Matrix;
  12. recreateShadowMap(): void;
  13. forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void;
  14. serialize(): any;
  15. dispose(): void;
  16. }
  17. export class ShadowGenerator implements IShadowGenerator {
  18. private static _FILTER_NONE = 0;
  19. private static _FILTER_EXPONENTIALSHADOWMAP = 1;
  20. private static _FILTER_POISSONSAMPLING = 2;
  21. private static _FILTER_BLUREXPONENTIALSHADOWMAP = 3;
  22. private static _FILTER_CLOSEEXPONENTIALSHADOWMAP = 4;
  23. private static _FILTER_BLURCLOSEEXPONENTIALSHADOWMAP = 5;
  24. // Static
  25. public static get FILTER_NONE(): number {
  26. return ShadowGenerator._FILTER_NONE;
  27. }
  28. public static get FILTER_POISSONSAMPLING(): number {
  29. return ShadowGenerator._FILTER_POISSONSAMPLING;
  30. }
  31. public static get FILTER_EXPONENTIALSHADOWMAP(): number {
  32. return ShadowGenerator._FILTER_EXPONENTIALSHADOWMAP;
  33. }
  34. public static get FILTER_BLUREXPONENTIALSHADOWMAP(): number {
  35. return ShadowGenerator._FILTER_BLUREXPONENTIALSHADOWMAP;
  36. }
  37. public static get FILTER_CLOSEEXPONENTIALSHADOWMAP(): number {
  38. return ShadowGenerator._FILTER_CLOSEEXPONENTIALSHADOWMAP;
  39. }
  40. public static get FILTER_BLURCLOSEEXPONENTIALSHADOWMAP(): number {
  41. return ShadowGenerator._FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
  42. }
  43. // Members
  44. private _bias = 0.00005;
  45. public get bias(): number {
  46. return this._bias;
  47. }
  48. public set bias(bias: number) {
  49. this._bias = bias;
  50. }
  51. private _blurBoxOffset = 1;
  52. public get blurBoxOffset(): number {
  53. return this._blurBoxOffset;
  54. }
  55. public set blurBoxOffset(value: number) {
  56. if (this._blurBoxOffset === value) {
  57. return;
  58. }
  59. this._blurBoxOffset = value;
  60. this._disposeBlurPostProcesses();
  61. }
  62. private _blurScale = 2;
  63. public get blurScale(): number {
  64. return this._blurScale;
  65. }
  66. public set blurScale(value: number) {
  67. if (this._blurScale === value) {
  68. return;
  69. }
  70. this._blurScale = value;
  71. this._disposeBlurPostProcesses();
  72. }
  73. private _blurKernel = 1;
  74. public get blurKernel(): number {
  75. return this._blurKernel;
  76. }
  77. public set blurKernel(value: number) {
  78. if (this._blurKernel === value) {
  79. return;
  80. }
  81. this._blurKernel = value;
  82. this._disposeBlurPostProcesses();
  83. }
  84. private _useKernelBlur = false;
  85. public get useKernelBlur(): boolean {
  86. return this._useKernelBlur;
  87. }
  88. public set useKernelBlur(value: boolean) {
  89. if (this._useKernelBlur === value) {
  90. return;
  91. }
  92. this._useKernelBlur = value;
  93. this._disposeBlurPostProcesses();
  94. }
  95. private _depthScale: number;
  96. public get depthScale(): number {
  97. return this._depthScale !== undefined ? this._depthScale : this._light.getDepthScale();
  98. }
  99. public set depthScale(value: number) {
  100. this._depthScale = value;
  101. }
  102. private _filter = ShadowGenerator.FILTER_NONE;
  103. public get filter(): number {
  104. return this._filter;
  105. }
  106. public set filter(value: number) {
  107. // Blurring the cubemap is going to be too expensive. Reverting to unblurred version
  108. if (this._light.needCube()) {
  109. if (value === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
  110. this.useExponentialShadowMap = true;
  111. return;
  112. }
  113. else if (value === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
  114. this.useCloseExponentialShadowMap = true;
  115. return;
  116. }
  117. }
  118. if (this._filter === value) {
  119. return;
  120. }
  121. this._filter = value;
  122. this._disposeBlurPostProcesses();
  123. this._applyFilterValues();
  124. this._light._markMeshesAsLightDirty();
  125. }
  126. public get usePoissonSampling(): boolean {
  127. return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
  128. }
  129. public set usePoissonSampling(value: boolean) {
  130. if (!value && this.filter!== ShadowGenerator.FILTER_POISSONSAMPLING) {
  131. return;
  132. }
  133. this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
  134. }
  135. public get useVarianceShadowMap(): boolean {
  136. Tools.Warn("VSM are now replaced by ESM. Please use useExponentialShadowMap instead.");
  137. return this.useExponentialShadowMap;
  138. }
  139. public set useVarianceShadowMap(value: boolean) {
  140. Tools.Warn("VSM are now replaced by ESM. Please use useExponentialShadowMap instead.");
  141. this.useExponentialShadowMap = value;
  142. }
  143. public get useBlurVarianceShadowMap(): boolean {
  144. Tools.Warn("VSM are now replaced by ESM. Please use useBlurExponentialShadowMap instead.");
  145. return this.useBlurExponentialShadowMap;
  146. }
  147. public set useBlurVarianceShadowMap(value: boolean) {
  148. Tools.Warn("VSM are now replaced by ESM. Please use useBlurExponentialShadowMap instead.");
  149. this.useBlurExponentialShadowMap = value;
  150. }
  151. public get useExponentialShadowMap(): boolean {
  152. return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
  153. }
  154. public set useExponentialShadowMap(value: boolean) {
  155. if (!value && this.filter!== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
  156. return;
  157. }
  158. this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
  159. }
  160. public get useBlurExponentialShadowMap(): boolean {
  161. return this.filter === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP;
  162. }
  163. public set useBlurExponentialShadowMap(value: boolean) {
  164. if (!value && this.filter!== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
  165. return;
  166. }
  167. this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
  168. }
  169. public get useCloseExponentialShadowMap(): boolean {
  170. return this.filter === ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP;
  171. }
  172. public set useCloseExponentialShadowMap(value: boolean) {
  173. if (!value && this.filter!== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
  174. return;
  175. }
  176. this.filter = (value ? ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
  177. }
  178. public get useBlurCloseExponentialShadowMap(): boolean {
  179. return this.filter === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
  180. }
  181. public set useBlurCloseExponentialShadowMap(value: boolean) {
  182. if (!value && this.filter!== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
  183. return;
  184. }
  185. this.filter = (value ? ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
  186. }
  187. private _darkness = 0;
  188. /**
  189. * Returns the darkness value (float).
  190. */
  191. public getDarkness(): number {
  192. return this._darkness;
  193. }
  194. /**
  195. * Sets the ShadowGenerator darkness value (float <= 1.0).
  196. * Returns the ShadowGenerator.
  197. */
  198. public setDarkness(darkness: number): ShadowGenerator {
  199. if (darkness >= 1.0)
  200. this._darkness = 1.0;
  201. else if (darkness <= 0.0)
  202. this._darkness = 0.0;
  203. else
  204. this._darkness = darkness;
  205. return this;
  206. }
  207. private _transparencyShadow = false;
  208. /**
  209. * Sets the ability to have transparent shadow (boolean).
  210. * Returns the ShadowGenerator.
  211. */
  212. public setTransparencyShadow(hasShadow: boolean): ShadowGenerator {
  213. this._transparencyShadow = hasShadow;
  214. return this;
  215. }
  216. private _shadowMap: RenderTargetTexture;
  217. private _shadowMap2: RenderTargetTexture;
  218. /**
  219. * Returns a RenderTargetTexture object : the shadow map texture.
  220. */
  221. public getShadowMap(): RenderTargetTexture {
  222. return this._shadowMap;
  223. }
  224. /**
  225. * Returns the most ready computed shadow map as a RenderTargetTexture object.
  226. */
  227. public getShadowMapForRendering(): RenderTargetTexture {
  228. if (this._shadowMap2) {
  229. return this._shadowMap2;
  230. }
  231. return this._shadowMap;
  232. }
  233. /**
  234. * Controls the extent to which the shadows fade out at the edge of the frustum
  235. * Used only by directionals and spots
  236. */
  237. public frustumEdgeFalloff = 0;
  238. private _light: IShadowLight;
  239. /**
  240. * Returns the associated light object.
  241. */
  242. public getLight(): IShadowLight {
  243. return this._light;
  244. }
  245. public forceBackFacesOnly = false;
  246. private _scene: Scene;
  247. private _lightDirection = Vector3.Zero();
  248. private _effect: Effect;
  249. private _viewMatrix = Matrix.Zero();
  250. private _projectionMatrix = Matrix.Zero();
  251. private _transformMatrix = Matrix.Zero();
  252. private _worldViewProjection = Matrix.Zero();
  253. private _cachedPosition: Vector3;
  254. private _cachedDirection: Vector3;
  255. private _cachedDefines: string;
  256. private _currentRenderID: number;
  257. private _downSamplePostprocess: PassPostProcess;
  258. private _boxBlurPostprocess: PostProcess;
  259. private _kernelBlurXPostprocess: PostProcess;
  260. private _kernelBlurYPostprocess: PostProcess;
  261. private _blurPostProcesses: PostProcess[];
  262. private _mapSize: number;
  263. private _currentFaceIndex = 0;
  264. private _currentFaceIndexCache = 0;
  265. private _textureType: number;
  266. private _isCube = false;
  267. private _defaultTextureMatrix = Matrix.Identity();
  268. /**
  269. * Creates a ShadowGenerator object.
  270. * A ShadowGenerator is the required tool to use the shadows.
  271. * Each light casting shadows needs to use its own ShadowGenerator.
  272. * Required parameters :
  273. * - `mapSize` (integer): the size of the texture what stores the shadows. Example : 1024.
  274. * - `light`: the light object generating the shadows.
  275. * - `useFullFloatFirst`: by default the generator will try to use half float textures but if you need precision (for self shadowing for instance), you can use this option to enforce full float texture.
  276. * Documentation : http://doc.babylonjs.com/tutorials/shadows
  277. */
  278. constructor(mapSize: number, light: IShadowLight, useFullFloatFirst?: boolean) {
  279. this._mapSize = mapSize;
  280. this._light = light;
  281. this._scene = light.getScene();
  282. light._shadowGenerator = this;
  283. // Texture type fallback from float to int if not supported.
  284. var caps = this._scene.getEngine().getCaps();
  285. if (!useFullFloatFirst) {
  286. if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
  287. this._textureType = Engine.TEXTURETYPE_HALF_FLOAT;
  288. }
  289. else if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
  290. this._textureType = Engine.TEXTURETYPE_FLOAT;
  291. }
  292. else {
  293. this._textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
  294. }
  295. } else {
  296. if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
  297. this._textureType = Engine.TEXTURETYPE_FLOAT;
  298. }
  299. else if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
  300. this._textureType = Engine.TEXTURETYPE_HALF_FLOAT;
  301. }
  302. else {
  303. this._textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
  304. }
  305. }
  306. this._initializeGenerator();
  307. }
  308. private _initializeGenerator(): void {
  309. this._light._markMeshesAsLightDirty();
  310. this._initializeShadowMap();
  311. }
  312. private _initializeShadowMap(): void {
  313. // Render target
  314. this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
  315. this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
  316. this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
  317. this._shadowMap.anisotropicFilteringLevel = 1;
  318. this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  319. this._shadowMap.renderParticles = false;
  320. // Record Face Index before render.
  321. this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
  322. this._currentFaceIndex = faceIndex;
  323. });
  324. // Custom render function.
  325. this._shadowMap.customRenderFunction = this._renderForShadowMap.bind(this);
  326. // Blur if required afer render.
  327. this._shadowMap.onAfterUnbindObservable.add(() => {
  328. if (!this.useBlurExponentialShadowMap && !this.useBlurCloseExponentialShadowMap) {
  329. return;
  330. }
  331. if (!this._blurPostProcesses) {
  332. this._initializeBlurRTTAndPostProcesses();
  333. }
  334. this._scene.postProcessManager.directRender(this._blurPostProcesses, this.getShadowMapForRendering().getInternalTexture());
  335. });
  336. // Clear according to the chosen filter.
  337. this._shadowMap.onClearObservable.add((engine: Engine) => {
  338. if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  339. engine.clear(new Color4(0, 0, 0, 0), true, true, true);
  340. }
  341. else {
  342. engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
  343. }
  344. });
  345. }
  346. private _initializeBlurRTTAndPostProcesses(): void {
  347. var engine = this._scene.getEngine();
  348. var targetSize = this._mapSize / this.blurScale;
  349. if (!this.useKernelBlur || this.blurScale !== 1.0) {
  350. this._shadowMap2 = new RenderTargetTexture(this._light.name + "_shadowMap2", targetSize, this._scene, false, true, this._textureType);
  351. this._shadowMap2.wrapU = Texture.CLAMP_ADDRESSMODE;
  352. this._shadowMap2.wrapV = Texture.CLAMP_ADDRESSMODE;
  353. this._shadowMap2.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  354. }
  355. if (this.useKernelBlur) {
  356. this._kernelBlurXPostprocess = new BlurPostProcess(this._light.name + "KernelBlurX", new Vector2(1, 0), this.blurKernel, 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._textureType);
  357. this._kernelBlurXPostprocess.width = targetSize;
  358. this._kernelBlurXPostprocess.height = targetSize;
  359. this._kernelBlurXPostprocess.onApplyObservable.add(effect => {
  360. effect.setTexture("textureSampler", this._shadowMap);
  361. });
  362. this._kernelBlurYPostprocess = new BlurPostProcess(this._light.name + "KernelBlurY", new Vector2(0, 1), this.blurKernel, 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._textureType);
  363. this._kernelBlurXPostprocess.autoClear = false;
  364. this._kernelBlurYPostprocess.autoClear = false;
  365. if (this._textureType === Engine.TEXTURETYPE_UNSIGNED_INT) {
  366. (<BlurPostProcess>this._kernelBlurXPostprocess).packedFloat = true;
  367. (<BlurPostProcess>this._kernelBlurYPostprocess).packedFloat = true;
  368. }
  369. this._blurPostProcesses = [this._kernelBlurXPostprocess, this._kernelBlurYPostprocess];
  370. }
  371. else {
  372. this._boxBlurPostprocess = new PostProcess(this._light.name + "DepthBoxBlur", "depthBoxBlur", ["screenSize", "boxOffset"], [], 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, "#define OFFSET " + this._blurBoxOffset, this._textureType);
  373. this._boxBlurPostprocess.onApplyObservable.add(effect => {
  374. effect.setFloat2("screenSize", targetSize, targetSize);
  375. effect.setTexture("textureSampler", this._shadowMap);
  376. });
  377. this._boxBlurPostprocess.autoClear = false;
  378. this._blurPostProcesses = [this._boxBlurPostprocess];
  379. }
  380. }
  381. private _renderForShadowMap(opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void {
  382. var index: number;
  383. for (index = 0; index < opaqueSubMeshes.length; index++) {
  384. this._renderSubMeshForShadowMap(opaqueSubMeshes.data[index]);
  385. }
  386. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  387. this._renderSubMeshForShadowMap(alphaTestSubMeshes.data[index]);
  388. }
  389. if (this._transparencyShadow) {
  390. for (index = 0; index < transparentSubMeshes.length; index++) {
  391. this._renderSubMeshForShadowMap(transparentSubMeshes.data[index]);
  392. }
  393. }
  394. }
  395. private _renderSubMeshForShadowMap(subMesh: SubMesh): void {
  396. var mesh = subMesh.getRenderingMesh();
  397. var scene = this._scene;
  398. var engine = scene.getEngine();
  399. // Culling
  400. engine.setState(subMesh.getMaterial().backFaceCulling);
  401. // Managing instances
  402. var batch = mesh._getInstancesRenderList(subMesh._id);
  403. if (batch.mustReturn) {
  404. return;
  405. }
  406. var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
  407. if (this.isReady(subMesh, hardwareInstancedRendering)) {
  408. engine.enableEffect(this._effect);
  409. mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
  410. var material = subMesh.getMaterial();
  411. this._effect.setFloat2("biasAndScale", this.bias, this.depthScale);
  412. this._effect.setMatrix("viewProjection", this.getTransformMatrix());
  413. this._effect.setVector3("lightPosition", this.getLight().position);
  414. this._effect.setFloat2("depthValues", this.getLight().getDepthMinZ(scene.activeCamera), this.getLight().getDepthMinZ(scene.activeCamera) + this.getLight().getDepthMaxZ(scene.activeCamera));
  415. // Alpha test
  416. if (material && material.needAlphaTesting()) {
  417. var alphaTexture = material.getAlphaTestTexture();
  418. if (alphaTexture) {
  419. this._effect.setTexture("diffuseSampler", alphaTexture);
  420. this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix() || this._defaultTextureMatrix);
  421. }
  422. }
  423. // Bones
  424. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  425. this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
  426. }
  427. if (this.forceBackFacesOnly) {
  428. engine.setState(true, 0, false, true);
  429. }
  430. // Draw
  431. mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
  432. (isInstance, world) => this._effect.setMatrix("world", world));
  433. if (this.forceBackFacesOnly) {
  434. engine.setState(true, 0, false, false);
  435. }
  436. } else {
  437. // Need to reset refresh rate of the shadowMap
  438. this._shadowMap.resetRefreshCounter();
  439. }
  440. }
  441. private _applyFilterValues(): void {
  442. if (this.filter === ShadowGenerator.FILTER_NONE) {
  443. this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
  444. } else {
  445. this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  446. }
  447. }
  448. /**
  449. * Force shader compilation including textures ready check
  450. */
  451. public forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void {
  452. var scene = this._scene;
  453. var engine = scene.getEngine();
  454. var subMeshes = new Array<SubMesh>();
  455. var currentIndex = 0;
  456. for(var mesh of this.getShadowMap().renderList) {
  457. subMeshes.push(...mesh.subMeshes);
  458. }
  459. var checkReady = () => {
  460. if (!this._scene || !this._scene.getEngine()) {
  461. return;
  462. }
  463. let subMesh = subMeshes[currentIndex];
  464. if (this.isReady(subMesh, options ? options.useInstances : false)) {
  465. currentIndex++;
  466. if (currentIndex >= subMeshes.length) {
  467. if (onCompiled) {
  468. onCompiled(this);
  469. }
  470. return;
  471. }
  472. }
  473. setTimeout(checkReady, 16);
  474. };
  475. if (subMeshes.length > 0) {
  476. checkReady();
  477. }
  478. }
  479. /**
  480. * Boolean : true when the ShadowGenerator is finally computed.
  481. */
  482. public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
  483. var defines = [];
  484. if (this._textureType !== Engine.TEXTURETYPE_UNSIGNED_INT) {
  485. defines.push("#define FLOAT");
  486. }
  487. if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  488. defines.push("#define ESM");
  489. }
  490. var attribs = [VertexBuffer.PositionKind];
  491. var mesh = subMesh.getMesh();
  492. var material = subMesh.getMaterial();
  493. // Alpha test
  494. if (material && material.needAlphaTesting()) {
  495. var alphaTexture = material.getAlphaTestTexture();
  496. if (alphaTexture) {
  497. defines.push("#define ALPHATEST");
  498. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  499. attribs.push(VertexBuffer.UVKind);
  500. defines.push("#define UV1");
  501. }
  502. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  503. if (alphaTexture.coordinatesIndex === 1) {
  504. attribs.push(VertexBuffer.UV2Kind);
  505. defines.push("#define UV2");
  506. }
  507. }
  508. }
  509. }
  510. // Bones
  511. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  512. attribs.push(VertexBuffer.MatricesIndicesKind);
  513. attribs.push(VertexBuffer.MatricesWeightsKind);
  514. if (mesh.numBoneInfluencers > 4) {
  515. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  516. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  517. }
  518. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  519. defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
  520. } else {
  521. defines.push("#define NUM_BONE_INFLUENCERS 0");
  522. }
  523. // Instances
  524. if (useInstances) {
  525. defines.push("#define INSTANCES");
  526. attribs.push("world0");
  527. attribs.push("world1");
  528. attribs.push("world2");
  529. attribs.push("world3");
  530. }
  531. // Get correct effect
  532. var join = defines.join("\n");
  533. if (this._cachedDefines !== join) {
  534. this._cachedDefines = join;
  535. this._effect = this._scene.getEngine().createEffect("shadowMap",
  536. attribs,
  537. ["world", "mBones", "viewProjection", "diffuseMatrix", "lightPosition", "depthValues", "biasAndScale"],
  538. ["diffuseSampler"], join);
  539. }
  540. return this._effect.isReady();
  541. }
  542. /**
  543. * This creates the defines related to the standard BJS materials.
  544. */
  545. public prepareDefines(defines: MaterialDefines, lightIndex: number): void {
  546. var scene = this._scene;
  547. var light = this._light;
  548. if (!scene.shadowsEnabled || !light.shadowEnabled) {
  549. return;
  550. }
  551. defines["SHADOW" + lightIndex] = true;
  552. if (this.usePoissonSampling) {
  553. defines["SHADOWPCF" + lightIndex] = true;
  554. }
  555. else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  556. defines["SHADOWESM" + lightIndex] = true;
  557. }
  558. else if (this.useCloseExponentialShadowMap || this.useBlurCloseExponentialShadowMap) {
  559. defines["SHADOWCLOSEESM" + lightIndex] = true;
  560. }
  561. if (light.needCube()) {
  562. defines["SHADOWCUBE" + lightIndex] = true;
  563. }
  564. }
  565. /**
  566. * This binds shadow lights related to the standard BJS materials.
  567. * It implies the unifroms available on the materials are the standard BJS ones.
  568. */
  569. public bindShadowLight(lightIndex: string, effect: Effect): void {
  570. var light = this._light;
  571. var scene = this._scene;
  572. if (!scene.shadowsEnabled || !light.shadowEnabled) {
  573. return;
  574. }
  575. if (!light.needCube()) {
  576. effect.setMatrix("lightMatrix" + lightIndex, this.getTransformMatrix());
  577. }
  578. effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
  579. light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / this.getShadowMap().getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
  580. light._uniformBuffer.updateFloat2("depthValues", this.getLight().getDepthMinZ(scene.activeCamera), this.getLight().getDepthMinZ(scene.activeCamera) + this.getLight().getDepthMaxZ(scene.activeCamera), lightIndex);
  581. }
  582. // Methods
  583. /**
  584. * Returns a Matrix object : the updated transformation matrix.
  585. */
  586. public getTransformMatrix(): Matrix {
  587. var scene = this._scene;
  588. if (this._currentRenderID === scene.getRenderId() && this._currentFaceIndexCache === this._currentFaceIndex) {
  589. return this._transformMatrix;
  590. }
  591. this._currentRenderID = scene.getRenderId();
  592. this._currentFaceIndexCache = this._currentFaceIndex;
  593. var lightPosition = this._light.position;
  594. if (this._light.computeTransformedInformation()) {
  595. lightPosition = this._light.transformedPosition;
  596. }
  597. Vector3.NormalizeToRef(this._light.getShadowDirection(this._currentFaceIndex), this._lightDirection);
  598. if (Math.abs(Vector3.Dot(this._lightDirection, Vector3.Up())) === 1.0) {
  599. this._lightDirection.z = 0.0000000000001; // Required to avoid perfectly perpendicular light
  600. }
  601. if (this._light.needProjectionMatrixCompute() || !this._cachedPosition || !this._cachedDirection || !lightPosition.equals(this._cachedPosition) || !this._lightDirection.equals(this._cachedDirection)) {
  602. this._cachedPosition = lightPosition.clone();
  603. this._cachedDirection = this._lightDirection.clone();
  604. Matrix.LookAtLHToRef(lightPosition, lightPosition.add(this._lightDirection), Vector3.Up(), this._viewMatrix);
  605. this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, this.getShadowMap().renderList);
  606. this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  607. }
  608. return this._transformMatrix;
  609. }
  610. public recreateShadowMap(): void {
  611. // Track render list.
  612. var renderList = this._shadowMap.renderList;
  613. // Clean up existing data.
  614. this._disposeRTTandPostProcesses();
  615. // Reinitializes.
  616. this._initializeGenerator();
  617. // Reaffect the filter to ensure a correct fallback if necessary.
  618. this.filter = this.filter;
  619. // Reaffect the filter.
  620. this._applyFilterValues();
  621. // Reaffect Render List.
  622. this._shadowMap.renderList = renderList;
  623. }
  624. private _disposeBlurPostProcesses(): void {
  625. if (this._shadowMap2) {
  626. this._shadowMap2.dispose();
  627. this._shadowMap2 = null;
  628. }
  629. if (this._downSamplePostprocess) {
  630. this._downSamplePostprocess.dispose();
  631. this._downSamplePostprocess = null;
  632. }
  633. if (this._boxBlurPostprocess) {
  634. this._boxBlurPostprocess.dispose();
  635. this._boxBlurPostprocess = null;
  636. }
  637. if (this._kernelBlurXPostprocess) {
  638. this._kernelBlurXPostprocess.dispose();
  639. this._kernelBlurXPostprocess = null;
  640. }
  641. if (this._kernelBlurYPostprocess) {
  642. this._kernelBlurYPostprocess.dispose();
  643. this._kernelBlurYPostprocess = null;
  644. }
  645. this._blurPostProcesses = null;
  646. }
  647. private _disposeRTTandPostProcesses(): void {
  648. if (this._shadowMap) {
  649. this._shadowMap.dispose();
  650. this._shadowMap = null;
  651. }
  652. this._disposeBlurPostProcesses();
  653. }
  654. /**
  655. * Disposes the ShadowGenerator.
  656. * Returns nothing.
  657. */
  658. public dispose(): void {
  659. this._disposeRTTandPostProcesses();
  660. this._light._shadowGenerator = null;
  661. this._light._markMeshesAsLightDirty();
  662. }
  663. /**
  664. * Serializes the ShadowGenerator and returns a serializationObject.
  665. */
  666. public serialize(): any {
  667. var serializationObject: any = {};
  668. var shadowMap = this.getShadowMap();
  669. serializationObject.lightId = this._light.id;
  670. serializationObject.mapSize = shadowMap.getRenderSize();
  671. serializationObject.useExponentialShadowMap = this.useExponentialShadowMap;
  672. serializationObject.useBlurExponentialShadowMap = this.useBlurExponentialShadowMap;
  673. serializationObject.useCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
  674. serializationObject.useBlurCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
  675. serializationObject.usePoissonSampling = this.usePoissonSampling;
  676. serializationObject.forceBackFacesOnly = this.forceBackFacesOnly;
  677. serializationObject.depthScale = this.depthScale;
  678. serializationObject.darkness = this.getDarkness();
  679. serializationObject.blurBoxOffset = this.blurBoxOffset;
  680. serializationObject.blurKernel = this.blurKernel;
  681. serializationObject.blurScale = this.blurScale;
  682. serializationObject.useKernelBlur = this.useKernelBlur;
  683. serializationObject.transparencyShadow = this._transparencyShadow;
  684. serializationObject.renderList = [];
  685. for (var meshIndex = 0; meshIndex < shadowMap.renderList.length; meshIndex++) {
  686. var mesh = shadowMap.renderList[meshIndex];
  687. serializationObject.renderList.push(mesh.id);
  688. }
  689. return serializationObject;
  690. }
  691. /**
  692. * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.
  693. */
  694. public static Parse(parsedShadowGenerator: any, scene: Scene): ShadowGenerator {
  695. //casting to point light, as light is missing the position attr and typescript complains.
  696. var light = <PointLight>scene.getLightByID(parsedShadowGenerator.lightId);
  697. var shadowGenerator = new ShadowGenerator(parsedShadowGenerator.mapSize, light);
  698. var shadowMap = shadowGenerator.getShadowMap();
  699. for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
  700. var meshes = scene.getMeshesByID(parsedShadowGenerator.renderList[meshIndex]);
  701. meshes.forEach(function (mesh) {
  702. shadowMap.renderList.push(mesh);
  703. });
  704. }
  705. if (parsedShadowGenerator.usePoissonSampling) {
  706. shadowGenerator.usePoissonSampling = true;
  707. }
  708. else if (parsedShadowGenerator.useExponentialShadowMap) {
  709. shadowGenerator.useExponentialShadowMap = true;
  710. }
  711. else if (parsedShadowGenerator.useBlurExponentialShadowMap) {
  712. shadowGenerator.useBlurExponentialShadowMap = true;
  713. }
  714. else if (parsedShadowGenerator.useCloseExponentialShadowMap) {
  715. shadowGenerator.useCloseExponentialShadowMap = true;
  716. }
  717. else if (parsedShadowGenerator.useBlurExponentialShadowMap) {
  718. shadowGenerator.useBlurCloseExponentialShadowMap = true;
  719. }
  720. // Backward compat
  721. else if (parsedShadowGenerator.useVarianceShadowMap) {
  722. shadowGenerator.useExponentialShadowMap = true;
  723. }
  724. else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
  725. shadowGenerator.useBlurExponentialShadowMap = true;
  726. }
  727. if (parsedShadowGenerator.depthScale) {
  728. shadowGenerator.depthScale = parsedShadowGenerator.depthScale;
  729. }
  730. if (parsedShadowGenerator.blurScale) {
  731. shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
  732. }
  733. if (parsedShadowGenerator.blurBoxOffset) {
  734. shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
  735. }
  736. if (parsedShadowGenerator.useKernelBlur) {
  737. shadowGenerator.useKernelBlur = parsedShadowGenerator.useKernelBlur;
  738. }
  739. if (parsedShadowGenerator.blurKernel) {
  740. shadowGenerator.blurKernel = parsedShadowGenerator.blurKernel;
  741. }
  742. if (parsedShadowGenerator.bias !== undefined) {
  743. shadowGenerator.bias = parsedShadowGenerator.bias;
  744. }
  745. if (parsedShadowGenerator.darkness) {
  746. shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
  747. }
  748. if (parsedShadowGenerator.transparencyShadow) {
  749. shadowGenerator.setTransparencyShadow(true);
  750. }
  751. shadowGenerator.forceBackFacesOnly = parsedShadowGenerator.forceBackFacesOnly;
  752. return shadowGenerator;
  753. }
  754. }
  755. }