babylon.shadowGenerator.ts 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. module BABYLON {
  2. export interface IShadowGenerator {
  3. getShadowMap(): RenderTargetTexture;
  4. isReady(subMesh: SubMesh, useInstances: boolean): boolean;
  5. prepareDefines(defines: MaterialDefines, lightIndex: number): void;
  6. bindShadowLight(lightIndex: string, effect: Effect, depthValuesAlreadySet: boolean): boolean;
  7. recreateShadowMap(): void;
  8. serialize(): any;
  9. dispose(): void;
  10. }
  11. export class ShadowGenerator implements IShadowGenerator {
  12. private static _FILTER_NONE = 0;
  13. private static _FILTER_EXPONENTIALSHADOWMAP = 1;
  14. private static _FILTER_POISSONSAMPLING = 2;
  15. private static _FILTER_BLUREXPONENTIALSHADOWMAP = 3;
  16. // Static
  17. public static get FILTER_NONE(): number {
  18. return ShadowGenerator._FILTER_NONE;
  19. }
  20. public static get FILTER_POISSONSAMPLING(): number {
  21. return ShadowGenerator._FILTER_POISSONSAMPLING;
  22. }
  23. public static get FILTER_EXPONENTIALSHADOWMAP(): number {
  24. return ShadowGenerator._FILTER_EXPONENTIALSHADOWMAP;
  25. }
  26. public static get FILTER_BLUREXPONENTIALSHADOWMAP(): number {
  27. return ShadowGenerator._FILTER_BLUREXPONENTIALSHADOWMAP;
  28. }
  29. // Members
  30. private _filter = ShadowGenerator.FILTER_NONE;
  31. public blurScale = 2;
  32. private _blurBoxOffset = 0;
  33. private _bias = 0.00005;
  34. private _lightDirection = Vector3.Zero();
  35. private _depthScale: number;
  36. public forceBackFacesOnly = false;
  37. public get bias(): number {
  38. return this._bias;
  39. }
  40. public set bias(bias: number) {
  41. this._bias = bias;
  42. }
  43. public get blurBoxOffset(): number {
  44. return this._blurBoxOffset;
  45. }
  46. public set blurBoxOffset(value: number) {
  47. if (this._blurBoxOffset === value) {
  48. return;
  49. }
  50. this._blurBoxOffset = value;
  51. if (this._boxBlurPostprocess) {
  52. this._boxBlurPostprocess.dispose();
  53. }
  54. this._boxBlurPostprocess = new PostProcess("DepthBoxBlur", "depthBoxBlur", ["screenSize", "boxOffset"], [], 1.0 / this.blurScale, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, "#define OFFSET " + value, this._textureType);
  55. this._boxBlurPostprocess.onApplyObservable.add(effect => {
  56. effect.setFloat2("screenSize", this._mapSize / this.blurScale, this._mapSize / this.blurScale);
  57. });
  58. }
  59. public get depthScale(): number {
  60. return this._depthScale !== undefined ? this._depthScale : this._light.getDepthScale();
  61. }
  62. public set depthScale(value: number) {
  63. this._depthScale = value;
  64. }
  65. public get filter(): number {
  66. return this._filter;
  67. }
  68. public set filter(value: number) {
  69. if (this._filter === value) {
  70. return;
  71. }
  72. this._filter = value;
  73. this._applyFilterValues();
  74. this._light._markMeshesAsLightDirty();
  75. }
  76. public get useVarianceShadowMap(): boolean {
  77. Tools.Warn("VSM are now replaced by ESM. Please use useExponentialShadowMap instead.");
  78. return this.useExponentialShadowMap;
  79. }
  80. public set useVarianceShadowMap(value: boolean) {
  81. Tools.Warn("VSM are now replaced by ESM. Please use useExponentialShadowMap instead.");
  82. this.useExponentialShadowMap = value;
  83. }
  84. public get useExponentialShadowMap(): boolean {
  85. return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
  86. }
  87. public set useExponentialShadowMap(value: boolean) {
  88. this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
  89. }
  90. public get usePoissonSampling(): boolean {
  91. return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
  92. }
  93. public set usePoissonSampling(value: boolean) {
  94. this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
  95. }
  96. public get useBlurVarianceShadowMap(): boolean {
  97. Tools.Warn("VSM are now replaced by ESM. Please use useBlurExponentialShadowMap instead.");
  98. return this.useBlurExponentialShadowMap;
  99. }
  100. public set useBlurVarianceShadowMap(value: boolean) {
  101. Tools.Warn("VSM are now replaced by ESM. Please use useBlurExponentialShadowMap instead.");
  102. this.useBlurExponentialShadowMap = value;
  103. }
  104. public get useBlurExponentialShadowMap(): boolean {
  105. return this.filter === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP;
  106. }
  107. public set useBlurExponentialShadowMap(value: boolean) {
  108. if (this._light.needCube() && value) {
  109. this.useExponentialShadowMap = true; // Blurring the cubemap is going to be too expensive. Reverting to unblurred version
  110. } else {
  111. this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
  112. }
  113. }
  114. private _light: IShadowLight;
  115. private _scene: Scene;
  116. private _shadowMap: RenderTargetTexture;
  117. private _shadowMap2: RenderTargetTexture;
  118. private _darkness = 0;
  119. private _transparencyShadow = false;
  120. private _effect: Effect;
  121. private _viewMatrix = Matrix.Zero();
  122. private _projectionMatrix = Matrix.Zero();
  123. private _transformMatrix = Matrix.Zero();
  124. private _worldViewProjection = Matrix.Zero();
  125. private _cachedPosition: Vector3;
  126. private _cachedDirection: Vector3;
  127. private _cachedDefines: string;
  128. private _currentRenderID: number;
  129. private _downSamplePostprocess: PassPostProcess;
  130. private _boxBlurPostprocess: PostProcess;
  131. private _mapSize: number;
  132. private _currentFaceIndex = 0;
  133. private _currentFaceIndexCache = 0;
  134. private _textureType: number;
  135. private _isCube = false;
  136. /**
  137. * Creates a ShadowGenerator object.
  138. * A ShadowGenerator is the required tool to use the shadows.
  139. * Each light casting shadows needs to use its own ShadowGenerator.
  140. * Required parameters :
  141. * - `mapSize` (integer), the size of the texture what stores the shadows. Example : 1024.
  142. * - `light` : the light object generating the shadows.
  143. * Documentation : http://doc.babylonjs.com/tutorials/shadows
  144. */
  145. constructor(mapSize: number, light: IShadowLight) {
  146. this._mapSize = mapSize;
  147. this._light = light;
  148. this._scene = light.getScene();
  149. light._shadowGenerator = this;
  150. // Texture type fallback from float to int if not supported.
  151. var caps = this._scene.getEngine().getCaps();
  152. if (caps.textureFloatRender && caps.textureFloatLinearFiltering) {
  153. this._textureType = Engine.TEXTURETYPE_FLOAT;
  154. }
  155. else if (caps.textureHalfFloatRender && caps.textureHalfFloatLinearFiltering) {
  156. this._textureType = Engine.TEXTURETYPE_HALF_FLOAT;
  157. }
  158. else {
  159. this._textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
  160. }
  161. this._initializeGenerator(1);
  162. }
  163. private _initializeGenerator(boxBlurOffset: number): void {
  164. var light = this._light;
  165. var scene = this._scene;
  166. var textureType = this._textureType;
  167. light._markMeshesAsLightDirty();
  168. // Render target
  169. this._shadowMap = new RenderTargetTexture(light.name + "_shadowMap", this._mapSize, this._scene, false, true, textureType, light.needCube());
  170. this._shadowMap.wrapU = Texture.CLAMP_ADDRESSMODE;
  171. this._shadowMap.wrapV = Texture.CLAMP_ADDRESSMODE;
  172. this._shadowMap.anisotropicFilteringLevel = 1;
  173. this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  174. this._shadowMap.renderParticles = false;
  175. this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
  176. this._currentFaceIndex = faceIndex;
  177. });
  178. this._shadowMap.onAfterUnbindObservable.add(() => {
  179. if (!this.useBlurExponentialShadowMap) {
  180. return;
  181. }
  182. if (!this._shadowMap2) {
  183. this._shadowMap2 = new RenderTargetTexture(light.name + "_shadowMap", this._mapSize, this._scene, false, true, textureType);
  184. this._shadowMap2.wrapU = Texture.CLAMP_ADDRESSMODE;
  185. this._shadowMap2.wrapV = Texture.CLAMP_ADDRESSMODE;
  186. this._shadowMap2.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  187. this._downSamplePostprocess = new PassPostProcess("downScale", 1.0 / this.blurScale, null, Texture.BILINEAR_SAMPLINGMODE, this._scene.getEngine(), false, textureType);
  188. this._downSamplePostprocess.onApplyObservable.add(effect => {
  189. effect.setTexture("textureSampler", this._shadowMap);
  190. });
  191. this.blurBoxOffset = boxBlurOffset;
  192. }
  193. this._scene.postProcessManager.directRender([this._downSamplePostprocess, this._boxBlurPostprocess], this._shadowMap2.getInternalTexture());
  194. });
  195. // Custom render function
  196. var renderSubMesh = (subMesh: SubMesh): void => {
  197. var mesh = subMesh.getRenderingMesh();
  198. var scene = this._scene;
  199. var engine = scene.getEngine();
  200. // Culling
  201. engine.setState(subMesh.getMaterial().backFaceCulling);
  202. // Managing instances
  203. var batch = mesh._getInstancesRenderList(subMesh._id);
  204. if (batch.mustReturn) {
  205. return;
  206. }
  207. var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
  208. if (this.isReady(subMesh, hardwareInstancedRendering)) {
  209. engine.enableEffect(this._effect);
  210. mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
  211. var material = subMesh.getMaterial();
  212. this._effect.setFloat2("biasAndScale", this.bias, this.depthScale);
  213. this._effect.setMatrix("viewProjection", this.getTransformMatrix());
  214. this._effect.setVector3("lightPosition", this.getLight().position);
  215. if (this.getLight().needCube()) {
  216. this._effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.maxZ);
  217. }
  218. // Alpha test
  219. if (material && material.needAlphaTesting()) {
  220. var alphaTexture = material.getAlphaTestTexture();
  221. this._effect.setTexture("diffuseSampler", alphaTexture);
  222. this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
  223. }
  224. // Bones
  225. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  226. this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
  227. }
  228. if (this.forceBackFacesOnly) {
  229. engine.setState(true, 0, false, true);
  230. }
  231. // Draw
  232. mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
  233. (isInstance, world) => this._effect.setMatrix("world", world));
  234. if (this.forceBackFacesOnly) {
  235. engine.setState(true, 0, false, false);
  236. }
  237. } else {
  238. // Need to reset refresh rate of the shadowMap
  239. this._shadowMap.resetRefreshCounter();
  240. }
  241. };
  242. this._shadowMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>): void => {
  243. var index: number;
  244. for (index = 0; index < opaqueSubMeshes.length; index++) {
  245. renderSubMesh(opaqueSubMeshes.data[index]);
  246. }
  247. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  248. renderSubMesh(alphaTestSubMeshes.data[index]);
  249. }
  250. if (this._transparencyShadow) {
  251. for (index = 0; index < transparentSubMeshes.length; index++) {
  252. renderSubMesh(transparentSubMeshes.data[index]);
  253. }
  254. }
  255. };
  256. this._shadowMap.onClearObservable.add((engine: Engine) => {
  257. if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  258. engine.clear(new Color4(0, 0, 0, 0), true, true, true);
  259. } else {
  260. engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
  261. }
  262. });
  263. }
  264. private _applyFilterValues(): void {
  265. if (this.usePoissonSampling || this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  266. this._shadowMap.anisotropicFilteringLevel = 16;
  267. this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
  268. } else {
  269. this._shadowMap.anisotropicFilteringLevel = 1;
  270. this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
  271. }
  272. }
  273. public recreateShadowMap(): void {
  274. // Track render list.
  275. var renderList = this._shadowMap.renderList;
  276. // Clean up existing data.
  277. this._disposeRTTandPostProcesses();
  278. // Reinitializes.
  279. this._initializeGenerator(this.blurBoxOffset);
  280. // Reaffect the blur ESM to ensure a correct fallback if necessary.
  281. if (this.useBlurExponentialShadowMap) {
  282. this.useBlurExponentialShadowMap = true;
  283. }
  284. // Reaffect the filter.
  285. this._applyFilterValues();
  286. // Reaffect Render List.
  287. this._shadowMap.renderList = renderList;
  288. }
  289. /**
  290. * Boolean : true when the ShadowGenerator is finally computed.
  291. */
  292. public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
  293. var defines = [];
  294. if (this._textureType !== Engine.TEXTURETYPE_UNSIGNED_INT) {
  295. defines.push("#define FLOAT");
  296. }
  297. if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  298. defines.push("#define ESM");
  299. }
  300. if (this.getLight().needCube()) {
  301. defines.push("#define CUBEMAP");
  302. }
  303. var attribs = [VertexBuffer.PositionKind];
  304. var mesh = subMesh.getMesh();
  305. var material = subMesh.getMaterial();
  306. // Alpha test
  307. if (material && material.needAlphaTesting()) {
  308. defines.push("#define ALPHATEST");
  309. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  310. attribs.push(VertexBuffer.UVKind);
  311. defines.push("#define UV1");
  312. }
  313. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  314. var alphaTexture = material.getAlphaTestTexture();
  315. if (alphaTexture.coordinatesIndex === 1) {
  316. attribs.push(VertexBuffer.UV2Kind);
  317. defines.push("#define UV2");
  318. }
  319. }
  320. }
  321. // Bones
  322. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  323. attribs.push(VertexBuffer.MatricesIndicesKind);
  324. attribs.push(VertexBuffer.MatricesWeightsKind);
  325. if (mesh.numBoneInfluencers > 4) {
  326. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  327. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  328. }
  329. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  330. defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
  331. } else {
  332. defines.push("#define NUM_BONE_INFLUENCERS 0");
  333. }
  334. // Instances
  335. if (useInstances) {
  336. defines.push("#define INSTANCES");
  337. attribs.push("world0");
  338. attribs.push("world1");
  339. attribs.push("world2");
  340. attribs.push("world3");
  341. }
  342. // Get correct effect
  343. var join = defines.join("\n");
  344. if (this._cachedDefines !== join) {
  345. this._cachedDefines = join;
  346. this._effect = this._scene.getEngine().createEffect("shadowMap",
  347. attribs,
  348. ["world", "mBones", "viewProjection", "diffuseMatrix", "lightPosition", "depthValues", "biasAndScale"],
  349. ["diffuseSampler"], join);
  350. }
  351. return this._effect.isReady();
  352. }
  353. /**
  354. * Returns a RenderTargetTexture object : the shadow map texture.
  355. */
  356. public getShadowMap(): RenderTargetTexture {
  357. return this._shadowMap;
  358. }
  359. /**
  360. * Returns the most ready computed shadow map as a RenderTargetTexture object.
  361. */
  362. public getShadowMapForRendering(): RenderTargetTexture {
  363. if (this._shadowMap2) {
  364. return this._shadowMap2;
  365. }
  366. return this._shadowMap;
  367. }
  368. /**
  369. * Returns the associated light object.
  370. */
  371. public getLight(): IShadowLight {
  372. return this._light;
  373. }
  374. // Methods
  375. /**
  376. * Returns a Matrix object : the updated transformation matrix.
  377. */
  378. public getTransformMatrix(): Matrix {
  379. var scene = this._scene;
  380. if (this._currentRenderID === scene.getRenderId() && this._currentFaceIndexCache === this._currentFaceIndex) {
  381. return this._transformMatrix;
  382. }
  383. this._currentRenderID = scene.getRenderId();
  384. this._currentFaceIndexCache = this._currentFaceIndex;
  385. var lightPosition = this._light.position;
  386. if (this._light.computeTransformedInformation()) {
  387. lightPosition = this._light.transformedPosition;
  388. }
  389. Vector3.NormalizeToRef(this._light.getShadowDirection(this._currentFaceIndex), this._lightDirection);
  390. if (Math.abs(Vector3.Dot(this._lightDirection, Vector3.Up())) === 1.0) {
  391. this._lightDirection.z = 0.0000000000001; // Required to avoid perfectly perpendicular light
  392. }
  393. if (this._light.needProjectionMatrixCompute() || !this._cachedPosition || !this._cachedDirection || !lightPosition.equals(this._cachedPosition) || !this._lightDirection.equals(this._cachedDirection)) {
  394. this._cachedPosition = lightPosition.clone();
  395. this._cachedDirection = this._lightDirection.clone();
  396. Matrix.LookAtLHToRef(lightPosition, lightPosition.add(this._lightDirection), Vector3.Up(), this._viewMatrix);
  397. this._light.setShadowProjectionMatrix(this._projectionMatrix, this._viewMatrix, this.getShadowMap().renderList);
  398. this._viewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  399. }
  400. return this._transformMatrix;
  401. }
  402. /**
  403. * Returns the darkness value (float).
  404. */
  405. public getDarkness(): number {
  406. return this._darkness;
  407. }
  408. /**
  409. * Sets the ShadowGenerator darkness value (float <= 1.0).
  410. * Returns the ShadowGenerator.
  411. */
  412. public setDarkness(darkness: number): ShadowGenerator {
  413. if (darkness >= 1.0)
  414. this._darkness = 1.0;
  415. else if (darkness <= 0.0)
  416. this._darkness = 0.0;
  417. else
  418. this._darkness = darkness;
  419. return this;
  420. }
  421. /**
  422. * Sets the ability to have transparent shadow (boolean).
  423. * Returns the ShadowGenerator.
  424. */
  425. public setTransparencyShadow(hasShadow: boolean): ShadowGenerator {
  426. this._transparencyShadow = hasShadow;
  427. return this;
  428. }
  429. private _packHalf(depth: number): Vector2 {
  430. var scale = depth * 255.0;
  431. var fract = scale - Math.floor(scale);
  432. return new Vector2(depth - fract / 255.0, fract);
  433. }
  434. private _disposeRTTandPostProcesses(): void {
  435. if (this._shadowMap) {
  436. this._shadowMap.dispose();
  437. this._shadowMap = null;
  438. }
  439. if (this._shadowMap2) {
  440. this._shadowMap2.dispose();
  441. this._shadowMap2 = null;
  442. }
  443. if (this._downSamplePostprocess) {
  444. this._downSamplePostprocess.dispose();
  445. this._downSamplePostprocess = null;
  446. }
  447. if (this._boxBlurPostprocess) {
  448. this._boxBlurPostprocess.dispose();
  449. this._boxBlurPostprocess = null;
  450. }
  451. }
  452. /**
  453. * Disposes the ShadowGenerator.
  454. * Returns nothing.
  455. */
  456. public dispose(): void {
  457. this._disposeRTTandPostProcesses();
  458. this._light._shadowGenerator = null;
  459. this._light._markMeshesAsLightDirty();
  460. }
  461. /**
  462. * Serializes the ShadowGenerator and returns a serializationObject.
  463. */
  464. public serialize(): any {
  465. var serializationObject: any = {};
  466. var shadowMap = this.getShadowMap();
  467. serializationObject.lightId = this._light.id;
  468. serializationObject.mapSize = shadowMap.getRenderSize();
  469. serializationObject.useExponentialShadowMap = this.useExponentialShadowMap;
  470. serializationObject.useBlurExponentialShadowMap = this.useBlurExponentialShadowMap;
  471. serializationObject.usePoissonSampling = this.usePoissonSampling;
  472. serializationObject.forceBackFacesOnly = this.forceBackFacesOnly;
  473. serializationObject.depthScale = this.depthScale;
  474. serializationObject.darkness = this.getDarkness();
  475. serializationObject.renderList = [];
  476. for (var meshIndex = 0; meshIndex < shadowMap.renderList.length; meshIndex++) {
  477. var mesh = shadowMap.renderList[meshIndex];
  478. serializationObject.renderList.push(mesh.id);
  479. }
  480. return serializationObject;
  481. }
  482. /**
  483. * Parses a serialized ShadowGenerator and returns a new ShadowGenerator.
  484. */
  485. public static Parse(parsedShadowGenerator: any, scene: Scene): ShadowGenerator {
  486. //casting to point light, as light is missing the position attr and typescript complains.
  487. var light = <PointLight>scene.getLightByID(parsedShadowGenerator.lightId);
  488. var shadowGenerator = new ShadowGenerator(parsedShadowGenerator.mapSize, light);
  489. var shadowMap = shadowGenerator.getShadowMap();
  490. for (var meshIndex = 0; meshIndex < parsedShadowGenerator.renderList.length; meshIndex++) {
  491. var meshes = scene.getMeshesByID(parsedShadowGenerator.renderList[meshIndex]);
  492. meshes.forEach(function (mesh) {
  493. shadowMap.renderList.push(mesh);
  494. });
  495. }
  496. if (parsedShadowGenerator.usePoissonSampling) {
  497. shadowGenerator.usePoissonSampling = true;
  498. }
  499. else if (parsedShadowGenerator.useExponentialShadowMap) {
  500. shadowGenerator.useExponentialShadowMap = true;
  501. }
  502. else if (parsedShadowGenerator.useBlurExponentialShadowMap) {
  503. shadowGenerator.useBlurExponentialShadowMap = true;
  504. }
  505. // Backward compat
  506. else if (parsedShadowGenerator.useVarianceShadowMap) {
  507. shadowGenerator.useExponentialShadowMap = true;
  508. }
  509. else if (parsedShadowGenerator.useBlurVarianceShadowMap) {
  510. shadowGenerator.useBlurExponentialShadowMap = true;
  511. }
  512. if (parsedShadowGenerator.depthScale) {
  513. shadowGenerator.depthScale = parsedShadowGenerator.depthScale;
  514. }
  515. if (parsedShadowGenerator.blurScale) {
  516. shadowGenerator.blurScale = parsedShadowGenerator.blurScale;
  517. }
  518. if (parsedShadowGenerator.blurBoxOffset) {
  519. shadowGenerator.blurBoxOffset = parsedShadowGenerator.blurBoxOffset;
  520. }
  521. if (parsedShadowGenerator.bias !== undefined) {
  522. shadowGenerator.bias = parsedShadowGenerator.bias;
  523. }
  524. if (parsedShadowGenerator.darkness) {
  525. shadowGenerator.setDarkness(parsedShadowGenerator.darkness);
  526. }
  527. shadowGenerator.forceBackFacesOnly = parsedShadowGenerator.forceBackFacesOnly;
  528. return shadowGenerator;
  529. }
  530. /**
  531. * This creates the defines related to the standard BJS materials.
  532. */
  533. public prepareDefines(defines: MaterialDefines, lightIndex: number): void {
  534. var scene = this._scene;
  535. var light = this._light;
  536. if (!scene.shadowsEnabled || !light.shadowEnabled) {
  537. return;
  538. }
  539. defines["SHADOW" + lightIndex] = true;
  540. if (this.usePoissonSampling) {
  541. defines["SHADOWPCF" + lightIndex] = true;
  542. }
  543. else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
  544. defines["SHADOWESM" + lightIndex] = true;
  545. }
  546. if (light.needCube()) {
  547. defines["SHADOWCUBE" + lightIndex] = true;
  548. }
  549. }
  550. /**
  551. * This binds shadow lights related to the standard BJS materials.
  552. * It implies the unifroms available on the materials are the standard BJS ones.
  553. */
  554. public bindShadowLight(lightIndex: string, effect: Effect, depthValuesAlreadySet: boolean): boolean {
  555. var light = this._light;
  556. var scene = this._scene;
  557. if (!scene.shadowsEnabled || !light.shadowEnabled) {
  558. return;
  559. }
  560. if (!light.needCube()) {
  561. effect.setMatrix("lightMatrix" + lightIndex, this.getTransformMatrix());
  562. } else {
  563. if (!depthValuesAlreadySet) {
  564. depthValuesAlreadySet = true;
  565. effect.setFloat2("depthValues", scene.activeCamera.minZ, scene.activeCamera.maxZ);
  566. }
  567. }
  568. effect.setTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
  569. light._uniformBuffer.updateFloat3("shadowsInfo", this.getDarkness(), this.blurScale / this.getShadowMap().getSize().width, this.depthScale, lightIndex);
  570. return depthValuesAlreadySet;
  571. }
  572. }
  573. }