babylon.shadowGenerator.ts 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. module BABYLON {
  2. /**
  3. * Interface to implement to create a shadow generator compatible with BJS.
  4. */
  5. export interface IShadowGenerator {
  6. getShadowMap(): Nullable<RenderTargetTexture>;
  7. getShadowMapForRendering(): Nullable<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: Nullable<RenderTargetTexture>;
  217. private _shadowMap2: Nullable<RenderTargetTexture>;
  218. /**
  219. * Returns a RenderTargetTexture object : the shadow map texture.
  220. */
  221. public getShadowMap(): Nullable<RenderTargetTexture> {
  222. return this._shadowMap;
  223. }
  224. /**
  225. * Returns the most ready computed shadow map as a RenderTargetTexture object.
  226. */
  227. public getShadowMapForRendering(): Nullable<RenderTargetTexture> {
  228. if (this._shadowMap2) {
  229. return this._shadowMap2;
  230. }
  231. return this._shadowMap;
  232. }
  233. /**
  234. * Helper function to add a mesh and its descendants to the list of shadow casters
  235. * @param mesh Mesh to add
  236. * @param includeDescendants boolean indicating if the descendants should be added. Default to true
  237. */
  238. public addShadowCaster(mesh: AbstractMesh, includeDescendants = true): ShadowGenerator {
  239. if (!this._shadowMap) {
  240. return this;
  241. }
  242. if (!this._shadowMap.renderList) {
  243. this._shadowMap.renderList = [];
  244. }
  245. this._shadowMap.renderList.push(mesh);
  246. if (includeDescendants) {
  247. this._shadowMap.renderList.push(...mesh.getChildMeshes());
  248. }
  249. return this;
  250. }
  251. /**
  252. * Helper function to remove a mesh and its descendants from the list of shadow casters
  253. * @param mesh Mesh to remove
  254. * @param includeDescendants boolean indicating if the descendants should be removed. Default to true
  255. */
  256. public removeShadowCaster(mesh: AbstractMesh, includeDescendants = true): ShadowGenerator {
  257. if (!this._shadowMap || !this._shadowMap.renderList) {
  258. return this;
  259. }
  260. var index = this._shadowMap.renderList.indexOf(mesh);
  261. if (index !== -1) {
  262. this._shadowMap.renderList.splice(index, 1);
  263. }
  264. if (includeDescendants) {
  265. for (var child of mesh.getChildren()) {
  266. this.removeShadowCaster(<any>child);
  267. }
  268. }
  269. return this;
  270. }
  271. /**
  272. * Controls the extent to which the shadows fade out at the edge of the frustum
  273. * Used only by directionals and spots
  274. */
  275. public frustumEdgeFalloff = 0;
  276. private _light: IShadowLight;
  277. /**
  278. * Returns the associated light object.
  279. */
  280. public getLight(): IShadowLight {
  281. return this._light;
  282. }
  283. public forceBackFacesOnly = false;
  284. private _scene: Scene;
  285. private _lightDirection = Vector3.Zero();
  286. private _effect: Effect;
  287. private _viewMatrix = Matrix.Zero();
  288. private _projectionMatrix = Matrix.Zero();
  289. private _transformMatrix = Matrix.Zero();
  290. private _cachedPosition: Vector3;
  291. private _cachedDirection: Vector3;
  292. private _cachedDefines: string;
  293. private _currentRenderID: number;
  294. private _downSamplePostprocess: Nullable<PassPostProcess>;
  295. private _boxBlurPostprocess: Nullable<PostProcess>;
  296. private _kernelBlurXPostprocess: Nullable<PostProcess>;
  297. private _kernelBlurYPostprocess: Nullable<PostProcess>;
  298. private _blurPostProcesses: PostProcess[];
  299. private _mapSize: number;
  300. private _currentFaceIndex = 0;
  301. private _currentFaceIndexCache = 0;
  302. private _textureType: number;
  303. private _defaultTextureMatrix = Matrix.Identity();
  304. /**
  305. * Creates a ShadowGenerator object.
  306. * A ShadowGenerator is the required tool to use the shadows.
  307. * Each light casting shadows needs to use its own ShadowGenerator.
  308. * Required parameters :
  309. * - `mapSize` (integer): the size of the texture what stores the shadows. Example : 1024.
  310. * - `light`: the light object generating the shadows.
  311. * - `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.
  312. * Documentation : http://doc.babylonjs.com/tutorials/shadows
  313. */
  314. constructor(mapSize: number, light: IShadowLight, useFullFloatFirst?: boolean) {
  315. this._mapSize = mapSize;
  316. this._light = light;
  317. this._scene = light.getScene();
  318. light._shadowGenerator = this;
  319. // Texture type fallback from float to int if not supported.
  320. var caps = this._scene.getEngine().getCaps();
  321. if (!useFullFloatFirst) {
  322. if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
  323. this._textureType = Engine.TEXTURETYPE_HALF_FLOAT;
  324. }
  325. else if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
  326. this._textureType = Engine.TEXTURETYPE_FLOAT;
  327. }
  328. else {
  329. this._textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
  330. }
  331. } else {
  332. if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
  333. this._textureType = Engine.TEXTURETYPE_FLOAT;
  334. }
  335. else if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
  336. this._textureType = Engine.TEXTURETYPE_HALF_FLOAT;
  337. }
  338. else {
  339. this._textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
  340. }
  341. }
  342. this._initializeGenerator();
  343. }
  344. private _initializeGenerator(): void {
  345. this._light._markMeshesAsLightDirty();
  346. this._initializeShadowMap();
  347. }
  348. private _initializeShadowMap(): void {
  349. // Render target
  350. this._shadowMap = new RenderTargetTexture(this._light.name + "_shadowMap", this._mapSize, this._scene, false, true, this._textureType, this._light.needCube());
  351. this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
  352. this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
  353. this._shadowMap.anisotropicFilteringLevel = 1;
  354. this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  355. this._shadowMap.renderParticles = false;
  356. this._shadowMap.ignoreCameraViewport = true;
  357. // Record Face Index before render.
  358. this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
  359. this._currentFaceIndex = faceIndex;
  360. });
  361. // Custom render function.
  362. this._shadowMap.customRenderFunction = this._renderForShadowMap.bind(this);
  363. // Blur if required afer render.
  364. this._shadowMap.onAfterUnbindObservable.add(() => {
  365. if (!this.useBlurExponentialShadowMap && !this.useBlurCloseExponentialShadowMap) {
  366. return;
  367. }
  368. if (!this._blurPostProcesses || !this._blurPostProcesses.length) {
  369. this._initializeBlurRTTAndPostProcesses();
  370. }
  371. let shadowMap = this.getShadowMapForRendering();
  372. if (shadowMap) {
  373. this._scene.postProcessManager.directRender(this._blurPostProcesses, shadowMap.getInternalTexture(), true);
  374. }
  375. });
  376. // Clear according to the chosen filter.
  377. this._shadowMap.onClearObservable.add((engine: Engine) => {
  378. if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  379. engine.clear(new Color4(0, 0, 0, 0), true, true, true);
  380. }
  381. else {
  382. engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
  383. }
  384. });
  385. }
  386. private _initializeBlurRTTAndPostProcesses(): void {
  387. var engine = this._scene.getEngine();
  388. var targetSize = this._mapSize / this.blurScale;
  389. if (!this.useKernelBlur || this.blurScale !== 1.0) {
  390. this._shadowMap2 = new RenderTargetTexture(this._light.name + "_shadowMap2", targetSize, this._scene, false, true, this._textureType);
  391. this._shadowMap2.wrapU = Texture.CLAMP_ADDRESSMODE;
  392. this._shadowMap2.wrapV = Texture.CLAMP_ADDRESSMODE;
  393. this._shadowMap2.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  394. }
  395. if (this.useKernelBlur) {
  396. this._kernelBlurXPostprocess = new BlurPostProcess(this._light.name + "KernelBlurX", new Vector2(1, 0), this.blurKernel, 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._textureType);
  397. this._kernelBlurXPostprocess.width = targetSize;
  398. this._kernelBlurXPostprocess.height = targetSize;
  399. this._kernelBlurXPostprocess.onApplyObservable.add(effect => {
  400. effect.setTexture("textureSampler", this._shadowMap);
  401. });
  402. this._kernelBlurYPostprocess = new BlurPostProcess(this._light.name + "KernelBlurY", new Vector2(0, 1), this.blurKernel, 1.0, null, Texture.BILINEAR_SAMPLINGMODE, engine, false, this._textureType);
  403. this._kernelBlurXPostprocess.autoClear = false;
  404. this._kernelBlurYPostprocess.autoClear = false;
  405. if (this._textureType === Engine.TEXTURETYPE_UNSIGNED_INT) {
  406. (<BlurPostProcess>this._kernelBlurXPostprocess).packedFloat = true;
  407. (<BlurPostProcess>this._kernelBlurYPostprocess).packedFloat = true;
  408. }
  409. this._blurPostProcesses = [this._kernelBlurXPostprocess, this._kernelBlurYPostprocess];
  410. }
  411. else {
  412. 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);
  413. this._boxBlurPostprocess.onApplyObservable.add(effect => {
  414. effect.setFloat2("screenSize", targetSize, targetSize);
  415. effect.setTexture("textureSampler", this._shadowMap);
  416. });
  417. this._boxBlurPostprocess.autoClear = false;
  418. this._blurPostProcesses = [this._boxBlurPostprocess];
  419. }
  420. }
  421. private _renderForShadowMap(opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void {
  422. var index: number;
  423. let engine = this._scene.getEngine();
  424. if (depthOnlySubMeshes.length) {
  425. engine.setColorWrite(false);
  426. for (index = 0; index < depthOnlySubMeshes.length; index++) {
  427. this._renderSubMeshForShadowMap(depthOnlySubMeshes.data[index]);
  428. }
  429. engine.setColorWrite(true);
  430. }
  431. for (index = 0; index < opaqueSubMeshes.length; index++) {
  432. this._renderSubMeshForShadowMap(opaqueSubMeshes.data[index]);
  433. }
  434. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  435. this._renderSubMeshForShadowMap(alphaTestSubMeshes.data[index]);
  436. }
  437. if (this._transparencyShadow) {
  438. for (index = 0; index < transparentSubMeshes.length; index++) {
  439. this._renderSubMeshForShadowMap(transparentSubMeshes.data[index]);
  440. }
  441. }
  442. }
  443. private _renderSubMeshForShadowMap(subMesh: SubMesh): void {
  444. var mesh = subMesh.getRenderingMesh();
  445. var scene = this._scene;
  446. var engine = scene.getEngine();
  447. let material = subMesh.getMaterial();
  448. if (!material) {
  449. return;
  450. }
  451. // Culling
  452. engine.setState(material.backFaceCulling);
  453. // Managing instances
  454. var batch = mesh._getInstancesRenderList(subMesh._id);
  455. if (batch.mustReturn) {
  456. return;
  457. }
  458. var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
  459. if (this.isReady(subMesh, hardwareInstancedRendering)) {
  460. engine.enableEffect(this._effect);
  461. mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
  462. this._effect.setFloat2("biasAndScale", this.bias, this.depthScale);
  463. this._effect.setMatrix("viewProjection", this.getTransformMatrix());
  464. this._effect.setVector3("lightPosition", this.getLight().position);
  465. if (scene.activeCamera) {
  466. this._effect.setFloat2("depthValues", this.getLight().getDepthMinZ(scene.activeCamera), this.getLight().getDepthMinZ(scene.activeCamera) + this.getLight().getDepthMaxZ(scene.activeCamera));
  467. }
  468. // Alpha test
  469. if (material && material.needAlphaTesting()) {
  470. var alphaTexture = material.getAlphaTestTexture();
  471. if (alphaTexture) {
  472. this._effect.setTexture("diffuseSampler", alphaTexture);
  473. this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix() || this._defaultTextureMatrix);
  474. }
  475. }
  476. // Bones
  477. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  478. this._effect.setMatrices("mBones", (<Skeleton>mesh.skeleton).getTransformMatrices((mesh)));
  479. }
  480. if (this.forceBackFacesOnly) {
  481. engine.setState(true, 0, false, true);
  482. }
  483. // Draw
  484. mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
  485. (isInstance, world) => this._effect.setMatrix("world", world));
  486. if (this.forceBackFacesOnly) {
  487. engine.setState(true, 0, false, false);
  488. }
  489. } else {
  490. // Need to reset refresh rate of the shadowMap
  491. if (this._shadowMap) {
  492. this._shadowMap.resetRefreshCounter();
  493. }
  494. }
  495. }
  496. private _applyFilterValues(): void {
  497. if (!this._shadowMap) {
  498. return;
  499. }
  500. if (this.filter === ShadowGenerator.FILTER_NONE) {
  501. this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
  502. } else {
  503. this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  504. }
  505. }
  506. /**
  507. * Force shader compilation including textures ready check
  508. */
  509. public forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void {
  510. let shadowMap = this.getShadowMap();
  511. if (!shadowMap) {
  512. return;
  513. }
  514. var subMeshes = new Array<SubMesh>();
  515. var currentIndex = 0;
  516. let renderList = shadowMap.renderList;
  517. if (!renderList) {
  518. return;
  519. }
  520. for (var mesh of renderList) {
  521. subMeshes.push(...mesh.subMeshes);
  522. }
  523. var checkReady = () => {
  524. if (!this._scene || !this._scene.getEngine()) {
  525. return;
  526. }
  527. let subMesh = subMeshes[currentIndex];
  528. if (this.isReady(subMesh, options ? options.useInstances : false)) {
  529. currentIndex++;
  530. if (currentIndex >= subMeshes.length) {
  531. if (onCompiled) {
  532. onCompiled(this);
  533. }
  534. return;
  535. }
  536. }
  537. setTimeout(checkReady, 16);
  538. };
  539. if (subMeshes.length > 0) {
  540. checkReady();
  541. }
  542. }
  543. /**
  544. * Boolean : true when the ShadowGenerator is finally computed.
  545. */
  546. public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
  547. var defines = [];
  548. if (this._textureType !== Engine.TEXTURETYPE_UNSIGNED_INT) {
  549. defines.push("#define FLOAT");
  550. }
  551. if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  552. defines.push("#define ESM");
  553. }
  554. var attribs = [VertexBuffer.PositionKind];
  555. var mesh = subMesh.getMesh();
  556. var material = subMesh.getMaterial();
  557. // Alpha test
  558. if (material && material.needAlphaTesting()) {
  559. var alphaTexture = material.getAlphaTestTexture();
  560. if (alphaTexture) {
  561. defines.push("#define ALPHATEST");
  562. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  563. attribs.push(VertexBuffer.UVKind);
  564. defines.push("#define UV1");
  565. }
  566. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  567. if (alphaTexture.coordinatesIndex === 1) {
  568. attribs.push(VertexBuffer.UV2Kind);
  569. defines.push("#define UV2");
  570. }
  571. }
  572. }
  573. }
  574. // Bones
  575. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  576. attribs.push(VertexBuffer.MatricesIndicesKind);
  577. attribs.push(VertexBuffer.MatricesWeightsKind);
  578. if (mesh.numBoneInfluencers > 4) {
  579. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  580. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  581. }
  582. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  583. defines.push("#define BonesPerMesh " + ((<Skeleton>mesh.skeleton).bones.length + 1));
  584. } else {
  585. defines.push("#define NUM_BONE_INFLUENCERS 0");
  586. }
  587. // Instances
  588. if (useInstances) {
  589. defines.push("#define INSTANCES");
  590. attribs.push("world0");
  591. attribs.push("world1");
  592. attribs.push("world2");
  593. attribs.push("world3");
  594. }
  595. // Get correct effect
  596. var join = defines.join("\n");
  597. if (this._cachedDefines !== join) {
  598. this._cachedDefines = join;
  599. this._effect = this._scene.getEngine().createEffect("shadowMap",
  600. attribs,
  601. ["world", "mBones", "viewProjection", "diffuseMatrix", "lightPosition", "depthValues", "biasAndScale"],
  602. ["diffuseSampler"], join);
  603. }
  604. return this._effect.isReady();
  605. }
  606. /**
  607. * This creates the defines related to the standard BJS materials.
  608. */
  609. public prepareDefines(defines: any, lightIndex: number): void {
  610. var scene = this._scene;
  611. var light = this._light;
  612. if (!scene.shadowsEnabled || !light.shadowEnabled) {
  613. return;
  614. }
  615. defines["SHADOW" + lightIndex] = true;
  616. if (this.usePoissonSampling) {
  617. defines["SHADOWPCF" + lightIndex] = true;
  618. }
  619. else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  620. defines["SHADOWESM" + lightIndex] = true;
  621. }
  622. else if (this.useCloseExponentialShadowMap || this.useBlurCloseExponentialShadowMap) {
  623. defines["SHADOWCLOSEESM" + lightIndex] = true;
  624. }
  625. if (light.needCube()) {
  626. defines["SHADOWCUBE" + lightIndex] = true;
  627. }
  628. }
  629. /**
  630. * This binds shadow lights related to the standard BJS materials.
  631. * It implies the unifroms available on the materials are the standard BJS ones.
  632. */
  633. public bindShadowLight(lightIndex: string, effect: Effect): void {
  634. var light = this._light;
  635. var scene = this._scene;
  636. if (!scene.shadowsEnabled || !light.shadowEnabled) {
  637. return;
  638. }
  639. let camera = scene.activeCamera;
  640. if (!camera) {
  641. return;
  642. }
  643. let shadowMap = this.getShadowMap();
  644. if (!shadowMap) {
  645. return;
  646. }
  647. if (!light.needCube()) {
  648. effect.setMatrix("lightMatrix" + lightIndex, this.getTransformMatrix());
  649. }
  650. effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
  651. light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / shadowMap.getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
  652. light._uniformBuffer.updateFloat2("depthValues", this.getLight().getDepthMinZ(camera), this.getLight().getDepthMinZ(camera) + this.getLight().getDepthMaxZ(camera), lightIndex);
  653. }
  654. // Methods
  655. /**
  656. * Returns a Matrix object : the updated transformation matrix.
  657. */
  658. public getTransformMatrix(): Matrix {
  659. var scene = this._scene;
  660. if (this._currentRenderID === scene.getRenderId() && this._currentFaceIndexCache === this._currentFaceIndex) {
  661. return this._transformMatrix;
  662. }
  663. this._currentRenderID = scene.getRenderId();
  664. this._currentFaceIndexCache = this._currentFaceIndex;
  665. var lightPosition = this._light.position;
  666. if (this._light.computeTransformedInformation()) {
  667. lightPosition = this._light.transformedPosition;
  668. }
  669. Vector3.NormalizeToRef(this._light.getShadowDirection(this._currentFaceIndex), this._lightDirection);
  670. if (Math.abs(Vector3.Dot(this._lightDirection, Vector3.Up())) === 1.0) {
  671. this._lightDirection.z = 0.0000000000001; // Required to avoid perfectly perpendicular light
  672. }
  673. if (this._light.needProjectionMatrixCompute() || !this._cachedPosition || !this._cachedDirection || !lightPosition.equals(this._cachedPosition) || !this._lightDirection.equals(this._cachedDirection)) {
  674. this._cachedPosition = lightPosition.clone();
  675. this._cachedDirection = this._lightDirection.clone();
  676. Matrix.LookAtLHToRef(lightPosition, lightPosition.add(this._lightDirection), Vector3.Up(), this._viewMatrix);
  677. let shadowMap = this.getShadowMap();
  678. if (shadowMap) {
  679. let renderList = shadowMap.renderList;
  680. if (renderList) {
  681. this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, renderList);
  682. }
  683. }
  684. this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  685. }
  686. return this._transformMatrix;
  687. }
  688. public recreateShadowMap(): void {
  689. let shadowMap = this._shadowMap;
  690. if (!shadowMap) {
  691. return;
  692. }
  693. // Track render list.
  694. var renderList = shadowMap.renderList;
  695. // Clean up existing data.
  696. this._disposeRTTandPostProcesses();
  697. // Reinitializes.
  698. this._initializeGenerator();
  699. // Reaffect the filter to ensure a correct fallback if necessary.
  700. this.filter = this.filter;
  701. // Reaffect the filter.
  702. this._applyFilterValues();
  703. // Reaffect Render List.
  704. shadowMap.renderList = renderList;
  705. }
  706. private _disposeBlurPostProcesses(): void {
  707. if (this._shadowMap2) {
  708. this._shadowMap2.dispose();
  709. this._shadowMap2 = null;
  710. }
  711. if (this._downSamplePostprocess) {
  712. this._downSamplePostprocess.dispose();
  713. this._downSamplePostprocess = null;
  714. }
  715. if (this._boxBlurPostprocess) {
  716. this._boxBlurPostprocess.dispose();
  717. this._boxBlurPostprocess = null;
  718. }
  719. if (this._kernelBlurXPostprocess) {
  720. this._kernelBlurXPostprocess.dispose();
  721. this._kernelBlurXPostprocess = null;
  722. }
  723. if (this._kernelBlurYPostprocess) {
  724. this._kernelBlurYPostprocess.dispose();
  725. this._kernelBlurYPostprocess = null;
  726. }
  727. this._blurPostProcesses = [];
  728. }
  729. private _disposeRTTandPostProcesses(): void {
  730. if (this._shadowMap) {
  731. this._shadowMap.dispose();
  732. this._shadowMap = null;
  733. }
  734. this._disposeBlurPostProcesses();
  735. }
  736. /**
  737. * Disposes the ShadowGenerator.
  738. * Returns nothing.
  739. */
  740. public dispose(): void {
  741. this._disposeRTTandPostProcesses();
  742. if (this._light) {
  743. this._light._shadowGenerator = null;
  744. this._light._markMeshesAsLightDirty();
  745. }
  746. }
  747. /**
  748. * Serializes the ShadowGenerator and returns a serializationObject.
  749. */
  750. public serialize(): any {
  751. var serializationObject: any = {};
  752. var shadowMap = this.getShadowMap();
  753. if (!shadowMap) {
  754. return serializationObject;
  755. }
  756. serializationObject.lightId = this._light.id;
  757. serializationObject.mapSize = shadowMap.getRenderSize();
  758. serializationObject.useExponentialShadowMap = this.useExponentialShadowMap;
  759. serializationObject.useBlurExponentialShadowMap = this.useBlurExponentialShadowMap;
  760. serializationObject.useCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
  761. serializationObject.useBlurCloseExponentialShadowMap = this.useBlurExponentialShadowMap;
  762. serializationObject.usePoissonSampling = this.usePoissonSampling;
  763. serializationObject.forceBackFacesOnly = this.forceBackFacesOnly;
  764. serializationObject.depthScale = this.depthScale;
  765. serializationObject.darkness = this.getDarkness();
  766. serializationObject.blurBoxOffset = this.blurBoxOffset;
  767. serializationObject.blurKernel = this.blurKernel;
  768. serializationObject.blurScale = this.blurScale;
  769. serializationObject.useKernelBlur = this.useKernelBlur;
  770. serializationObject.transparencyShadow = this._transparencyShadow;
  771. serializationObject.renderList = [];
  772. if (shadowMap.renderList) {
  773. for (var meshIndex = 0; meshIndex < shadowMap.renderList.length; meshIndex++) {
  774. var mesh = shadowMap.renderList[meshIndex];
  775. serializationObject.renderList.push(mesh.id);
  776. }
  777. }
  778. return serializationObject;
  779. }
  780. /**
  781. * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.
  782. */
  783. public static Parse(parsedShadowGenerator: any, scene: Scene): ShadowGenerator {
  784. //casting to point light, as light is missing the position attr and typescript complains.
  785. var light = <PointLight>scene.getLightByID(parsedShadowGenerator.lightId);
  786. var shadowGenerator = new ShadowGenerator(parsedShadowGenerator.mapSize, light);
  787. var shadowMap = shadowGenerator.getShadowMap();
  788. for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
  789. var meshes = scene.getMeshesByID(parsedShadowGenerator.renderList[meshIndex]);
  790. meshes.forEach(function (mesh) {
  791. if (!shadowMap) {
  792. return;
  793. }
  794. if (!shadowMap.renderList) {
  795. shadowMap.renderList = [];
  796. }
  797. shadowMap.renderList.push(mesh);
  798. });
  799. }
  800. if (parsedShadowGenerator.usePoissonSampling) {
  801. shadowGenerator.usePoissonSampling = true;
  802. }
  803. else if (parsedShadowGenerator.useExponentialShadowMap) {
  804. shadowGenerator.useExponentialShadowMap = true;
  805. }
  806. else if (parsedShadowGenerator.useBlurExponentialShadowMap) {
  807. shadowGenerator.useBlurExponentialShadowMap = true;
  808. }
  809. else if (parsedShadowGenerator.useCloseExponentialShadowMap) {
  810. shadowGenerator.useCloseExponentialShadowMap = true;
  811. }
  812. else if (parsedShadowGenerator.useBlurCloseExponentialShadowMap) {
  813. shadowGenerator.useBlurCloseExponentialShadowMap = true;
  814. }
  815. // Backward compat
  816. else if (parsedShadowGenerator.useVarianceShadowMap) {
  817. shadowGenerator.useExponentialShadowMap = true;
  818. }
  819. else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
  820. shadowGenerator.useBlurExponentialShadowMap = true;
  821. }
  822. if (parsedShadowGenerator.depthScale) {
  823. shadowGenerator.depthScale = parsedShadowGenerator.depthScale;
  824. }
  825. if (parsedShadowGenerator.blurScale) {
  826. shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
  827. }
  828. if (parsedShadowGenerator.blurBoxOffset) {
  829. shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
  830. }
  831. if (parsedShadowGenerator.useKernelBlur) {
  832. shadowGenerator.useKernelBlur = parsedShadowGenerator.useKernelBlur;
  833. }
  834. if (parsedShadowGenerator.blurKernel) {
  835. shadowGenerator.blurKernel = parsedShadowGenerator.blurKernel;
  836. }
  837. if (parsedShadowGenerator.bias !== undefined) {
  838. shadowGenerator.bias = parsedShadowGenerator.bias;
  839. }
  840. if (parsedShadowGenerator.darkness) {
  841. shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
  842. }
  843. if (parsedShadowGenerator.transparencyShadow) {
  844. shadowGenerator.setTransparencyShadow(true);
  845. }
  846. shadowGenerator.forceBackFacesOnly = parsedShadowGenerator.forceBackFacesOnly;
  847. return shadowGenerator;
  848. }
  849. }
  850. }