geometryBufferRenderer.ts 27 KB

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