geometryBufferRenderer.ts 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. import { Matrix } from "../Maths/math.vector";
  2. import { VertexBuffer } from "../Meshes/buffer";
  3. import { SubMesh } from "../Meshes/subMesh";
  4. import { Mesh } from "../Meshes/mesh";
  5. import { Constants } from "../Engines/constants";
  6. import { SmartArray } from "../Misc/smartArray";
  7. import { Texture } from "../Materials/Textures/texture";
  8. import { InternalTexture } from "../Materials/Textures/internalTexture";
  9. import { MultiRenderTarget } from "../Materials/Textures/multiRenderTarget";
  10. import { Effect } from "../Materials/effect";
  11. import { PrePassRenderer } from "../Rendering/prePassRenderer";
  12. import { MaterialHelper } from "../Materials/materialHelper";
  13. import { Scene } from "../scene";
  14. import { AbstractMesh } from "../Meshes/abstractMesh";
  15. import { Color4 } from '../Maths/math.color';
  16. import { StandardMaterial } from '../Materials/standardMaterial';
  17. import { PBRMaterial } from '../Materials/PBR/pbrMaterial';
  18. import { _DevTools } from '../Misc/devTools';
  19. import { Observer } from '../Misc/observable';
  20. import { Engine } from '../Engines/engine';
  21. import { Nullable } from '../types';
  22. import { Material } from '../Materials/material';
  23. import "../Shaders/geometry.fragment";
  24. import "../Shaders/geometry.vertex";
  25. /** @hidden */
  26. interface ISavedTransformationMatrix {
  27. world: Matrix;
  28. viewProjection: Matrix;
  29. }
  30. /**
  31. * This renderer is helpful to fill one of the render target with a geometry buffer.
  32. */
  33. export class GeometryBufferRenderer {
  34. /**
  35. * Constant used to retrieve the depth texture index in the G-Buffer textures array
  36. * using getIndex(GeometryBufferRenderer.DEPTH_TEXTURE_INDEX)
  37. */
  38. public static readonly DEPTH_TEXTURE_TYPE = 0;
  39. /**
  40. * Constant used to retrieve the normal texture index in the G-Buffer textures array
  41. * using getIndex(GeometryBufferRenderer.NORMAL_TEXTURE_INDEX)
  42. */
  43. public static readonly NORMAL_TEXTURE_TYPE = 1;
  44. /**
  45. * Constant used to retrieve the position texture index in the G-Buffer textures array
  46. * using getIndex(GeometryBufferRenderer.POSITION_TEXTURE_INDEX)
  47. */
  48. public static readonly POSITION_TEXTURE_TYPE = 2;
  49. /**
  50. * Constant used to retrieve the velocity texture index in the G-Buffer textures array
  51. * using getIndex(GeometryBufferRenderer.VELOCITY_TEXTURE_INDEX)
  52. */
  53. public static readonly VELOCITY_TEXTURE_TYPE = 3;
  54. /**
  55. * Constant used to retrieve the reflectivity texture index in the G-Buffer textures array
  56. * using the getIndex(GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE)
  57. */
  58. public static readonly REFLECTIVITY_TEXTURE_TYPE = 4;
  59. /**
  60. * Dictionary used to store the previous transformation matrices of each rendered mesh
  61. * in order to compute objects velocities when enableVelocity is set to "true"
  62. * @hidden
  63. */
  64. public _previousTransformationMatrices: { [index: number]: ISavedTransformationMatrix } = {};
  65. /**
  66. * Dictionary used to store the previous bones transformation matrices of each rendered mesh
  67. * in order to compute objects velocities when enableVelocity is set to "true"
  68. * @hidden
  69. */
  70. public _previousBonesTransformationMatrices: { [index: number]: Float32Array } = {};
  71. /**
  72. * Array used to store the ignored skinned meshes while computing velocity map (typically used by the motion blur post-process).
  73. * Avoids computing bones velocities and computes only mesh's velocity itself (position, rotation, scaling).
  74. */
  75. public excludedSkinnedMeshesFromVelocity: AbstractMesh[] = [];
  76. /** Gets or sets a boolean indicating if transparent meshes should be rendered */
  77. public renderTransparentMeshes = true;
  78. private _scene: Scene;
  79. private _resizeObserver: Nullable<Observer<Engine>> = null;
  80. private _multiRenderTarget: MultiRenderTarget;
  81. private _ratio: number;
  82. private _enablePosition: boolean = false;
  83. private _enableVelocity: boolean = false;
  84. private _enableReflectivity: boolean = false;
  85. private _positionIndex: number = -1;
  86. private _velocityIndex: number = -1;
  87. private _reflectivityIndex: number = -1;
  88. private _depthIndex: number = -1;
  89. private _normalIndex: number = -1;
  90. private _linkedWithPrePass: boolean = false;
  91. private _prePassRenderer: PrePassRenderer;
  92. private _attachments: number[];
  93. private _useUbo: boolean;
  94. protected _effect: Effect;
  95. protected _cachedDefines: string;
  96. /**
  97. * @hidden
  98. * Sets up internal structures to share outputs with PrePassRenderer
  99. * This method should only be called by the PrePassRenderer itself
  100. */
  101. public _linkPrePassRenderer(prePassRenderer: PrePassRenderer) {
  102. this._linkedWithPrePass = true;
  103. this._prePassRenderer = prePassRenderer;
  104. if (this._multiRenderTarget) {
  105. // prevents clearing of the RT since it's done by prepass
  106. this._multiRenderTarget.onClearObservable.clear();
  107. this._multiRenderTarget.onClearObservable.add((engine) => {
  108. // pass
  109. });
  110. }
  111. }
  112. /**
  113. * @hidden
  114. * Separates internal structures from PrePassRenderer so the geometry buffer can now operate by itself.
  115. * This method should only be called by the PrePassRenderer itself
  116. */
  117. public _unlinkPrePassRenderer() {
  118. this._linkedWithPrePass = false;
  119. this._createRenderTargets();
  120. }
  121. /**
  122. * @hidden
  123. * Resets the geometry buffer layout
  124. */
  125. public _resetLayout() {
  126. this._enablePosition = false;
  127. this._enableReflectivity = false;
  128. this._enableVelocity = false;
  129. this._attachments = [];
  130. }
  131. /**
  132. * @hidden
  133. * Replaces a texture in the geometry buffer renderer
  134. * Useful when linking textures of the prepass renderer
  135. */
  136. public _forceTextureType(geometryBufferType: number, index: number) {
  137. if (geometryBufferType === GeometryBufferRenderer.POSITION_TEXTURE_TYPE) {
  138. this._positionIndex = index;
  139. this._enablePosition = true;
  140. } else if (geometryBufferType === GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE) {
  141. this._velocityIndex = index;
  142. this._enableVelocity = true;
  143. } else if (geometryBufferType === GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE) {
  144. this._reflectivityIndex = index;
  145. this._enableReflectivity = true;
  146. } else if (geometryBufferType === GeometryBufferRenderer.DEPTH_TEXTURE_TYPE) {
  147. this._depthIndex = index;
  148. } else if (geometryBufferType === GeometryBufferRenderer.NORMAL_TEXTURE_TYPE) {
  149. this._normalIndex = index;
  150. }
  151. }
  152. /**
  153. * @hidden
  154. * Sets texture attachments
  155. * Useful when linking textures of the prepass renderer
  156. */
  157. public _setAttachments(attachments: number[]) {
  158. this._attachments = attachments;
  159. }
  160. /**
  161. * @hidden
  162. * Replaces the first texture which is hard coded as a depth texture in the geometry buffer
  163. * Useful when linking textures of the prepass renderer
  164. */
  165. public _linkInternalTexture(internalTexture: InternalTexture) {
  166. this._multiRenderTarget._texture = internalTexture;
  167. }
  168. /**
  169. * Gets the render list (meshes to be rendered) used in the G buffer.
  170. */
  171. public get renderList() {
  172. return this._multiRenderTarget.renderList;
  173. }
  174. /**
  175. * Set the render list (meshes to be rendered) used in the G buffer.
  176. */
  177. public set renderList(meshes: Nullable<AbstractMesh[]>) {
  178. this._multiRenderTarget.renderList = meshes;
  179. }
  180. /**
  181. * Gets whether or not G buffer are supported by the running hardware.
  182. * This requires draw buffer supports
  183. */
  184. public get isSupported(): boolean {
  185. return this._multiRenderTarget.isSupported;
  186. }
  187. /**
  188. * Returns the index of the given texture type in the G-Buffer textures array
  189. * @param textureType The texture type constant. For example GeometryBufferRenderer.POSITION_TEXTURE_INDEX
  190. * @returns the index of the given texture type in the G-Buffer textures array
  191. */
  192. public getTextureIndex(textureType: number): number {
  193. switch (textureType) {
  194. case GeometryBufferRenderer.POSITION_TEXTURE_TYPE: return this._positionIndex;
  195. case GeometryBufferRenderer.VELOCITY_TEXTURE_TYPE: return this._velocityIndex;
  196. case GeometryBufferRenderer.REFLECTIVITY_TEXTURE_TYPE: return this._reflectivityIndex;
  197. default: return -1;
  198. }
  199. }
  200. /**
  201. * Gets a boolean indicating if objects positions are enabled for the G buffer.
  202. */
  203. public get enablePosition(): boolean {
  204. return this._enablePosition;
  205. }
  206. /**
  207. * Sets whether or not objects positions are enabled for the G buffer.
  208. */
  209. public set enablePosition(enable: boolean) {
  210. this._enablePosition = enable;
  211. // PrePass handles index and texture links
  212. if (!this._linkedWithPrePass) {
  213. this.dispose();
  214. this._createRenderTargets();
  215. }
  216. }
  217. /**
  218. * Gets a boolean indicating if objects velocities are enabled for the G buffer.
  219. */
  220. public get enableVelocity(): boolean {
  221. return this._enableVelocity;
  222. }
  223. /**
  224. * Sets whether or not objects velocities are enabled for the G buffer.
  225. */
  226. public set enableVelocity(enable: boolean) {
  227. this._enableVelocity = enable;
  228. if (!enable) {
  229. this._previousTransformationMatrices = {};
  230. }
  231. if (!this._linkedWithPrePass) {
  232. this.dispose();
  233. this._createRenderTargets();
  234. }
  235. }
  236. /**
  237. * Gets a boolean indicating if objects roughness are enabled in the G buffer.
  238. */
  239. public get enableReflectivity(): boolean {
  240. return this._enableReflectivity;
  241. }
  242. /**
  243. * Sets whether or not objects roughness are enabled for the G buffer.
  244. */
  245. public set enableReflectivity(enable: boolean) {
  246. this._enableReflectivity = enable;
  247. if (!this._linkedWithPrePass) {
  248. this.dispose();
  249. this._createRenderTargets();
  250. }
  251. }
  252. /**
  253. * Gets the scene associated with the buffer.
  254. */
  255. public get scene(): Scene {
  256. return this._scene;
  257. }
  258. /**
  259. * Gets the ratio used by the buffer during its creation.
  260. * How big is the buffer related to the main canvas.
  261. */
  262. public get ratio(): number {
  263. return this._ratio;
  264. }
  265. /** @hidden */
  266. public static _SceneComponentInitialization: (scene: Scene) => void = (_) => {
  267. throw _DevTools.WarnImport("GeometryBufferRendererSceneComponent");
  268. }
  269. /**
  270. * Creates a new G Buffer for the scene
  271. * @param scene The scene the buffer belongs to
  272. * @param ratio How big is the buffer related to the main canvas.
  273. */
  274. constructor(scene: Scene, ratio: number = 1) {
  275. this._scene = scene;
  276. this._ratio = ratio;
  277. this._useUbo = scene.getEngine().supportsUniformBuffers;
  278. GeometryBufferRenderer._SceneComponentInitialization(this._scene);
  279. // Render target
  280. this._createRenderTargets();
  281. }
  282. /**
  283. * Checks whether everything is ready to render a submesh to the G buffer.
  284. * @param subMesh the submesh to check readiness for
  285. * @param useInstances is the mesh drawn using instance or not
  286. * @returns true if ready otherwise false
  287. */
  288. public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
  289. var material = <any> subMesh.getMaterial();
  290. if (material && material.disableDepthWrite) {
  291. return false;
  292. }
  293. var defines = [];
  294. var attribs = [VertexBuffer.PositionKind, VertexBuffer.NormalKind];
  295. var mesh = subMesh.getMesh();
  296. // Alpha test
  297. if (material) {
  298. let needUv = false;
  299. if (material.needAlphaTesting() && material.getAlphaTestTexture()) {
  300. defines.push("#define ALPHATEST");
  301. defines.push(`#define ALPHATEST_UV${material.getAlphaTestTexture().coordinatesIndex + 1}`);
  302. needUv = true;
  303. }
  304. if (material.bumpTexture && StandardMaterial.BumpTextureEnabled) {
  305. defines.push("#define BUMP");
  306. defines.push(`#define BUMP_UV${material.bumpTexture.coordinatesIndex + 1}`);
  307. needUv = true;
  308. }
  309. if (this._enableReflectivity) {
  310. if (material instanceof StandardMaterial && material.specularTexture) {
  311. defines.push("#define HAS_SPECULAR");
  312. defines.push(`#define REFLECTIVITY_UV${material.specularTexture.coordinatesIndex + 1}`);
  313. needUv = true;
  314. } else if (material instanceof PBRMaterial && material.reflectivityTexture) {
  315. defines.push("#define HAS_REFLECTIVITY");
  316. defines.push(`#define REFLECTIVITY_UV${material.reflectivityTexture.coordinatesIndex + 1}`);
  317. needUv = true;
  318. }
  319. }
  320. if (needUv) {
  321. defines.push("#define NEED_UV");
  322. if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
  323. attribs.push(VertexBuffer.UVKind);
  324. defines.push("#define UV1");
  325. }
  326. if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
  327. attribs.push(VertexBuffer.UV2Kind);
  328. defines.push("#define UV2");
  329. }
  330. }
  331. }
  332. // PrePass
  333. if (this._linkedWithPrePass) {
  334. defines.push("#define PREPASS");
  335. if (this._depthIndex !== -1) {
  336. defines.push("#define DEPTH_INDEX " + this._depthIndex);
  337. defines.push("#define PREPASS_DEPTH");
  338. }
  339. if (this._normalIndex !== -1) {
  340. defines.push("#define NORMAL_INDEX " + this._normalIndex);
  341. defines.push("#define PREPASS_NORMAL");
  342. }
  343. }
  344. // Buffers
  345. if (this._enablePosition) {
  346. defines.push("#define POSITION");
  347. defines.push("#define POSITION_INDEX " + this._positionIndex);
  348. }
  349. if (this._enableVelocity) {
  350. defines.push("#define VELOCITY");
  351. defines.push("#define VELOCITY_INDEX " + this._velocityIndex);
  352. if (this.excludedSkinnedMeshesFromVelocity.indexOf(mesh) === -1) {
  353. defines.push("#define BONES_VELOCITY_ENABLED");
  354. }
  355. }
  356. if (this._enableReflectivity) {
  357. defines.push("#define REFLECTIVITY");
  358. defines.push("#define REFLECTIVITY_INDEX " + this._reflectivityIndex);
  359. }
  360. // Bones
  361. if (mesh.useBones && mesh.computeBonesUsingShaders) {
  362. attribs.push(VertexBuffer.MatricesIndicesKind);
  363. attribs.push(VertexBuffer.MatricesWeightsKind);
  364. if (mesh.numBoneInfluencers > 4) {
  365. attribs.push(VertexBuffer.MatricesIndicesExtraKind);
  366. attribs.push(VertexBuffer.MatricesWeightsExtraKind);
  367. }
  368. defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
  369. defines.push("#define BonesPerMesh " + (mesh.skeleton ? mesh.skeleton.bones.length + 1 : 0));
  370. } else {
  371. defines.push("#define NUM_BONE_INFLUENCERS 0");
  372. }
  373. // Morph targets
  374. const morphTargetManager = (mesh as Mesh).morphTargetManager;
  375. let numMorphInfluencers = 0;
  376. if (morphTargetManager) {
  377. if (morphTargetManager.numInfluencers > 0) {
  378. numMorphInfluencers = morphTargetManager.numInfluencers;
  379. defines.push("#define MORPHTARGETS");
  380. defines.push("#define NUM_MORPH_INFLUENCERS " + numMorphInfluencers);
  381. if (morphTargetManager.isUsingTextureForTargets) {
  382. defines.push("#define MORPHTARGETS_TEXTURE");
  383. }
  384. MaterialHelper.PrepareAttributesForMorphTargetsInfluencers(attribs, mesh, numMorphInfluencers);
  385. }
  386. }
  387. // Instances
  388. if (useInstances) {
  389. defines.push("#define INSTANCES");
  390. MaterialHelper.PushAttributesForInstances(attribs);
  391. if (subMesh.getRenderingMesh().hasThinInstances) {
  392. defines.push("#define THIN_INSTANCES");
  393. }
  394. }
  395. // Setup textures count
  396. if (this._linkedWithPrePass) {
  397. defines.push("#define RENDER_TARGET_COUNT " + this._attachments.length);
  398. } else {
  399. defines.push("#define RENDER_TARGET_COUNT " + this._multiRenderTarget.textures.length);
  400. }
  401. // Get correct effect
  402. var join = defines.join("\n");
  403. if (this._cachedDefines !== join) {
  404. this._cachedDefines = join;
  405. this._effect = this._scene.getEngine().createEffect("geometry",
  406. {
  407. attributes: attribs,
  408. uniformsNames: [
  409. "world", "mBones", "viewProjection", "diffuseMatrix", "view", "previousWorld", "previousViewProjection", "mPreviousBones",
  410. "bumpMatrix", "reflectivityMatrix", "vTangentSpaceParams", "vBumpInfos",
  411. "morphTargetInfluences", "morphTargetTextureInfo"
  412. ],
  413. samplers: ["diffuseSampler", "bumpSampler", "reflectivitySampler", "morphTargets"],
  414. defines: join,
  415. onCompiled: null,
  416. fallbacks: null,
  417. onError: null,
  418. uniformBuffersNames: ["Scene"],
  419. indexParameters: { buffersCount: this._multiRenderTarget.textures.length - 1, maxSimultaneousMorphTargets: numMorphInfluencers },
  420. },
  421. this._scene.getEngine());
  422. }
  423. return this._effect.isReady();
  424. }
  425. /**
  426. * Gets the current underlying G Buffer.
  427. * @returns the buffer
  428. */
  429. public getGBuffer(): MultiRenderTarget {
  430. return this._multiRenderTarget;
  431. }
  432. /**
  433. * Gets the number of samples used to render the buffer (anti aliasing).
  434. */
  435. public get samples(): number {
  436. return this._multiRenderTarget.samples;
  437. }
  438. /**
  439. * Sets the number of samples used to render the buffer (anti aliasing).
  440. */
  441. public set samples(value: number) {
  442. this._multiRenderTarget.samples = value;
  443. }
  444. /**
  445. * Disposes the renderer and frees up associated resources.
  446. */
  447. public dispose(): void {
  448. if (this._resizeObserver) {
  449. const engine = this._scene.getEngine();
  450. engine.onResizeObservable.remove(this._resizeObserver);
  451. this._resizeObserver = null;
  452. }
  453. this.getGBuffer().dispose();
  454. }
  455. private _assignRenderTargetIndices() : number {
  456. let count = 2;
  457. if (this._enablePosition) {
  458. this._positionIndex = count;
  459. count++;
  460. }
  461. if (this._enableVelocity) {
  462. this._velocityIndex = count;
  463. count++;
  464. }
  465. if (this._enableReflectivity) {
  466. this._reflectivityIndex = count;
  467. count++;
  468. }
  469. return count;
  470. }
  471. protected _createRenderTargets(): void {
  472. var engine = this._scene.getEngine();
  473. var count = this._assignRenderTargetIndices();
  474. this._multiRenderTarget = new MultiRenderTarget("gBuffer",
  475. { width: engine.getRenderWidth() * this._ratio, height: engine.getRenderHeight() * this._ratio }, count, this._scene,
  476. { generateMipMaps: false, generateDepthTexture: true, defaultType: Constants.TEXTURETYPE_FLOAT });
  477. if (!this.isSupported) {
  478. return;
  479. }
  480. this._multiRenderTarget.wrapU = Texture.CLAMP_ADDRESSMODE;
  481. this._multiRenderTarget.wrapV = Texture.CLAMP_ADDRESSMODE;
  482. this._multiRenderTarget.refreshRate = 1;
  483. this._multiRenderTarget.renderParticles = false;
  484. this._multiRenderTarget.renderList = null;
  485. // set default depth value to 1.0 (far away)
  486. this._multiRenderTarget.onClearObservable.add((engine) => {
  487. engine.clear(new Color4(0.0, 0.0, 0.0, 1.0), true, true, true);
  488. });
  489. this._resizeObserver = engine.onResizeObservable.add(() => {
  490. if (this._multiRenderTarget) {
  491. this._multiRenderTarget.resize({ width: engine.getRenderWidth() * this._ratio, height: engine.getRenderHeight() * this._ratio });
  492. }
  493. });
  494. // Custom render function
  495. var renderSubMesh = (subMesh: SubMesh): void => {
  496. var renderingMesh = subMesh.getRenderingMesh();
  497. var effectiveMesh = subMesh.getEffectiveMesh();
  498. var scene = this._scene;
  499. var engine = scene.getEngine();
  500. let material = <any> subMesh.getMaterial();
  501. if (!material) {
  502. return;
  503. }
  504. effectiveMesh._internalAbstractMeshDataInfo._isActiveIntermediate = false;
  505. // Velocity
  506. if (this._enableVelocity && !this._previousTransformationMatrices[effectiveMesh.uniqueId]) {
  507. this._previousTransformationMatrices[effectiveMesh.uniqueId] = {
  508. world: Matrix.Identity(),
  509. viewProjection: scene.getTransformMatrix()
  510. };
  511. if (renderingMesh.skeleton) {
  512. const bonesTransformations = renderingMesh.skeleton.getTransformMatrices(renderingMesh);
  513. this._previousBonesTransformationMatrices[renderingMesh.uniqueId] = this._copyBonesTransformationMatrices(bonesTransformations, new Float32Array(bonesTransformations.length));
  514. }
  515. }
  516. // Managing instances
  517. var batch = renderingMesh._getInstancesRenderList(subMesh._id, !!subMesh.getReplacementMesh());
  518. if (batch.mustReturn) {
  519. return;
  520. }
  521. var hardwareInstancedRendering = (engine.getCaps().instancedArrays) && (batch.visibleInstances[subMesh._id] !== null || renderingMesh.hasThinInstances);
  522. var world = effectiveMesh.getWorldMatrix();
  523. if (this.isReady(subMesh, hardwareInstancedRendering)) {
  524. engine.enableEffect(this._effect);
  525. renderingMesh._bind(subMesh, this._effect, material.fillMode);
  526. if (!this._useUbo) {
  527. this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
  528. this._effect.setMatrix("view", scene.getViewMatrix());
  529. } else {
  530. MaterialHelper.FinalizeSceneUbo(this._scene);
  531. MaterialHelper.BindSceneUniformBuffer(this._effect, this._scene.getSceneUniformBuffer());
  532. }
  533. if (material) {
  534. var sideOrientation: Nullable<number>;
  535. let instanceDataStorage = (renderingMesh as Mesh)._instanceDataStorage;
  536. if (!instanceDataStorage.isFrozen &&
  537. (material.backFaceCulling || material.overrideMaterialSideOrientation !== null)) {
  538. let mainDeterminant = effectiveMesh._getWorldMatrixDeterminant();
  539. sideOrientation = material.overrideMaterialSideOrientation;
  540. if (sideOrientation == null) {
  541. sideOrientation = material.sideOrientation;
  542. }
  543. if (mainDeterminant < 0) {
  544. sideOrientation = (sideOrientation === Material.ClockWiseSideOrientation ? Material.CounterClockWiseSideOrientation : Material.ClockWiseSideOrientation);
  545. }
  546. } else {
  547. sideOrientation = instanceDataStorage.sideOrientation;
  548. }
  549. material._preBind(this._effect, sideOrientation);
  550. // Alpha test
  551. if (material.needAlphaTesting()) {
  552. var alphaTexture = material.getAlphaTestTexture();
  553. if (alphaTexture) {
  554. this._effect.setTexture("diffuseSampler", alphaTexture);
  555. this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
  556. }
  557. }
  558. // Bump
  559. if (material.bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) {
  560. this._effect.setFloat3("vBumpInfos", material.bumpTexture.coordinatesIndex, 1.0 / material.bumpTexture.level, material.parallaxScaleBias);
  561. this._effect.setMatrix("bumpMatrix", material.bumpTexture.getTextureMatrix());
  562. this._effect.setTexture("bumpSampler", material.bumpTexture);
  563. this._effect.setFloat2("vTangentSpaceParams", material.invertNormalMapX ? -1.0 : 1.0, material.invertNormalMapY ? -1.0 : 1.0);
  564. }
  565. // Roughness
  566. if (this._enableReflectivity) {
  567. if (material instanceof StandardMaterial && material.specularTexture) {
  568. this._effect.setMatrix("reflectivityMatrix", material.specularTexture.getTextureMatrix());
  569. this._effect.setTexture("reflectivitySampler", material.specularTexture);
  570. } else if (material instanceof PBRMaterial && material.reflectivityTexture) {
  571. this._effect.setMatrix("reflectivityMatrix", material.reflectivityTexture.getTextureMatrix());
  572. this._effect.setTexture("reflectivitySampler", material.reflectivityTexture);
  573. }
  574. }
  575. }
  576. // Bones
  577. if (renderingMesh.useBones && renderingMesh.computeBonesUsingShaders && renderingMesh.skeleton) {
  578. this._effect.setMatrices("mBones", renderingMesh.skeleton.getTransformMatrices(renderingMesh));
  579. if (this._enableVelocity) {
  580. this._effect.setMatrices("mPreviousBones", this._previousBonesTransformationMatrices[renderingMesh.uniqueId]);
  581. }
  582. }
  583. // Morph targets
  584. MaterialHelper.BindMorphTargetParameters(renderingMesh, this._effect);
  585. if (renderingMesh.morphTargetManager && renderingMesh.morphTargetManager.isUsingTextureForTargets) {
  586. renderingMesh.morphTargetManager._bind(this._effect);
  587. }
  588. // Velocity
  589. if (this._enableVelocity) {
  590. this._effect.setMatrix("previousWorld", this._previousTransformationMatrices[effectiveMesh.uniqueId].world);
  591. this._effect.setMatrix("previousViewProjection", this._previousTransformationMatrices[effectiveMesh.uniqueId].viewProjection);
  592. }
  593. // Draw
  594. renderingMesh._processRendering(effectiveMesh, subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
  595. (isInstance, w) => this._effect.setMatrix("world", w));
  596. }
  597. // Velocity
  598. if (this._enableVelocity) {
  599. this._previousTransformationMatrices[effectiveMesh.uniqueId].world = world.clone();
  600. this._previousTransformationMatrices[effectiveMesh.uniqueId].viewProjection = this._scene.getTransformMatrix().clone();
  601. if (renderingMesh.skeleton) {
  602. this._copyBonesTransformationMatrices(renderingMesh.skeleton.getTransformMatrices(renderingMesh), this._previousBonesTransformationMatrices[effectiveMesh.uniqueId]);
  603. }
  604. }
  605. };
  606. this._multiRenderTarget.customRenderFunction = (opaqueSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>): void => {
  607. var index;
  608. if (this._linkedWithPrePass) {
  609. if (!this._prePassRenderer.enabled) {
  610. return;
  611. }
  612. this._scene.getEngine().bindAttachments(this._attachments);
  613. }
  614. if (depthOnlySubMeshes.length) {
  615. engine.setColorWrite(false);
  616. for (index = 0; index < depthOnlySubMeshes.length; index++) {
  617. renderSubMesh(depthOnlySubMeshes.data[index]);
  618. }
  619. engine.setColorWrite(true);
  620. }
  621. for (index = 0; index < opaqueSubMeshes.length; index++) {
  622. renderSubMesh(opaqueSubMeshes.data[index]);
  623. }
  624. engine.setDepthWrite(false);
  625. for (index = 0; index < alphaTestSubMeshes.length; index++) {
  626. renderSubMesh(alphaTestSubMeshes.data[index]);
  627. }
  628. if (this.renderTransparentMeshes) {
  629. for (index = 0; index < transparentSubMeshes.length; index++) {
  630. renderSubMesh(transparentSubMeshes.data[index]);
  631. }
  632. }
  633. engine.setDepthWrite(true);
  634. };
  635. }
  636. // Copies the bones transformation matrices into the target array and returns the target's reference
  637. private _copyBonesTransformationMatrices(source: Float32Array, target: Float32Array): Float32Array {
  638. for (let i = 0; i < source.length; i++) {
  639. target[i] = source[i];
  640. }
  641. return target;
  642. }
  643. }