123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- import { SmartArray, SmartArrayNoDuplicate } from "../Misc/smartArray.js";
- import { Vector3 } from "../Maths/math.vector.js";
- /**
- * This represents the object necessary to create a rendering group.
- * This is exclusively used and created by the rendering manager.
- * To modify the behavior, you use the available helpers in your scene or meshes.
- * @internal
- */
- export class RenderingGroup {
- /**
- * Set the opaque sort comparison function.
- * If null the sub meshes will be render in the order they were created
- */
- set opaqueSortCompareFn(value) {
- if (value) {
- this._opaqueSortCompareFn = value;
- }
- else {
- this._opaqueSortCompareFn = RenderingGroup.PainterSortCompare;
- }
- this._renderOpaque = this._renderOpaqueSorted;
- }
- /**
- * Set the alpha test sort comparison function.
- * If null the sub meshes will be render in the order they were created
- */
- set alphaTestSortCompareFn(value) {
- if (value) {
- this._alphaTestSortCompareFn = value;
- }
- else {
- this._alphaTestSortCompareFn = RenderingGroup.PainterSortCompare;
- }
- this._renderAlphaTest = this._renderAlphaTestSorted;
- }
- /**
- * Set the transparent sort comparison function.
- * If null the sub meshes will be render in the order they were created
- */
- set transparentSortCompareFn(value) {
- if (value) {
- this._transparentSortCompareFn = value;
- }
- else {
- this._transparentSortCompareFn = RenderingGroup.defaultTransparentSortCompare;
- }
- this._renderTransparent = this._renderTransparentSorted;
- }
- /**
- * Creates a new rendering group.
- * @param index The rendering group index
- * @param scene
- * @param opaqueSortCompareFn The opaque sort comparison function. If null no order is applied
- * @param alphaTestSortCompareFn The alpha test sort comparison function. If null no order is applied
- * @param transparentSortCompareFn The transparent sort comparison function. If null back to front + alpha index sort is applied
- */
- constructor(index, scene, opaqueSortCompareFn = null, alphaTestSortCompareFn = null, transparentSortCompareFn = null) {
- this.index = index;
- this._opaqueSubMeshes = new SmartArray(256);
- this._transparentSubMeshes = new SmartArray(256);
- this._alphaTestSubMeshes = new SmartArray(256);
- this._depthOnlySubMeshes = new SmartArray(256);
- this._particleSystems = new SmartArray(256);
- this._spriteManagers = new SmartArray(256);
- /** @internal */
- this._empty = true;
- /** @internal */
- this._edgesRenderers = new SmartArrayNoDuplicate(16);
- this._scene = scene;
- this.opaqueSortCompareFn = opaqueSortCompareFn;
- this.alphaTestSortCompareFn = alphaTestSortCompareFn;
- this.transparentSortCompareFn = transparentSortCompareFn;
- }
- /**
- * Render all the sub meshes contained in the group.
- * @param customRenderFunction Used to override the default render behaviour of the group.
- * @param renderSprites
- * @param renderParticles
- * @param activeMeshes
- */
- render(customRenderFunction, renderSprites, renderParticles, activeMeshes) {
- if (customRenderFunction) {
- customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes, this._depthOnlySubMeshes);
- return;
- }
- const engine = this._scene.getEngine();
- // Depth only
- if (this._depthOnlySubMeshes.length !== 0) {
- engine.setColorWrite(false);
- this._renderAlphaTest(this._depthOnlySubMeshes);
- engine.setColorWrite(true);
- }
- // Opaque
- if (this._opaqueSubMeshes.length !== 0) {
- this._renderOpaque(this._opaqueSubMeshes);
- }
- // Alpha test
- if (this._alphaTestSubMeshes.length !== 0) {
- this._renderAlphaTest(this._alphaTestSubMeshes);
- }
- const stencilState = engine.getStencilBuffer();
- engine.setStencilBuffer(false);
- // Sprites
- if (renderSprites) {
- this._renderSprites();
- }
- // Particles
- if (renderParticles) {
- this._renderParticles(activeMeshes);
- }
- if (this.onBeforeTransparentRendering) {
- this.onBeforeTransparentRendering();
- }
- // Transparent
- if (this._transparentSubMeshes.length !== 0 || this._scene.useOrderIndependentTransparency) {
- engine.setStencilBuffer(stencilState);
- if (this._scene.useOrderIndependentTransparency) {
- const excludedMeshes = this._scene.depthPeelingRenderer.render(this._transparentSubMeshes);
- if (excludedMeshes.length) {
- // Render leftover meshes that could not be processed by depth peeling
- this._renderTransparent(excludedMeshes);
- }
- }
- else {
- this._renderTransparent(this._transparentSubMeshes);
- }
- engine.setAlphaMode(0);
- }
- // Set back stencil to false in case it changes before the edge renderer.
- engine.setStencilBuffer(false);
- // Edges
- if (this._edgesRenderers.length) {
- for (let edgesRendererIndex = 0; edgesRendererIndex < this._edgesRenderers.length; edgesRendererIndex++) {
- this._edgesRenderers.data[edgesRendererIndex].render();
- }
- engine.setAlphaMode(0);
- }
- // Restore Stencil state.
- engine.setStencilBuffer(stencilState);
- }
- /**
- * Renders the opaque submeshes in the order from the opaqueSortCompareFn.
- * @param subMeshes The submeshes to render
- */
- _renderOpaqueSorted(subMeshes) {
- RenderingGroup._RenderSorted(subMeshes, this._opaqueSortCompareFn, this._scene.activeCamera, false);
- }
- /**
- * Renders the opaque submeshes in the order from the alphatestSortCompareFn.
- * @param subMeshes The submeshes to render
- */
- _renderAlphaTestSorted(subMeshes) {
- RenderingGroup._RenderSorted(subMeshes, this._alphaTestSortCompareFn, this._scene.activeCamera, false);
- }
- /**
- * Renders the opaque submeshes in the order from the transparentSortCompareFn.
- * @param subMeshes The submeshes to render
- */
- _renderTransparentSorted(subMeshes) {
- RenderingGroup._RenderSorted(subMeshes, this._transparentSortCompareFn, this._scene.activeCamera, true);
- }
- /**
- * Renders the submeshes in a specified order.
- * @param subMeshes The submeshes to sort before render
- * @param sortCompareFn The comparison function use to sort
- * @param camera The camera position use to preprocess the submeshes to help sorting
- * @param transparent Specifies to activate blending if true
- */
- static _RenderSorted(subMeshes, sortCompareFn, camera, transparent) {
- let subIndex = 0;
- let subMesh;
- const cameraPosition = camera ? camera.globalPosition : RenderingGroup._ZeroVector;
- if (transparent) {
- for (; subIndex < subMeshes.length; subIndex++) {
- subMesh = subMeshes.data[subIndex];
- subMesh._alphaIndex = subMesh.getMesh().alphaIndex;
- subMesh._distanceToCamera = Vector3.Distance(subMesh.getBoundingInfo().boundingSphere.centerWorld, cameraPosition);
- }
- }
- const sortedArray = subMeshes.length === subMeshes.data.length ? subMeshes.data : subMeshes.data.slice(0, subMeshes.length);
- if (sortCompareFn) {
- sortedArray.sort(sortCompareFn);
- }
- const scene = sortedArray[0].getMesh().getScene();
- for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
- subMesh = sortedArray[subIndex];
- if (scene._activeMeshesFrozenButKeepClipping && !subMesh.isInFrustum(scene._frustumPlanes)) {
- continue;
- }
- if (transparent) {
- const material = subMesh.getMaterial();
- if (material && material.needDepthPrePass) {
- const engine = material.getScene().getEngine();
- engine.setColorWrite(false);
- engine.setAlphaMode(0);
- subMesh.render(false);
- engine.setColorWrite(true);
- }
- }
- subMesh.render(transparent);
- }
- }
- /**
- * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
- * are rendered back to front if in the same alpha index.
- *
- * @param a The first submesh
- * @param b The second submesh
- * @returns The result of the comparison
- */
- // eslint-disable-next-line @typescript-eslint/naming-convention
- static defaultTransparentSortCompare(a, b) {
- // Alpha index first
- if (a._alphaIndex > b._alphaIndex) {
- return 1;
- }
- if (a._alphaIndex < b._alphaIndex) {
- return -1;
- }
- // Then distance to camera
- return RenderingGroup.backToFrontSortCompare(a, b);
- }
- /**
- * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
- * are rendered back to front.
- *
- * @param a The first submesh
- * @param b The second submesh
- * @returns The result of the comparison
- */
- // eslint-disable-next-line @typescript-eslint/naming-convention
- static backToFrontSortCompare(a, b) {
- // Then distance to camera
- if (a._distanceToCamera < b._distanceToCamera) {
- return 1;
- }
- if (a._distanceToCamera > b._distanceToCamera) {
- return -1;
- }
- return 0;
- }
- /**
- * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
- * are rendered front to back (prevent overdraw).
- *
- * @param a The first submesh
- * @param b The second submesh
- * @returns The result of the comparison
- */
- // eslint-disable-next-line @typescript-eslint/naming-convention
- static frontToBackSortCompare(a, b) {
- // Then distance to camera
- if (a._distanceToCamera < b._distanceToCamera) {
- return -1;
- }
- if (a._distanceToCamera > b._distanceToCamera) {
- return 1;
- }
- return 0;
- }
- /**
- * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
- * are grouped by material then geometry.
- *
- * @param a The first submesh
- * @param b The second submesh
- * @returns The result of the comparison
- */
- static PainterSortCompare(a, b) {
- const meshA = a.getMesh();
- const meshB = b.getMesh();
- if (meshA.material && meshB.material) {
- return meshA.material.uniqueId - meshB.material.uniqueId;
- }
- return meshA.uniqueId - meshB.uniqueId;
- }
- /**
- * Resets the different lists of submeshes to prepare a new frame.
- */
- prepare() {
- this._opaqueSubMeshes.reset();
- this._transparentSubMeshes.reset();
- this._alphaTestSubMeshes.reset();
- this._depthOnlySubMeshes.reset();
- this._particleSystems.reset();
- this.prepareSprites();
- this._edgesRenderers.reset();
- this._empty = true;
- }
- /**
- * Resets the different lists of sprites to prepare a new frame.
- */
- prepareSprites() {
- this._spriteManagers.reset();
- }
- dispose() {
- this._opaqueSubMeshes.dispose();
- this._transparentSubMeshes.dispose();
- this._alphaTestSubMeshes.dispose();
- this._depthOnlySubMeshes.dispose();
- this._particleSystems.dispose();
- this._spriteManagers.dispose();
- this._edgesRenderers.dispose();
- }
- /**
- * Inserts the submesh in its correct queue depending on its material.
- * @param subMesh The submesh to dispatch
- * @param [mesh] Optional reference to the submeshes's mesh. Provide if you have an exiting reference to improve performance.
- * @param [material] Optional reference to the submeshes's material. Provide if you have an exiting reference to improve performance.
- */
- dispatch(subMesh, mesh, material) {
- // Get mesh and materials if not provided
- if (mesh === undefined) {
- mesh = subMesh.getMesh();
- }
- if (material === undefined) {
- material = subMesh.getMaterial();
- }
- if (material === null || material === undefined) {
- return;
- }
- if (material.needAlphaBlendingForMesh(mesh)) {
- // Transparent
- this._transparentSubMeshes.push(subMesh);
- }
- else if (material.needAlphaTesting()) {
- // Alpha test
- if (material.needDepthPrePass) {
- this._depthOnlySubMeshes.push(subMesh);
- }
- this._alphaTestSubMeshes.push(subMesh);
- }
- else {
- if (material.needDepthPrePass) {
- this._depthOnlySubMeshes.push(subMesh);
- }
- this._opaqueSubMeshes.push(subMesh); // Opaque
- }
- mesh._renderingGroup = this;
- if (mesh._edgesRenderer && mesh._edgesRenderer.isEnabled) {
- this._edgesRenderers.pushNoDuplicate(mesh._edgesRenderer);
- }
- this._empty = false;
- }
- dispatchSprites(spriteManager) {
- this._spriteManagers.push(spriteManager);
- this._empty = false;
- }
- dispatchParticles(particleSystem) {
- this._particleSystems.push(particleSystem);
- this._empty = false;
- }
- _renderParticles(activeMeshes) {
- if (this._particleSystems.length === 0) {
- return;
- }
- // Particles
- const activeCamera = this._scene.activeCamera;
- this._scene.onBeforeParticlesRenderingObservable.notifyObservers(this._scene);
- for (let particleIndex = 0; particleIndex < this._particleSystems.length; particleIndex++) {
- const particleSystem = this._particleSystems.data[particleIndex];
- if ((activeCamera && activeCamera.layerMask & particleSystem.layerMask) === 0) {
- continue;
- }
- const emitter = particleSystem.emitter;
- if (!emitter.position || !activeMeshes || activeMeshes.indexOf(emitter) !== -1) {
- this._scene._activeParticles.addCount(particleSystem.render(), false);
- }
- }
- this._scene.onAfterParticlesRenderingObservable.notifyObservers(this._scene);
- }
- _renderSprites() {
- if (!this._scene.spritesEnabled || this._spriteManagers.length === 0) {
- return;
- }
- // Sprites
- const activeCamera = this._scene.activeCamera;
- this._scene.onBeforeSpritesRenderingObservable.notifyObservers(this._scene);
- for (let id = 0; id < this._spriteManagers.length; id++) {
- const spriteManager = this._spriteManagers.data[id];
- if ((activeCamera && activeCamera.layerMask & spriteManager.layerMask) !== 0) {
- spriteManager.render();
- }
- }
- this._scene.onAfterSpritesRenderingObservable.notifyObservers(this._scene);
- }
- }
- RenderingGroup._ZeroVector = Vector3.Zero();
- //# sourceMappingURL=renderingGroup.js.map
|