depthRenderer.ts 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import { Nullable } from "../types";
  2. import { Color4 } from "../Maths/math";
  3. import { SubMesh } from "../Meshes/subMesh";
  4. import { VertexBuffer } from "../Meshes/buffer";
  5. import { SmartArray } from "../Misc/smartArray";
  6. import { Scene } from "../scene";
  7. import { Texture } from "../Materials/Textures/texture";
  8. import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
  9. import { Effect } from "../Materials/effect";
  10. import { Material } from "../Materials/material";
  11. import { Camera } from "../Cameras/camera";
  12. import { Constants } from "../Engines/constants";
  13. import "../Shaders/depth.fragment";
  14. import "../Shaders/depth.vertex";
  15. import { _DevTools } from '../Misc/devTools';
  16. /**
  17. * This represents a depth renderer in Babylon.
  18. * A depth renderer will render to it's depth map every frame which can be displayed or used in post processing
  19. */
  20. export class DepthRenderer {
  21. private _scene: Scene;
  22. private _depthMap: RenderTargetTexture;
  23. private _effect: Effect;
  24. private _cachedDefines: string;
  25. private _camera: Nullable<Camera>;
  26. /**
  27. * Specifiess that the depth renderer will only be used within
  28. * the camera it is created for.
  29. * This can help forcing its rendering during the camera processing.
  30. */
  31. public useOnlyInActiveCamera: boolean = false;
  32. /** @hidden */
  33. public static _SceneComponentInitialization: (scene: Scene) => void = (_) => {
  34. throw _DevTools.WarnImport("DepthRendererSceneComponent");
  35. }
  36. /**
  37. * Instantiates a depth renderer
  38. * @param scene The scene the renderer belongs to
  39. * @param type The texture type of the depth map (default: Engine.TEXTURETYPE_FLOAT)
  40. * @param camera The camera to be used to render the depth map (default: scene's active camera)
  41. */
  42. constructor(scene: Scene, type: number = Constants.TEXTURETYPE_FLOAT, camera: Nullable<Camera> = null) {
  43. this._scene = scene;
  44. DepthRenderer._SceneComponentInitialization(this._scene);
  45. this._camera = camera;
  46. var engine = scene.getEngine();
  47. // Render target
  48. this._depthMap = new RenderTargetTexture("depthMap", { width: engine.getRenderWidth(), height: engine.getRenderHeight() }, this._scene, false, true, type);
  49. this._depthMap.wrapU = Texture.CLAMP_ADDRESSMODE;
  50. this._depthMap.wrapV = Texture.CLAMP_ADDRESSMODE;
  51. this._depthMap.refreshRate = 1;
  52. this._depthMap.renderParticles = false;
  53. this._depthMap.renderList = null;
  54. // Camera to get depth map from to support multiple concurrent cameras
  55. this._depthMap.activeCamera = this._camera;
  56. this._depthMap.ignoreCameraViewport = true;
  57. this._depthMap.useCameraPostProcesses = false;
  58. // set default depth value to 1.0 (far away)
  59. this._depthMap.onClearObservable.add((engine) => {
  60. engine.clear(new Color4(1.0, 1.0, 1.0, 1.0), true, true, true);
  61. });
  62. // Custom render function
  63. var renderSubMesh = (subMesh: SubMesh): void => {
  64. var mesh = subMesh.getRenderingMesh();
  65. var scene = this._scene;
  66. var engine = scene.getEngine();
  67. let material = subMesh.getMaterial();
  68. if (!material) {
  69. return;
  70. }
  71. // Culling and reverse (right handed system)
  72. engine.setState(material.backFaceCulling, 0, false, scene.useRightHandedSystem);
  73. // Managing instances
  74. var batch = mesh._getInstancesRenderList(subMesh._id);
  75. if (batch.mustReturn) {
  76. return;
  77. }
  78. var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
  79. var camera = this._camera || scene.activeCamera;
  80. if (this.isReady(subMesh, hardwareInstancedRendering) && camera) {
  81. engine.enableEffect(this._effect);
  82. mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
  83. this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
  84. this._effect.setFloat2("depthValues", camera.minZ, camera.minZ + camera.maxZ);
  85. // Alpha test
  86. if (material && material.needAlphaTesting()) {
  87. var alphaTexture = material.getAlphaTestTexture();
  88. if (alphaTexture) {
  89. this._effect.setTexture("diffuseSampler", alphaTexture);
  90. this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
  91. }
  92. }
  93. // Bones
  94. if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
  95. this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
  96. }
  97. // Draw
  98. mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
  99. (isInstance, world) => this._effect.setMatrix("world", world));
  100. }
  101. };
  102. this._depthMap.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
  103. var index;
  104. if (depthOnlySubMeshes.length) {
  105. engine.setColorWrite(false);
  106. for (index = 0; index < depthOnlySubMeshes.length; index++) {
  107. renderSubMesh(depthOnlySubMeshes.data[index]);
  108. }
  109. engine.setColorWrite(true);
  110. }
  111. for (index = 0; index < opaqueSubMeshes.length; index++) {
  112. renderSubMesh(opaqueSubMeshes.data[index]);
  113. }
  114. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  115. renderSubMesh(alphaTestSubMeshes.data[index]);
  116. }
  117. };
  118. }
  119. /**
  120. * Creates the depth rendering effect and checks if the effect is ready.
  121. * @param subMesh The submesh to be used to render the depth map of
  122. * @param useInstances If multiple world instances should be used
  123. * @returns if the depth renderer is ready to render the depth map
  124. */
  125. public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
  126. var material: any = subMesh.getMaterial();
  127. if (material.disableDepthWrite) {
  128. return false;
  129. }
  130. var defines = [];
  131. var attribs = [VertexBuffer.PositionKind];
  132. var mesh = subMesh.getMesh();
  133. // Alpha test
  134. if (material && material.needAlphaTesting() && material.getAlphaTestTexture()) {
  135. defines.push("#define ALPHATEST");
  136. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  137. attribs.push(VertexBuffer.UVKind);
  138. defines.push("#define UV1");
  139. }
  140. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  141. attribs.push(VertexBuffer.UV2Kind);
  142. defines.push("#define UV2");
  143. }
  144. }
  145. // Bones
  146. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  147. attribs.push(VertexBuffer.MatricesIndicesKind);
  148. attribs.push(VertexBuffer.MatricesWeightsKind);
  149. if (mesh.numBoneInfluencers > 4) {
  150. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  151. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  152. }
  153. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  154. defines.push("#define BonesPerMesh " + (mesh.skeleton ? mesh.skeleton.bones.length + 1 : 0));
  155. } else {
  156. defines.push("#define NUM_BONE_INFLUENCERS 0");
  157. }
  158. // Instances
  159. if (useInstances) {
  160. defines.push("#define INSTANCES");
  161. attribs.push("world0");
  162. attribs.push("world1");
  163. attribs.push("world2");
  164. attribs.push("world3");
  165. }
  166. // Get correct effect
  167. var join = defines.join("\n");
  168. if (this._cachedDefines !== join) {
  169. this._cachedDefines = join;
  170. this._effect = this._scene.getEngine().createEffect("depth",
  171. attribs,
  172. ["world", "mBones", "viewProjection", "diffuseMatrix", "depthValues"],
  173. ["diffuseSampler"], join);
  174. }
  175. return this._effect.isReady();
  176. }
  177. /**
  178. * Gets the texture which the depth map will be written to.
  179. * @returns The depth map texture
  180. */
  181. public getDepthMap(): RenderTargetTexture {
  182. return this._depthMap;
  183. }
  184. /**
  185. * Disposes of the depth renderer.
  186. */
  187. public dispose(): void {
  188. this._depthMap.dispose();
  189. }
  190. }