babylon.geometryBufferRenderer.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. module BABYLON {
  2. export class GeometryBufferRenderer {
  3. private _scene: Scene;
  4. private _multiRenderTarget: MultiRenderTarget;
  5. private _effect: Effect;
  6. private _ratio: number;
  7. private _cachedDefines: string;
  8. private _enablePosition: boolean = false;
  9. public set renderList(meshes: Mesh[]) {
  10. this._multiRenderTarget.renderList = meshes;
  11. }
  12. public get isSupported(): boolean {
  13. return this._multiRenderTarget.isSupported;
  14. }
  15. public get enablePosition(): boolean {
  16. return this._enablePosition;
  17. }
  18. public set enablePosition(enable: boolean) {
  19. this._enablePosition = enable;
  20. this.dispose();
  21. this._createRenderTargets();
  22. }
  23. constructor(scene: Scene, ratio: number = 1) {
  24. this._scene = scene;
  25. this._ratio = ratio;
  26. // Render target
  27. this._createRenderTargets();
  28. }
  29. public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
  30. var material: any = subMesh.getMaterial();
  31. if (material && material.disableDepthWrite) {
  32. return false;
  33. }
  34. var defines = [];
  35. var attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
  36. var mesh = subMesh.getMesh();
  37. // Alpha test
  38. if (material && material.needAlphaTesting()) {
  39. defines.push("#define ALPHATEST");
  40. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  41. attribs.push(VertexBuffer.UVKind);
  42. defines.push("#define UV1");
  43. }
  44. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  45. attribs.push(VertexBuffer.UV2Kind);
  46. defines.push("#define UV2");
  47. }
  48. }
  49. // Buffers
  50. if (this._enablePosition) {
  51. defines.push("#define POSITION");
  52. }
  53. // Bones
  54. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  55. attribs.push(VertexBuffer.MatricesIndicesKind);
  56. attribs.push(VertexBuffer.MatricesWeightsKind);
  57. if (mesh.numBoneInfluencers > 4) {
  58. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  59. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  60. }
  61. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  62. defines.push("#define BonesPerMesh " + (mesh.skeleton ? mesh.skeleton.bones.length + 1 : 0));
  63. } else {
  64. defines.push("#define NUM_BONE_INFLUENCERS 0");
  65. }
  66. // Instances
  67. if (useInstances) {
  68. defines.push("#define INSTANCES");
  69. attribs.push("world0");
  70. attribs.push("world1");
  71. attribs.push("world2");
  72. attribs.push("world3");
  73. }
  74. // Get correct effect
  75. var join = defines.join("\n");
  76. if (this._cachedDefines !== join) {
  77. this._cachedDefines = join;
  78. this._effect = this._scene.getEngine().createEffect("geometry",
  79. attribs,
  80. ["world", "mBones", "viewProjection", "diffuseMatrix", "view"],
  81. ["diffuseSampler"], join,
  82. undefined, undefined, undefined,
  83. { buffersCount: this._enablePosition ? 3 : 2 });
  84. }
  85. return this._effect.isReady();
  86. }
  87. public getGBuffer(): MultiRenderTarget {
  88. return this._multiRenderTarget;
  89. }
  90. // Methods
  91. public dispose(): void {
  92. this.getGBuffer().dispose();
  93. }
  94. private _createRenderTargets(): void {
  95. var engine = this._scene.getEngine();
  96. var count = this._enablePosition ? 3 : 2;
  97. this._multiRenderTarget = new MultiRenderTarget("gBuffer", { width: engine.getRenderWidth() * this._ratio, height: engine.getRenderHeight() * this._ratio }, count, this._scene, { generateMipMaps : false, generateDepthTexture: true });
  98. if (!this.isSupported) {
  99. return;
  100. }
  101. this._multiRenderTarget.wrapU = Texture.CLAMP_ADDRESSMODE;
  102. this._multiRenderTarget.wrapV = Texture.CLAMP_ADDRESSMODE;
  103. this._multiRenderTarget.refreshRate = 1;
  104. this._multiRenderTarget.renderParticles = false;
  105. this._multiRenderTarget.renderList = null;
  106. // set default depth value to 1.0 (far away)
  107. this._multiRenderTarget.onClearObservable.add((engine: Engine) => {
  108. engine.clear(new Color4(0.0, 0.0, 0.0, 1.0), true, true, true);
  109. });
  110. // Custom render function
  111. var renderSubMesh = (subMesh: SubMesh): void => {
  112. var mesh = subMesh.getRenderingMesh();
  113. var scene = this._scene;
  114. var engine = scene.getEngine();
  115. let material = subMesh.getMaterial();
  116. if (!material) {
  117. return;
  118. }
  119. // Culling
  120. engine.setState(material.backFaceCulling);
  121. // Managing instances
  122. var batch = mesh._getInstancesRenderList(subMesh._id);
  123. if (batch.mustReturn) {
  124. return;
  125. }
  126. var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null);
  127. if (this.isReady(subMesh, hardwareInstancedRendering)) {
  128. engine.enableEffect(this._effect);
  129. mesh._bind(subMesh, this._effect, Material.TriangleFillMode);
  130. this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
  131. this._effect.setMatrix("view", scene.getViewMatrix());
  132. // Alpha test
  133. if (material && material.needAlphaTesting()) {
  134. var alphaTexture = material.getAlphaTestTexture();
  135. if (alphaTexture) {
  136. this._effect.setTexture("diffuseSampler", alphaTexture);
  137. this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
  138. }
  139. }
  140. // Bones
  141. if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
  142. this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices(mesh));
  143. }
  144. // Draw
  145. mesh._processRendering(subMesh, this._effect, Material.TriangleFillMode, batch, hardwareInstancedRendering,
  146. (isInstance, world) => this._effect.setMatrix("world", world));
  147. }
  148. };
  149. this._multiRenderTarget.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
  150. var index;
  151. if (depthOnlySubMeshes.length) {
  152. engine.setColorWrite(false);
  153. for (index = 0; index < depthOnlySubMeshes.length; index++) {
  154. renderSubMesh(depthOnlySubMeshes.data[index]);
  155. }
  156. engine.setColorWrite(true);
  157. }
  158. for (index = 0; index < opaqueSubMeshes.length; index++) {
  159. renderSubMesh(opaqueSubMeshes.data[index]);
  160. }
  161. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  162. renderSubMesh(alphaTestSubMeshes.data[index]);
  163. }
  164. };
  165. }
  166. }
  167. }