babylon.geometryBufferRenderer.ts 8.5 KB

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