geometryBufferRenderer.ts 28 KB

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