geometryBufferRenderer.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  1. import { Matrix } from "../Maths/math.vector.js";
  2. import { VertexBuffer } from "../Buffers/buffer.js";
  3. import { Texture } from "../Materials/Textures/texture.js";
  4. import { MultiRenderTarget } from "../Materials/Textures/multiRenderTarget.js";
  5. import { Color4 } from "../Maths/math.color.js";
  6. import { _WarnImport } from "../Misc/devTools.js";
  7. import { Material } from "../Materials/material.js";
  8. import "../Shaders/geometry.fragment.js";
  9. import "../Shaders/geometry.vertex.js";
  10. import { MaterialFlags } from "../Materials/materialFlags.js";
  11. import { addClipPlaneUniforms, bindClipPlane, prepareStringDefinesForClipPlanes } from "../Materials/clipPlaneMaterialHelper.js";
  12. import { BindMorphTargetParameters, BindSceneUniformBuffer, PrepareAttributesForMorphTargetsInfluencers, PushAttributesForInstances } from "../Materials/materialHelper.functions.js";
  13. /** list the uniforms used by the geometry renderer */
  14. const uniforms = [
  15. "world",
  16. "mBones",
  17. "viewProjection",
  18. "diffuseMatrix",
  19. "view",
  20. "previousWorld",
  21. "previousViewProjection",
  22. "mPreviousBones",
  23. "bumpMatrix",
  24. "reflectivityMatrix",
  25. "albedoMatrix",
  26. "reflectivityColor",
  27. "albedoColor",
  28. "metallic",
  29. "glossiness",
  30. "vTangentSpaceParams",
  31. "vBumpInfos",
  32. "morphTargetInfluences",
  33. "morphTargetCount",
  34. "morphTargetTextureInfo",
  35. "morphTargetTextureIndices",
  36. "boneTextureWidth",
  37. ];
  38. addClipPlaneUniforms(uniforms);
  39. /**
  40. * This renderer is helpful to fill one of the render target with a geometry buffer.
  41. */
  42. export class GeometryBufferRenderer {
  43. /**
  44. * Gets a boolean indicating if normals are encoded in the [0,1] range in the render target. If true, you should do `normal = normal_rt * 2.0 - 1.0` to get the right normal
  45. */
  46. get normalsAreUnsigned() {
  47. return this._normalsAreUnsigned;
  48. }
  49. /**
  50. * @internal
  51. * Sets up internal structures to share outputs with PrePassRenderer
  52. * This method should only be called by the PrePassRenderer itself
  53. */
  54. _linkPrePassRenderer(prePassRenderer) {
  55. this._linkedWithPrePass = true;
  56. this._prePassRenderer = prePassRenderer;
  57. if (this._multiRenderTarget) {
  58. // prevents clearing of the RT since it's done by prepass
  59. this._multiRenderTarget.onClearObservable.clear();
  60. this._multiRenderTarget.onClearObservable.add(() => {
  61. // pass
  62. });
  63. }
  64. }
  65. /**
  66. * @internal
  67. * Separates internal structures from PrePassRenderer so the geometry buffer can now operate by itself.
  68. * This method should only be called by the PrePassRenderer itself
  69. */
  70. _unlinkPrePassRenderer() {
  71. this._linkedWithPrePass = false;
  72. this._createRenderTargets();
  73. }
  74. /**
  75. * @internal
  76. * Resets the geometry buffer layout
  77. */
  78. _resetLayout() {
  79. this._enablePosition = false;
  80. this._enableReflectivity = false;
  81. this._enableVelocity = false;
  82. this._attachmentsFromPrePass = [];
  83. }
  84. /**
  85. * @internal
  86. * Replaces a texture in the geometry buffer renderer
  87. * Useful when linking textures of the prepass renderer
  88. */
  89. _forceTextureType(geometryBufferType, index) {
  90. if (geometryBufferType === GeometryBufferRenderer.POSITION_TEXTURE_TYPE) {
  91. this._positionIndex = index;
  92. this._enablePosition = true;
  93. }
  94. else if (geometryBufferType === GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE) {
  95. this._velocityIndex = index;
  96. this._enableVelocity = true;
  97. }
  98. else if (geometryBufferType === GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE) {
  99. this._reflectivityIndex = index;
  100. this._enableReflectivity = true;
  101. }
  102. else if (geometryBufferType === GeometryBufferRenderer.DEPTH_TEXTURE_TYPE) {
  103. this._depthIndex = index;
  104. }
  105. else if (geometryBufferType === GeometryBufferRenderer.NORMAL_TEXTURE_TYPE) {
  106. this._normalIndex = index;
  107. }
  108. }
  109. /**
  110. * @internal
  111. * Sets texture attachments
  112. * Useful when linking textures of the prepass renderer
  113. */
  114. _setAttachments(attachments) {
  115. this._attachmentsFromPrePass = attachments;
  116. }
  117. /**
  118. * @internal
  119. * Replaces the first texture which is hard coded as a depth texture in the geometry buffer
  120. * Useful when linking textures of the prepass renderer
  121. */
  122. _linkInternalTexture(internalTexture) {
  123. this._multiRenderTarget.setInternalTexture(internalTexture, 0, false);
  124. }
  125. /**
  126. * Gets the render list (meshes to be rendered) used in the G buffer.
  127. */
  128. get renderList() {
  129. return this._multiRenderTarget.renderList;
  130. }
  131. /**
  132. * Set the render list (meshes to be rendered) used in the G buffer.
  133. */
  134. set renderList(meshes) {
  135. this._multiRenderTarget.renderList = meshes;
  136. }
  137. /**
  138. * Gets whether or not G buffer are supported by the running hardware.
  139. * This requires draw buffer supports
  140. */
  141. get isSupported() {
  142. return this._multiRenderTarget.isSupported;
  143. }
  144. /**
  145. * Returns the index of the given texture type in the G-Buffer textures array
  146. * @param textureType The texture type constant. For example GeometryBufferRenderer.POSITION_TEXTURE_INDEX
  147. * @returns the index of the given texture type in the G-Buffer textures array
  148. */
  149. getTextureIndex(textureType) {
  150. switch (textureType) {
  151. case GeometryBufferRenderer.POSITION_TEXTURE_TYPE:
  152. return this._positionIndex;
  153. case GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE:
  154. return this._velocityIndex;
  155. case GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE:
  156. return this._reflectivityIndex;
  157. case GeometryBufferRenderer.DEPTH_TEXTURE_TYPE:
  158. return this._linkedWithPrePass ? this._depthIndex : 0;
  159. case GeometryBufferRenderer.NORMAL_TEXTURE_TYPE:
  160. return this._linkedWithPrePass ? this._normalIndex : 1;
  161. default:
  162. return -1;
  163. }
  164. }
  165. /**
  166. * @returns a boolean indicating if objects positions are enabled for the G buffer.
  167. */
  168. get enablePosition() {
  169. return this._enablePosition;
  170. }
  171. /**
  172. * Sets whether or not objects positions are enabled for the G buffer.
  173. */
  174. set enablePosition(enable) {
  175. this._enablePosition = enable;
  176. // PrePass handles index and texture links
  177. if (!this._linkedWithPrePass) {
  178. this.dispose();
  179. this._createRenderTargets();
  180. }
  181. }
  182. /**
  183. * @returns a boolean indicating if objects velocities are enabled for the G buffer.
  184. */
  185. get enableVelocity() {
  186. return this._enableVelocity;
  187. }
  188. /**
  189. * Sets whether or not objects velocities are enabled for the G buffer.
  190. */
  191. set enableVelocity(enable) {
  192. this._enableVelocity = enable;
  193. if (!enable) {
  194. this._previousTransformationMatrices = {};
  195. }
  196. if (!this._linkedWithPrePass) {
  197. this.dispose();
  198. this._createRenderTargets();
  199. }
  200. this._scene.needsPreviousWorldMatrices = enable;
  201. }
  202. /**
  203. * Gets a boolean indicating if objects reflectivity are enabled in the G buffer.
  204. */
  205. get enableReflectivity() {
  206. return this._enableReflectivity;
  207. }
  208. /**
  209. * Sets whether or not objects reflectivity are enabled for the G buffer.
  210. * For Metallic-Roughness workflow with ORM texture, we assume that ORM texture is defined according to the default layout:
  211. * pbr.useRoughnessFromMetallicTextureAlpha = false;
  212. * pbr.useRoughnessFromMetallicTextureGreen = true;
  213. * pbr.useMetallnessFromMetallicTextureBlue = true;
  214. */
  215. set enableReflectivity(enable) {
  216. this._enableReflectivity = enable;
  217. if (!this._linkedWithPrePass) {
  218. this.dispose();
  219. this._createRenderTargets();
  220. }
  221. }
  222. /**
  223. * Gets the scene associated with the buffer.
  224. */
  225. get scene() {
  226. return this._scene;
  227. }
  228. /**
  229. * Gets the ratio used by the buffer during its creation.
  230. * How big is the buffer related to the main canvas.
  231. */
  232. get ratio() {
  233. return typeof this._ratioOrDimensions === "object" ? 1 : this._ratioOrDimensions;
  234. }
  235. /**
  236. * Creates a new G Buffer for the scene
  237. * @param scene The scene the buffer belongs to
  238. * @param ratioOrDimensions How big is the buffer related to the main canvas (default: 1). You can also directly pass a width and height for the generated textures
  239. * @param depthFormat Format of the depth texture (default: 15)
  240. * @param textureTypesAndFormats The types and formats of textures to create as render targets. If not provided, all textures will be RGBA and float or half float, depending on the engine capabilities.
  241. */
  242. constructor(scene, ratioOrDimensions = 1, depthFormat = 15, textureTypesAndFormats) {
  243. /**
  244. * Dictionary used to store the previous transformation matrices of each rendered mesh
  245. * in order to compute objects velocities when enableVelocity is set to "true"
  246. * @internal
  247. */
  248. this._previousTransformationMatrices = {};
  249. /**
  250. * Dictionary used to store the previous bones transformation matrices of each rendered mesh
  251. * in order to compute objects velocities when enableVelocity is set to "true"
  252. * @internal
  253. */
  254. this._previousBonesTransformationMatrices = {};
  255. /**
  256. * Array used to store the ignored skinned meshes while computing velocity map (typically used by the motion blur post-process).
  257. * Avoids computing bones velocities and computes only mesh's velocity itself (position, rotation, scaling).
  258. */
  259. this.excludedSkinnedMeshesFromVelocity = [];
  260. /** Gets or sets a boolean indicating if transparent meshes should be rendered */
  261. this.renderTransparentMeshes = true;
  262. /**
  263. * Gets or sets a boolean indicating if normals should be generated in world space (default: false, meaning normals are generated in view space)
  264. */
  265. this.generateNormalsInWorldSpace = false;
  266. this._normalsAreUnsigned = false;
  267. this._resizeObserver = null;
  268. this._enablePosition = false;
  269. this._enableVelocity = false;
  270. this._enableReflectivity = false;
  271. this._clearColor = new Color4(0, 0, 0, 0);
  272. this._clearDepthColor = new Color4(1e8, 0, 0, 1); // "infinity" value - depth in the depth texture is view.z, not a 0..1 value!
  273. this._positionIndex = -1;
  274. this._velocityIndex = -1;
  275. this._reflectivityIndex = -1;
  276. this._depthIndex = -1;
  277. this._normalIndex = -1;
  278. this._linkedWithPrePass = false;
  279. /**
  280. * If set to true (default: false), the depth texture will be cleared with the depth value corresponding to the far plane (1 in normal mode, 0 in reverse depth buffer mode)
  281. * If set to false, the depth texture is always cleared with 0.
  282. */
  283. this.useSpecificClearForDepthTexture = false;
  284. this._scene = scene;
  285. this._ratioOrDimensions = ratioOrDimensions;
  286. this._useUbo = scene.getEngine().supportsUniformBuffers;
  287. this._depthFormat = depthFormat;
  288. this._textureTypesAndFormats = textureTypesAndFormats || {};
  289. GeometryBufferRenderer._SceneComponentInitialization(this._scene);
  290. // Render target
  291. this._createRenderTargets();
  292. }
  293. /**
  294. * Checks whether everything is ready to render a submesh to the G buffer.
  295. * @param subMesh the submesh to check readiness for
  296. * @param useInstances is the mesh drawn using instance or not
  297. * @returns true if ready otherwise false
  298. */
  299. isReady(subMesh, useInstances) {
  300. const material = subMesh.getMaterial();
  301. if (material && material.disableDepthWrite) {
  302. return false;
  303. }
  304. const defines = [];
  305. const attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
  306. const mesh = subMesh.getMesh();
  307. if (material) {
  308. let needUv = false;
  309. // Alpha test
  310. if (material.needAlphaTesting() && material.getAlphaTestTexture()) {
  311. defines.push("#define ALPHATEST");
  312. defines.push(`#define ALPHATEST_UV${material.getAlphaTestTexture().coordinatesIndex + 1}`);
  313. needUv = true;
  314. }
  315. // Normal map texture
  316. if (material.bumpTexture && MaterialFlags.BumpTextureEnabled) {
  317. defines.push("#define BUMP");
  318. defines.push(`#define BUMP_UV${material.bumpTexture.coordinatesIndex + 1}`);
  319. needUv = true;
  320. }
  321. if (this._enableReflectivity) {
  322. let metallicWorkflow = false;
  323. // for PBR materials: cf. https://doc.babylonjs.com/features/featuresDeepDive/materials/using/masterPBR
  324. if (material.getClassName() === "PBRMetallicRoughnessMaterial") {
  325. // if it is a PBR material in MetallicRoughness Mode:
  326. if (material.metallicRoughnessTexture) {
  327. defines.push("#define ORMTEXTURE");
  328. defines.push(`#define REFLECTIVITY_UV${material.metallicRoughnessTexture.coordinatesIndex + 1}`);
  329. defines.push("#define METALLICWORKFLOW");
  330. needUv = true;
  331. metallicWorkflow = true;
  332. }
  333. // null or undefined
  334. if (material.metallic != null) {
  335. defines.push("#define METALLIC");
  336. defines.push("#define METALLICWORKFLOW");
  337. metallicWorkflow = true;
  338. }
  339. // null or undefined
  340. if (material.roughness != null) {
  341. defines.push("#define ROUGHNESS");
  342. defines.push("#define METALLICWORKFLOW");
  343. metallicWorkflow = true;
  344. }
  345. if (metallicWorkflow) {
  346. if (material.baseTexture) {
  347. defines.push("#define ALBEDOTEXTURE");
  348. defines.push(`#define ALBEDO_UV${material.baseTexture.coordinatesIndex + 1}`);
  349. if (material.baseTexture.gammaSpace) {
  350. defines.push("#define GAMMAALBEDO");
  351. }
  352. needUv = true;
  353. }
  354. if (material.baseColor) {
  355. defines.push("#define ALBEDOCOLOR");
  356. }
  357. }
  358. }
  359. else if (material.getClassName() === "PBRSpecularGlossinessMaterial") {
  360. // if it is a PBR material in Specular/Glossiness Mode:
  361. if (material.specularGlossinessTexture) {
  362. defines.push("#define SPECULARGLOSSINESSTEXTURE");
  363. defines.push(`#define REFLECTIVITY_UV${material.specularGlossinessTexture.coordinatesIndex + 1}`);
  364. needUv = true;
  365. if (material.specularGlossinessTexture.gammaSpace) {
  366. defines.push("#define GAMMAREFLECTIVITYTEXTURE");
  367. }
  368. }
  369. else {
  370. if (material.specularColor) {
  371. defines.push("#define REFLECTIVITYCOLOR");
  372. }
  373. }
  374. // null or undefined
  375. if (material.glossiness != null) {
  376. defines.push("#define GLOSSINESS");
  377. }
  378. }
  379. else if (material.getClassName() === "PBRMaterial") {
  380. // if it is the bigger PBRMaterial
  381. if (material.metallicTexture) {
  382. defines.push("#define ORMTEXTURE");
  383. defines.push(`#define REFLECTIVITY_UV${material.metallicTexture.coordinatesIndex + 1}`);
  384. defines.push("#define METALLICWORKFLOW");
  385. needUv = true;
  386. metallicWorkflow = true;
  387. }
  388. // null or undefined
  389. if (material.metallic != null) {
  390. defines.push("#define METALLIC");
  391. defines.push("#define METALLICWORKFLOW");
  392. metallicWorkflow = true;
  393. }
  394. // null or undefined
  395. if (material.roughness != null) {
  396. defines.push("#define ROUGHNESS");
  397. defines.push("#define METALLICWORKFLOW");
  398. metallicWorkflow = true;
  399. }
  400. if (metallicWorkflow) {
  401. if (material.albedoTexture) {
  402. defines.push("#define ALBEDOTEXTURE");
  403. defines.push(`#define ALBEDO_UV${material.albedoTexture.coordinatesIndex + 1}`);
  404. if (material.albedoTexture.gammaSpace) {
  405. defines.push("#define GAMMAALBEDO");
  406. }
  407. needUv = true;
  408. }
  409. if (material.albedoColor) {
  410. defines.push("#define ALBEDOCOLOR");
  411. }
  412. }
  413. else {
  414. // SpecularGlossiness Model
  415. if (material.reflectivityTexture) {
  416. defines.push("#define SPECULARGLOSSINESSTEXTURE");
  417. defines.push(`#define REFLECTIVITY_UV${material.reflectivityTexture.coordinatesIndex + 1}`);
  418. if (material.reflectivityTexture.gammaSpace) {
  419. defines.push("#define GAMMAREFLECTIVITYTEXTURE");
  420. }
  421. needUv = true;
  422. }
  423. else if (material.reflectivityColor) {
  424. defines.push("#define REFLECTIVITYCOLOR");
  425. }
  426. // null or undefined
  427. if (material.microSurface != null) {
  428. defines.push("#define GLOSSINESS");
  429. }
  430. }
  431. }
  432. else if (material.getClassName() === "StandardMaterial") {
  433. // if StandardMaterial:
  434. if (material.specularTexture) {
  435. defines.push("#define REFLECTIVITYTEXTURE");
  436. defines.push(`#define REFLECTIVITY_UV${material.specularTexture.coordinatesIndex + 1}`);
  437. if (material.specularTexture.gammaSpace) {
  438. defines.push("#define GAMMAREFLECTIVITYTEXTURE");
  439. }
  440. needUv = true;
  441. }
  442. if (material.specularColor) {
  443. defines.push("#define REFLECTIVITYCOLOR");
  444. }
  445. }
  446. }
  447. if (needUv) {
  448. defines.push("#define NEED_UV");
  449. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  450. attribs.push(VertexBuffer.UVKind);
  451. defines.push("#define UV1");
  452. }
  453. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  454. attribs.push(VertexBuffer.UV2Kind);
  455. defines.push("#define UV2");
  456. }
  457. }
  458. }
  459. // PrePass
  460. if (this._linkedWithPrePass) {
  461. defines.push("#define PREPASS");
  462. if (this._depthIndex !== -1) {
  463. defines.push("#define DEPTH_INDEX " + this._depthIndex);
  464. defines.push("#define PREPASS_DEPTH");
  465. }
  466. if (this._normalIndex !== -1) {
  467. defines.push("#define NORMAL_INDEX " + this._normalIndex);
  468. defines.push("#define PREPASS_NORMAL");
  469. }
  470. }
  471. // Buffers
  472. if (this._enablePosition) {
  473. defines.push("#define POSITION");
  474. defines.push("#define POSITION_INDEX " + this._positionIndex);
  475. }
  476. if (this._enableVelocity) {
  477. defines.push("#define VELOCITY");
  478. defines.push("#define VELOCITY_INDEX " + this._velocityIndex);
  479. if (this.excludedSkinnedMeshesFromVelocity.indexOf(mesh) === -1) {
  480. defines.push("#define BONES_VELOCITY_ENABLED");
  481. }
  482. }
  483. if (this._enableReflectivity) {
  484. defines.push("#define REFLECTIVITY");
  485. defines.push("#define REFLECTIVITY_INDEX " + this._reflectivityIndex);
  486. }
  487. if (this.generateNormalsInWorldSpace) {
  488. defines.push("#define NORMAL_WORLDSPACE");
  489. }
  490. if (this._normalsAreUnsigned) {
  491. defines.push("#define ENCODE_NORMAL");
  492. }
  493. // Bones
  494. if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
  495. attribs.push(VertexBuffer.MatricesIndicesKind);
  496. attribs.push(VertexBuffer.MatricesWeightsKind);
  497. if (mesh.numBoneInfluencers > 4) {
  498. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  499. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  500. }
  501. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  502. defines.push("#define BONETEXTURE " + mesh.skeleton.isUsingTextureForMatrices);
  503. defines.push("#define BonesPerMesh " + (mesh.skeleton.bones.length + 1));
  504. }
  505. else {
  506. defines.push("#define NUM_BONE_INFLUENCERS 0");
  507. defines.push("#define BONETEXTURE false");
  508. defines.push("#define BonesPerMesh 0");
  509. }
  510. // Morph targets
  511. const morphTargetManager = mesh.morphTargetManager;
  512. let numMorphInfluencers = 0;
  513. if (morphTargetManager) {
  514. numMorphInfluencers = morphTargetManager.numMaxInfluencers || morphTargetManager.numInfluencers;
  515. if (numMorphInfluencers > 0) {
  516. defines.push("#define MORPHTARGETS");
  517. defines.push("#define NUM_MORPH_INFLUENCERS " + numMorphInfluencers);
  518. if (morphTargetManager.isUsingTextureForTargets) {
  519. defines.push("#define MORPHTARGETS_TEXTURE");
  520. }
  521. PrepareAttributesForMorphTargetsInfluencers(attribs, mesh, numMorphInfluencers);
  522. }
  523. }
  524. // Instances
  525. if (useInstances) {
  526. defines.push("#define INSTANCES");
  527. PushAttributesForInstances(attribs, this._enableVelocity);
  528. if (subMesh.getRenderingMesh().hasThinInstances) {
  529. defines.push("#define THIN_INSTANCES");
  530. }
  531. }
  532. // Setup textures count
  533. if (this._linkedWithPrePass) {
  534. defines.push("#define RENDER_TARGET_COUNT " + this._attachmentsFromPrePass.length);
  535. }
  536. else {
  537. defines.push("#define RENDER_TARGET_COUNT " + this._multiRenderTarget.textures.length);
  538. }
  539. prepareStringDefinesForClipPlanes(material, this._scene, defines);
  540. // Get correct effect
  541. const engine = this._scene.getEngine();
  542. const drawWrapper = subMesh._getDrawWrapper(undefined, true);
  543. const cachedDefines = drawWrapper.defines;
  544. const join = defines.join("\n");
  545. if (cachedDefines !== join) {
  546. drawWrapper.setEffect(engine.createEffect("geometry", {
  547. attributes: attribs,
  548. uniformsNames: uniforms,
  549. samplers: ["diffuseSampler", "bumpSampler", "reflectivitySampler", "albedoSampler", "morphTargets", "boneSampler"],
  550. defines: join,
  551. onCompiled: null,
  552. fallbacks: null,
  553. onError: null,
  554. uniformBuffersNames: ["Scene"],
  555. indexParameters: { buffersCount: this._multiRenderTarget.textures.length - 1, maxSimultaneousMorphTargets: numMorphInfluencers },
  556. }, engine), join);
  557. }
  558. return drawWrapper.effect.isReady();
  559. }
  560. /**
  561. * Gets the current underlying G Buffer.
  562. * @returns the buffer
  563. */
  564. getGBuffer() {
  565. return this._multiRenderTarget;
  566. }
  567. /**
  568. * Gets the number of samples used to render the buffer (anti aliasing).
  569. */
  570. get samples() {
  571. return this._multiRenderTarget.samples;
  572. }
  573. /**
  574. * Sets the number of samples used to render the buffer (anti aliasing).
  575. */
  576. set samples(value) {
  577. this._multiRenderTarget.samples = value;
  578. }
  579. /**
  580. * Disposes the renderer and frees up associated resources.
  581. */
  582. dispose() {
  583. if (this._resizeObserver) {
  584. const engine = this._scene.getEngine();
  585. engine.onResizeObservable.remove(this._resizeObserver);
  586. this._resizeObserver = null;
  587. }
  588. this.getGBuffer().dispose();
  589. }
  590. _assignRenderTargetIndices() {
  591. const textureNames = [];
  592. const textureTypesAndFormats = [];
  593. let count = 2;
  594. textureNames.push("gBuffer_Depth", "gBuffer_Normal");
  595. textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.DEPTH_TEXTURE_TYPE]);
  596. textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE]);
  597. if (this._enablePosition) {
  598. this._positionIndex = count;
  599. count++;
  600. textureNames.push("gBuffer_Position");
  601. textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.POSITION_TEXTURE_TYPE]);
  602. }
  603. if (this._enableVelocity) {
  604. this._velocityIndex = count;
  605. count++;
  606. textureNames.push("gBuffer_Velocity");
  607. textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE]);
  608. }
  609. if (this._enableReflectivity) {
  610. this._reflectivityIndex = count;
  611. count++;
  612. textureNames.push("gBuffer_Reflectivity");
  613. textureTypesAndFormats.push(this._textureTypesAndFormats[GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE]);
  614. }
  615. return [count, textureNames, textureTypesAndFormats];
  616. }
  617. _createRenderTargets() {
  618. const engine = this._scene.getEngine();
  619. const [count, textureNames, textureTypesAndFormat] = this._assignRenderTargetIndices();
  620. let type = 0;
  621. if (engine._caps.textureFloat && engine._caps.textureFloatLinearFiltering) {
  622. type = 1;
  623. }
  624. else if (engine._caps.textureHalfFloat && engine._caps.textureHalfFloatLinearFiltering) {
  625. type = 2;
  626. }
  627. const dimensions = this._ratioOrDimensions.width !== undefined
  628. ? this._ratioOrDimensions
  629. : { width: engine.getRenderWidth() * this._ratioOrDimensions, height: engine.getRenderHeight() * this._ratioOrDimensions };
  630. const textureTypes = [];
  631. const textureFormats = [];
  632. for (const typeAndFormat of textureTypesAndFormat) {
  633. if (typeAndFormat) {
  634. textureTypes.push(typeAndFormat.textureType);
  635. textureFormats.push(typeAndFormat.textureFormat);
  636. }
  637. else {
  638. textureTypes.push(type);
  639. textureFormats.push(5);
  640. }
  641. }
  642. this._normalsAreUnsigned =
  643. textureTypes[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE] === 11 ||
  644. textureTypes[GeometryBufferRenderer.NORMAL_TEXTURE_TYPE] === 13;
  645. this._multiRenderTarget = new MultiRenderTarget("gBuffer", dimensions, count, this._scene, { generateMipMaps: false, generateDepthTexture: true, types: textureTypes, formats: textureFormats, depthTextureFormat: this._depthFormat }, textureNames.concat("gBuffer_DepthBuffer"));
  646. if (!this.isSupported) {
  647. return;
  648. }
  649. this._multiRenderTarget.wrapU = Texture.CLAMP_ADDRESSMODE;
  650. this._multiRenderTarget.wrapV = Texture.CLAMP_ADDRESSMODE;
  651. this._multiRenderTarget.refreshRate = 1;
  652. this._multiRenderTarget.renderParticles = false;
  653. this._multiRenderTarget.renderList = null;
  654. // Depth is always the first texture in the geometry buffer renderer!
  655. const layoutAttachmentsAll = [true];
  656. const layoutAttachmentsAllButDepth = [false];
  657. const layoutAttachmentsDepthOnly = [true];
  658. for (let i = 1; i < count; ++i) {
  659. layoutAttachmentsAll.push(true);
  660. layoutAttachmentsDepthOnly.push(false);
  661. layoutAttachmentsAllButDepth.push(true);
  662. }
  663. const attachmentsAll = engine.buildTextureLayout(layoutAttachmentsAll);
  664. const attachmentsAllButDepth = engine.buildTextureLayout(layoutAttachmentsAllButDepth);
  665. const attachmentsDepthOnly = engine.buildTextureLayout(layoutAttachmentsDepthOnly);
  666. this._multiRenderTarget.onClearObservable.add((engine) => {
  667. engine.bindAttachments(this.useSpecificClearForDepthTexture ? attachmentsAllButDepth : attachmentsAll);
  668. engine.clear(this._clearColor, true, true, true);
  669. if (this.useSpecificClearForDepthTexture) {
  670. engine.bindAttachments(attachmentsDepthOnly);
  671. engine.clear(this._clearDepthColor, true, true, true);
  672. }
  673. engine.bindAttachments(attachmentsAll);
  674. });
  675. this._resizeObserver = engine.onResizeObservable.add(() => {
  676. if (this._multiRenderTarget) {
  677. const dimensions = this._ratioOrDimensions.width !== undefined
  678. ? this._ratioOrDimensions
  679. : { width: engine.getRenderWidth() * this._ratioOrDimensions, height: engine.getRenderHeight() * this._ratioOrDimensions };
  680. this._multiRenderTarget.resize(dimensions);
  681. }
  682. });
  683. // Custom render function
  684. const renderSubMesh = (subMesh) => {
  685. const renderingMesh = subMesh.getRenderingMesh();
  686. const effectiveMesh = subMesh.getEffectiveMesh();
  687. const scene = this._scene;
  688. const engine = scene.getEngine();
  689. const material = subMesh.getMaterial();
  690. if (!material) {
  691. return;
  692. }
  693. effectiveMesh._internalAbstractMeshDataInfo._isActiveIntermediate = false;
  694. // Velocity
  695. if (this._enableVelocity && !this._previousTransformationMatrices[effectiveMesh.uniqueId]) {
  696. this._previousTransformationMatrices[effectiveMesh.uniqueId] = {
  697. world: Matrix.Identity(),
  698. viewProjection: scene.getTransformMatrix(),
  699. };
  700. if (renderingMesh.skeleton) {
  701. const bonesTransformations = renderingMesh.skeleton.getTransformMatrices(renderingMesh);
  702. this._previousBonesTransformationMatrices[renderingMesh.uniqueId] = this._copyBonesTransformationMatrices(bonesTransformations, new Float32Array(bonesTransformations.length));
  703. }
  704. }
  705. // Managing instances
  706. const batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
  707. if (batch.mustReturn) {
  708. return;
  709. }
  710. const hardwareInstancedRendering = engine.getCaps().instancedArrays && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
  711. const world = effectiveMesh.getWorldMatrix();
  712. if (this.isReady(subMesh, hardwareInstancedRendering)) {
  713. const drawWrapper = subMesh._getDrawWrapper();
  714. if (!drawWrapper) {
  715. return;
  716. }
  717. const effect = drawWrapper.effect;
  718. engine.enableEffect(drawWrapper);
  719. if (!hardwareInstancedRendering) {
  720. renderingMesh._bind(subMesh, effect, material.fillMode);
  721. }
  722. if (!this._useUbo) {
  723. effect.setMatrix("viewProjection", scene.getTransformMatrix());
  724. effect.setMatrix("view", scene.getViewMatrix());
  725. }
  726. else {
  727. BindSceneUniformBuffer(effect, this._scene.getSceneUniformBuffer());
  728. this._scene.finalizeSceneUbo();
  729. }
  730. let sideOrientation;
  731. const instanceDataStorage = renderingMesh._instanceDataStorage;
  732. if (!instanceDataStorage.isFrozen && (material.backFaceCulling || renderingMesh.overrideMaterialSideOrientation !== null)) {
  733. const mainDeterminant = effectiveMesh._getWorldMatrixDeterminant();
  734. sideOrientation = renderingMesh.overrideMaterialSideOrientation;
  735. if (sideOrientation === null) {
  736. sideOrientation = material.sideOrientation;
  737. }
  738. if (mainDeterminant < 0) {
  739. sideOrientation = sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation;
  740. }
  741. }
  742. else {
  743. sideOrientation = instanceDataStorage.sideOrientation;
  744. }
  745. material._preBind(drawWrapper, sideOrientation);
  746. // Alpha test
  747. if (material.needAlphaTesting()) {
  748. const alphaTexture = material.getAlphaTestTexture();
  749. if (alphaTexture) {
  750. effect.setTexture("diffuseSampler", alphaTexture);
  751. effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
  752. }
  753. }
  754. // Bump
  755. if (material.bumpTexture && scene.getEngine().getCaps().standardDerivatives && MaterialFlags.BumpTextureEnabled) {
  756. effect.setFloat3("vBumpInfos", material.bumpTexture.coordinatesIndex, 1.0 / material.bumpTexture.level, material.parallaxScaleBias);
  757. effect.setMatrix("bumpMatrix", material.bumpTexture.getTextureMatrix());
  758. effect.setTexture("bumpSampler", material.bumpTexture);
  759. effect.setFloat2("vTangentSpaceParams", material.invertNormalMapX ? -1.0 : 1.0, material.invertNormalMapY ? -1.0 : 1.0);
  760. }
  761. // Reflectivity
  762. if (this._enableReflectivity) {
  763. // for PBR materials: cf. https://doc.babylonjs.com/features/featuresDeepDive/materials/using/masterPBR
  764. if (material.getClassName() === "PBRMetallicRoughnessMaterial") {
  765. // if it is a PBR material in MetallicRoughness Mode:
  766. if (material.metallicRoughnessTexture !== null) {
  767. effect.setTexture("reflectivitySampler", material.metallicRoughnessTexture);
  768. effect.setMatrix("reflectivityMatrix", material.metallicRoughnessTexture.getTextureMatrix());
  769. }
  770. if (material.metallic !== null) {
  771. effect.setFloat("metallic", material.metallic);
  772. }
  773. if (material.roughness !== null) {
  774. effect.setFloat("glossiness", 1.0 - material.roughness);
  775. }
  776. if (material.baseTexture !== null) {
  777. effect.setTexture("albedoSampler", material.baseTexture);
  778. effect.setMatrix("albedoMatrix", material.baseTexture.getTextureMatrix());
  779. }
  780. if (material.baseColor !== null) {
  781. effect.setColor3("albedoColor", material.baseColor);
  782. }
  783. }
  784. else if (material.getClassName() === "PBRSpecularGlossinessMaterial") {
  785. // if it is a PBR material in Specular/Glossiness Mode:
  786. if (material.specularGlossinessTexture !== null) {
  787. effect.setTexture("reflectivitySampler", material.specularGlossinessTexture);
  788. effect.setMatrix("reflectivityMatrix", material.specularGlossinessTexture.getTextureMatrix());
  789. }
  790. else {
  791. if (material.specularColor !== null) {
  792. effect.setColor3("reflectivityColor", material.specularColor);
  793. }
  794. }
  795. if (material.glossiness !== null) {
  796. effect.setFloat("glossiness", material.glossiness);
  797. }
  798. }
  799. else if (material.getClassName() === "PBRMaterial") {
  800. // if it is the bigger PBRMaterial
  801. if (material.metallicTexture !== null) {
  802. effect.setTexture("reflectivitySampler", material.metallicTexture);
  803. effect.setMatrix("reflectivityMatrix", material.metallicTexture.getTextureMatrix());
  804. }
  805. if (material.metallic !== null) {
  806. effect.setFloat("metallic", material.metallic);
  807. }
  808. if (material.roughness !== null) {
  809. effect.setFloat("glossiness", 1.0 - material.roughness);
  810. }
  811. if (material.roughness !== null || material.metallic !== null || material.metallicTexture !== null) {
  812. // MetallicRoughness Model
  813. if (material.albedoTexture !== null) {
  814. effect.setTexture("albedoSampler", material.albedoTexture);
  815. effect.setMatrix("albedoMatrix", material.albedoTexture.getTextureMatrix());
  816. }
  817. if (material.albedoColor !== null) {
  818. effect.setColor3("albedoColor", material.albedoColor);
  819. }
  820. }
  821. else {
  822. // SpecularGlossiness Model
  823. if (material.reflectivityTexture !== null) {
  824. effect.setTexture("reflectivitySampler", material.reflectivityTexture);
  825. effect.setMatrix("reflectivityMatrix", material.reflectivityTexture.getTextureMatrix());
  826. }
  827. else if (material.reflectivityColor !== null) {
  828. effect.setColor3("reflectivityColor", material.reflectivityColor);
  829. }
  830. if (material.microSurface !== null) {
  831. effect.setFloat("glossiness", material.microSurface);
  832. }
  833. }
  834. }
  835. else if (material.getClassName() === "StandardMaterial") {
  836. // if StandardMaterial:
  837. if (material.specularTexture !== null) {
  838. effect.setTexture("reflectivitySampler", material.specularTexture);
  839. effect.setMatrix("reflectivityMatrix", material.specularTexture.getTextureMatrix());
  840. }
  841. if (material.specularColor !== null) {
  842. effect.setColor3("reflectivityColor", material.specularColor);
  843. }
  844. }
  845. }
  846. // Clip plane
  847. bindClipPlane(effect, material, this._scene);
  848. // Bones
  849. if (renderingMesh.useBones && renderingMesh.computeBonesUsingShaders && renderingMesh.skeleton) {
  850. const skeleton = renderingMesh.skeleton;
  851. if (skeleton.isUsingTextureForMatrices && effect.getUniformIndex("boneTextureWidth") > -1) {
  852. const boneTexture = skeleton.getTransformMatrixTexture(renderingMesh);
  853. effect.setTexture("boneSampler", boneTexture);
  854. effect.setFloat("boneTextureWidth", 4.0 * (skeleton.bones.length + 1));
  855. }
  856. else {
  857. effect.setMatrices("mBones", renderingMesh.skeleton.getTransformMatrices(renderingMesh));
  858. }
  859. if (this._enableVelocity) {
  860. effect.setMatrices("mPreviousBones", this._previousBonesTransformationMatrices[renderingMesh.uniqueId]);
  861. }
  862. }
  863. // Morph targets
  864. BindMorphTargetParameters(renderingMesh, effect);
  865. if (renderingMesh.morphTargetManager && renderingMesh.morphTargetManager.isUsingTextureForTargets) {
  866. renderingMesh.morphTargetManager._bind(effect);
  867. }
  868. // Velocity
  869. if (this._enableVelocity) {
  870. effect.setMatrix("previousWorld", this._previousTransformationMatrices[effectiveMesh.uniqueId].world);
  871. effect.setMatrix("previousViewProjection", this._previousTransformationMatrices[effectiveMesh.uniqueId].viewProjection);
  872. }
  873. if (hardwareInstancedRendering && renderingMesh.hasThinInstances) {
  874. effect.setMatrix("world", world);
  875. }
  876. // Draw
  877. renderingMesh._processRendering(effectiveMesh, subMesh, effect, material.fillMode, batch, hardwareInstancedRendering, (isInstance, w) => {
  878. if (!isInstance) {
  879. effect.setMatrix("world", w);
  880. }
  881. });
  882. }
  883. // Velocity
  884. if (this._enableVelocity) {
  885. this._previousTransformationMatrices[effectiveMesh.uniqueId].world = world.clone();
  886. this._previousTransformationMatrices[effectiveMesh.uniqueId].viewProjection = this._scene.getTransformMatrix().clone();
  887. if (renderingMesh.skeleton) {
  888. this._copyBonesTransformationMatrices(renderingMesh.skeleton.getTransformMatrices(renderingMesh), this._previousBonesTransformationMatrices[effectiveMesh.uniqueId]);
  889. }
  890. }
  891. };
  892. this._multiRenderTarget.customIsReadyFunction = (mesh, refreshRate, preWarm) => {
  893. if ((preWarm || refreshRate === 0) && mesh.subMeshes) {
  894. for (let i = 0; i < mesh.subMeshes.length; ++i) {
  895. const subMesh = mesh.subMeshes[i];
  896. const material = subMesh.getMaterial();
  897. const renderingMesh = subMesh.getRenderingMesh();
  898. if (!material) {
  899. continue;
  900. }
  901. const batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
  902. const hardwareInstancedRendering = engine.getCaps().instancedArrays && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
  903. if (!this.isReady(subMesh, hardwareInstancedRendering)) {
  904. return false;
  905. }
  906. }
  907. }
  908. return true;
  909. };
  910. this._multiRenderTarget.customRenderFunction = (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes, depthOnlySubMeshes) => {
  911. let index;
  912. if (this._linkedWithPrePass) {
  913. if (!this._prePassRenderer.enabled) {
  914. return;
  915. }
  916. this._scene.getEngine().bindAttachments(this._attachmentsFromPrePass);
  917. }
  918. if (depthOnlySubMeshes.length) {
  919. engine.setColorWrite(false);
  920. for (index = 0; index < depthOnlySubMeshes.length; index++) {
  921. renderSubMesh(depthOnlySubMeshes.data[index]);
  922. }
  923. engine.setColorWrite(true);
  924. }
  925. for (index = 0; index < opaqueSubMeshes.length; index++) {
  926. renderSubMesh(opaqueSubMeshes.data[index]);
  927. }
  928. engine.setDepthWrite(false);
  929. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  930. renderSubMesh(alphaTestSubMeshes.data[index]);
  931. }
  932. if (this.renderTransparentMeshes) {
  933. for (index = 0; index < transparentSubMeshes.length; index++) {
  934. renderSubMesh(transparentSubMeshes.data[index]);
  935. }
  936. }
  937. engine.setDepthWrite(true);
  938. };
  939. }
  940. // Copies the bones transformation matrices into the target array and returns the target's reference
  941. _copyBonesTransformationMatrices(source, target) {
  942. for (let i = 0; i < source.length; i++) {
  943. target[i] = source[i];
  944. }
  945. return target;
  946. }
  947. }
  948. /**
  949. * Constant used to retrieve the depth texture index in the G-Buffer textures array
  950. * using getIndex(GeometryBufferRenderer.DEPTH_TEXTURE_INDEX)
  951. */
  952. GeometryBufferRenderer.DEPTH_TEXTURE_TYPE = 0;
  953. /**
  954. * Constant used to retrieve the normal texture index in the G-Buffer textures array
  955. * using getIndex(GeometryBufferRenderer.NORMAL_TEXTURE_INDEX)
  956. */
  957. GeometryBufferRenderer.NORMAL_TEXTURE_TYPE = 1;
  958. /**
  959. * Constant used to retrieve the position texture index in the G-Buffer textures array
  960. * using getIndex(GeometryBufferRenderer.POSITION_TEXTURE_INDEX)
  961. */
  962. GeometryBufferRenderer.POSITION_TEXTURE_TYPE = 2;
  963. /**
  964. * Constant used to retrieve the velocity texture index in the G-Buffer textures array
  965. * using getIndex(GeometryBufferRenderer.VELOCITY_TEXTURE_INDEX)
  966. */
  967. GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE = 3;
  968. /**
  969. * Constant used to retrieve the reflectivity texture index in the G-Buffer textures array
  970. * using the getIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE)
  971. */
  972. GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE = 4;
  973. /**
  974. * @internal
  975. */
  976. GeometryBufferRenderer._SceneComponentInitialization = (_) => {
  977. throw _WarnImport("GeometryBufferRendererSceneComponent");
  978. };
  979. //# sourceMappingURL=geometryBufferRenderer.js.map