From 9c1b561b5428f55ba72a3997c2011499fe2cd84d Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 21 Aug 2023 20:12:17 +0800 Subject: [PATCH 001/218] refactor(renderpipeline): refactor framework --- .../src/2d/assembler/TiledSpriteAssembler.ts | 10 +- packages/core/src/2d/sprite/SpriteMask.ts | 8 +- packages/core/src/2d/sprite/SpriteRenderer.ts | 7 +- packages/core/src/2d/text/TextRenderer.ts | 14 +- packages/core/src/Camera.ts | 7 + packages/core/src/Engine.ts | 14 - .../core/src/RenderPipeline/Basic2DBatcher.ts | 255 -------------- .../src/RenderPipeline/BasicRenderPipeline.ts | 23 +- .../core/src/RenderPipeline/MeshRenderData.ts | 6 + .../core/src/RenderPipeline/RenderData.ts | 4 +- .../core/src/RenderPipeline/RenderQueue.ts | 166 ++++----- .../core/src/RenderPipeline/SpriteBatcher.ts | 152 -------- .../src/RenderPipeline/SpriteMaskBatcher.ts | 105 ------ .../src/RenderPipeline/SpriteMaskManager.ts | 27 +- .../RenderPipeline/SpriteMaskRenderData.ts | 25 -- .../src/RenderPipeline/SpriteRenderData.ts | 7 +- .../core/src/RenderPipeline/TextRenderData.ts | 17 - .../src/RenderPipeline/batcher/Batcher2D.ts | 279 +++++++++++++++ .../RenderPipeline/batcher/BatcherManager.ts | 58 ++++ .../src/RenderPipeline/batcher/IBatcher.ts | 9 + .../batcher/SpriteMaskBatcher.ts | 325 ++++++++++++++++++ .../RenderPipeline/enums/RenderDataUsage.ts | 11 + packages/core/src/index.ts | 1 - packages/core/src/mesh/MeshRenderer.ts | 6 +- tests/src/core/SpriteMask.test.ts | 2 +- 25 files changed, 827 insertions(+), 711 deletions(-) delete mode 100644 packages/core/src/RenderPipeline/Basic2DBatcher.ts delete mode 100644 packages/core/src/RenderPipeline/SpriteBatcher.ts delete mode 100644 packages/core/src/RenderPipeline/SpriteMaskBatcher.ts delete mode 100644 packages/core/src/RenderPipeline/SpriteMaskRenderData.ts delete mode 100644 packages/core/src/RenderPipeline/TextRenderData.ts create mode 100644 packages/core/src/RenderPipeline/batcher/Batcher2D.ts create mode 100644 packages/core/src/RenderPipeline/batcher/BatcherManager.ts create mode 100644 packages/core/src/RenderPipeline/batcher/IBatcher.ts create mode 100644 packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts create mode 100644 packages/core/src/RenderPipeline/enums/RenderDataUsage.ts diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index f5450462c3..5dfb5a187a 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -2,11 +2,11 @@ import { MathUtil, Matrix, Vector2, Vector3 } from "@galacean/engine-math"; import { StaticInterfaceImplement } from "../../base/StaticInterfaceImplement"; import { DisorderedArray } from "../../DisorderedArray"; import { SpriteTileMode } from "../enums/SpriteTileMode"; -import { Basic2DBatcher } from "../../RenderPipeline/Basic2DBatcher"; import { Sprite } from "../sprite"; import { SpriteRenderer } from "../sprite/SpriteRenderer"; import { IAssembler } from "./IAssembler"; import { Logger } from "../../base"; +import { Batcher2D } from "../../RenderPipeline/batcher/Batcher2D"; /** * @internal @@ -188,12 +188,12 @@ export class TiledSpriteAssembler { } } - if ((rVertCount - 1) * (cVertCount - 1) * 4 > Basic2DBatcher.MAX_VERTEX_COUNT) { + if ((rVertCount - 1) * (cVertCount - 1) * 4 > Batcher2D.MAX_VERTEX_COUNT) { posRow.add(width * left), posRow.add(width * right); posColumn.add(height * bottom), posColumn.add(height * top); uvRow.add(spriteUV0.x), uvRow.add(spriteUV3.x); uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV3.y); - Logger.warn(`The number of vertices exceeds the upper limit(${Basic2DBatcher.MAX_VERTEX_COUNT}).`); + Logger.warn(`The number of vertices exceeds the upper limit(${Batcher2D.MAX_VERTEX_COUNT}).`); return; } @@ -308,12 +308,12 @@ export class TiledSpriteAssembler { } } - if ((rVertCount - 1) * (cVertCount - 1) * 4 > Basic2DBatcher.MAX_VERTEX_COUNT) { + if ((rVertCount - 1) * (cVertCount - 1) * 4 > Batcher2D.MAX_VERTEX_COUNT) { posRow.add(width * left), posRow.add(width * right); posColumn.add(height * bottom), posColumn.add(height * top); uvRow.add(spriteUV0.x), uvRow.add(spriteUV3.x); uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV3.y); - Logger.warn(`The number of vertices exceeds the upper limit(${Basic2DBatcher.MAX_VERTEX_COUNT}).`); + Logger.warn(`The number of vertices exceeds the upper limit(${Batcher2D.MAX_VERTEX_COUNT}).`); return; } diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 54b0552db2..ecd3fe76bf 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -10,6 +10,7 @@ import { VertexData2D } from "../data/VertexData2D"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { SpriteModifyFlags } from "../enums/SpriteModifyFlags"; import { Sprite } from "./Sprite"; +import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; /** * A component for masking Sprites. @@ -215,11 +216,12 @@ export class SpriteMask extends Renderer { this._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.UV; } - context.camera._renderPipeline._allSpriteMasks.add(this); + context.camera._renderPipeline._spriteMaskManager.addMask(this); - const renderData = this._engine._spriteMaskRenderDataPool.getFromPool(); + const renderData = this._engine._spriteRenderDataPool.getFromPool(); const material = this.getMaterial(); - renderData.set(this, material, this._verticesData); + renderData.set(this, material, this._verticesData, this.sprite.texture); + renderData.usage = RenderDataUsage.SpriteMask; const renderElement = this._engine._renderElementPool.getFromPool(); const pass = material.shader.subShaders[0].passes[0]; diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 2204e1e2e4..e38df6f7bc 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -16,6 +16,7 @@ import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { SpriteModifyFlags } from "../enums/SpriteModifyFlags"; import { SpriteTileMode } from "../enums/SpriteTileMode"; import { Sprite } from "./Sprite"; +import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; /** * Renders a Sprite for 2D graphics. @@ -322,10 +323,10 @@ export class SpriteRenderer extends Renderer { // Push primitive const material = this.getMaterial(); - const texture = this.sprite.texture; const renderData = this._engine._spriteRenderDataPool.getFromPool(); - renderData.set(this, material, this._verticesData, texture); - context.camera._renderPipeline.pushRenderData(context, renderData); + renderData.set(this, material, this._verticesData, this.sprite.texture); + renderData.usage = RenderDataUsage.Sprite; + context.camera._batcherManager.commitRenderData(context, renderData); } /** diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index dc75e7366c..281d77a6c9 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -16,6 +16,7 @@ import { CharRenderDataPool } from "./CharRenderDataPool"; import { Font } from "./Font"; import { SubFont } from "./SubFont"; import { TextUtils } from "./TextUtils"; +import { SpriteRenderData } from "../../RenderPipeline/SpriteRenderData"; /** * Renders a text for 2D graphics. @@ -387,23 +388,18 @@ export class TextRenderer extends Renderer { } const spriteRenderDataPool = this._engine._spriteRenderDataPool; - const textData = this._engine._textRenderDataPool.getFromPool(); - const charsData = textData.charsData; const material = this.getMaterial(); const charRenderDatas = this._charRenderDatas; const charCount = charRenderDatas.length; - textData.component = this; - textData.material = material; - charsData.length = charCount; - + let spriteRenderDatas: Array = []; for (let i = 0; i < charCount; ++i) { const charRenderData = charRenderDatas[i]; const spriteRenderData = spriteRenderDataPool.getFromPool(); - spriteRenderData.set(this, material, charRenderData.renderData, charRenderData.texture, i); - charsData[i] = spriteRenderData; + spriteRenderData.set(this, material, charRenderData.renderData, charRenderData.texture); + spriteRenderDatas.push(spriteRenderData); } - context.camera._renderPipeline.pushRenderData(context, textData); + context.camera._batcherManager.commitRenderData(context, spriteRenderDatas); } private _updateStencilState(): void { diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 37e92c8a67..5b89e5ec1b 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -18,6 +18,7 @@ import { ShaderTagKey } from "./shader/ShaderTagKey"; import { ShaderDataGroup } from "./shader/enums/ShaderDataGroup"; import { RenderTarget } from "./texture/RenderTarget"; import { TextureCubeFace } from "./texture/enums/TextureCubeFace"; +import { BatcherManager } from "./RenderPipeline/batcher/BatcherManager"; class MathTemp { static tempVec4 = new Vector4(); @@ -61,6 +62,9 @@ export class Camera extends Component { _renderPipeline: BasicRenderPipeline; /** @internal */ @ignoreClone + _batcherManager: BatcherManager; + /** @internal */ + @ignoreClone _virtualCamera: VirtualCamera = new VirtualCamera(); /** @internal */ _replacementShader: Shader = null; @@ -306,6 +310,7 @@ export class Camera extends Component { this._isInvViewProjDirty = transform.registerWorldChangeFlag(); this._frustumViewChangeFlag = transform.registerWorldChangeFlag(); this._renderPipeline = new BasicRenderPipeline(this); + this._batcherManager = new BatcherManager(this.engine); this.shaderData._addReferCount(1); } @@ -556,6 +561,7 @@ export class Camera extends Component { protected override _onDestroy(): void { super._onDestroy(); this._renderPipeline?.destroy(); + this._batcherManager?.destroy(); this._isInvViewProjDirty.destroy(); this._isViewMatrixDirty.destroy(); this.shaderData._addReferCount(-1); @@ -564,6 +570,7 @@ export class Camera extends Component { this._globalShaderMacro = null; this._frustum = null; this._renderPipeline = null; + this._batcherManager = null; this._virtualCamera = null; this._shaderData = null; this._frustumViewChangeFlag = null; diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 7856646a04..e026dd0b43 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -9,9 +9,7 @@ import { MeshRenderData } from "./RenderPipeline/MeshRenderData"; import { RenderContext } from "./RenderPipeline/RenderContext"; import { RenderElement } from "./RenderPipeline/RenderElement"; import { SpriteMaskManager } from "./RenderPipeline/SpriteMaskManager"; -import { SpriteMaskRenderData } from "./RenderPipeline/SpriteMaskRenderData"; import { SpriteRenderData } from "./RenderPipeline/SpriteRenderData"; -import { TextRenderData } from "./RenderPipeline/TextRenderData"; import { Scene } from "./Scene"; import { SceneManager } from "./SceneManager"; import { ContentRestorer } from "./asset/ContentRestorer"; @@ -72,10 +70,6 @@ export class Engine extends EventDispatcher { _meshRenderDataPool: ClassPool = new ClassPool(MeshRenderData); /* @internal */ _spriteRenderDataPool: ClassPool = new ClassPool(SpriteRenderData); - /* @internal */ - _spriteMaskRenderDataPool: ClassPool = new ClassPool(SpriteMaskRenderData); - /* @internal */ - _textRenderDataPool: ClassPool = new ClassPool(TextRenderData); /* @internal */ _spriteDefaultMaterial: Material; @@ -104,8 +98,6 @@ export class Engine extends EventDispatcher { /* @internal */ _shaderProgramPools: ShaderProgramPool[] = []; /** @internal */ - _spriteMaskManager: SpriteMaskManager; - /** @internal */ _canSpriteBatch: boolean = true; /** @internal */ _fontMap: Record = {}; @@ -229,7 +221,6 @@ export class Engine extends EventDispatcher { this._canvas = canvas; - this._spriteMaskManager = new SpriteMaskManager(this); this._spriteDefaultMaterial = this._createSpriteMaterial(); this._spriteMaskDefaultMaterial = this._createSpriteMaskMaterial(); this._textDefaultFont = Font.createFromOS(this, "Arial"); @@ -308,8 +299,6 @@ export class Engine extends EventDispatcher { this._renderElementPool.resetPool(); this._meshRenderDataPool.resetPool(); this._spriteRenderDataPool.resetPool(); - this._spriteMaskRenderDataPool.resetPool(); - this._textRenderDataPool.resetPool(); const { inputManager, _physicsInitialized: physicsInitialized } = this; inputManager._update(); @@ -418,7 +407,6 @@ export class Engine extends EventDispatcher { // Cancel animation this.pause(); - this._spriteMaskManager.destroy(); this._hardwareRenderer.destroy(); this.removeAllEventListeners(); @@ -668,8 +656,6 @@ export class Engine extends EventDispatcher { this._renderElementPool.garbageCollection(); this._meshRenderDataPool.garbageCollection(); this._spriteRenderDataPool.garbageCollection(); - this._spriteMaskRenderDataPool.garbageCollection(); - this._textRenderDataPool.garbageCollection(); } /** diff --git a/packages/core/src/RenderPipeline/Basic2DBatcher.ts b/packages/core/src/RenderPipeline/Basic2DBatcher.ts deleted file mode 100644 index 36a8d68248..0000000000 --- a/packages/core/src/RenderPipeline/Basic2DBatcher.ts +++ /dev/null @@ -1,255 +0,0 @@ -import { Camera } from "../Camera"; -import { Engine } from "../Engine"; -import { Buffer, BufferBindFlag, BufferUsage, IndexFormat, MeshTopology, SubMesh, VertexElement } from "../graphic"; -import { BufferMesh } from "../mesh"; -import { ShaderTagKey } from "../shader/ShaderTagKey"; -import { ClassPool } from "./ClassPool"; -import { RenderElement } from "./RenderElement"; -import { SpriteMaskRenderData } from "./SpriteMaskRenderData"; -import { SpriteRenderData } from "./SpriteRenderData"; -import { TextRenderData } from "./TextRenderData"; - -type SpriteData = SpriteRenderData | SpriteMaskRenderData; - -export abstract class Basic2DBatcher { - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - - /** The maximum number of vertex. */ - static MAX_VERTEX_COUNT: number = 4096; - static _canUploadSameBuffer: boolean = true; - - /** @internal */ - _engine: Engine; - /** @internal */ - _subMeshPool: ClassPool = new ClassPool(SubMesh); - /** @internal */ - _batchedQueue: RenderElement[] = []; - /** @internal */ - _meshes: BufferMesh[] = []; - /** @internal */ - _meshCount: number = 1; - /** @internal */ - _vertexBuffers: Buffer[] = []; - /** @internal */ - _indiceBuffers: Buffer[] = []; - /** @internal */ - _vertices: Float32Array; - /** @internal */ - _indices: Uint16Array; - /** @internal */ - _flushId: number = 0; - /** @internal */ - _vertexCount: number = 0; - /** @internal */ - _elementCount: number = 0; - - constructor(engine: Engine) { - this._engine = engine; - this._initMeshes(engine); - } - - drawElement(element: RenderElement, camera: Camera): void { - const data = element.data; - - if (data.multiRenderData) { - const charsData = (data).charsData; - const pool = camera.engine._renderElementPool; - - for (let i = 0, n = charsData.length; i < n; ++i) { - const charRenderElement = pool.getFromPool(); - charRenderElement.set(charsData[i], element.shaderPass, element.renderState); - this._drawSubElement(charRenderElement, camera); - } - } else { - this._drawSubElement(element, camera); - } - } - - /** - * @internal - * Standalone for canvas 2d renderer plugin. - */ - _initMeshes(engine: Engine) { - const { MAX_VERTEX_COUNT } = Basic2DBatcher; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 3); - - const { _meshes, _meshCount } = this; - for (let i = 0; i < _meshCount; i++) { - _meshes[i] = this._createMesh(engine, i); - } - } - - flush(camera: Camera): void { - const batchedQueue = this._batchedQueue; - - if (batchedQueue.length === 0) { - return; - } - this._updateData(this._engine); - this.drawBatches(camera); - - if (!Basic2DBatcher._canUploadSameBuffer) { - this._flushId++; - } - - batchedQueue.length = 0; - this._subMeshPool.resetPool(); - this._vertexCount = 0; - this._elementCount = 0; - } - - clear(): void { - this._flushId = 0; - this._vertexCount = 0; - this._elementCount = 0; - this._batchedQueue.length = 0; - } - - destroy(): void { - this._batchedQueue = null; - - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - meshes[i].destroy(); - } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; - } - - private _drawSubElement(element: RenderElement, camera: Camera): void { - const vertexCount = (element.data).verticesData.vertexCount; - if (this._vertexCount + vertexCount > Basic2DBatcher.MAX_VERTEX_COUNT) { - this.flush(camera); - } - - this._vertexCount += vertexCount; - this._batchedQueue[this._elementCount++] = element; - } - - private _createMesh(engine: Engine, index: number): BufferMesh { - const { MAX_VERTEX_COUNT } = Basic2DBatcher; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh.isGCIgnored = true; - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 6, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - - return mesh; - } - - private _updateData(engine: Engine): void { - const { _meshes, _flushId } = this; - - if (!Basic2DBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { - this._meshCount++; - _meshes[_flushId] = this._createMesh(engine, _flushId); - } - - const { _batchedQueue: batchedQueue, _vertices: vertices, _indices: indices } = this; - const mesh = _meshes[_flushId]; - mesh.clearSubMesh(); - - let vertexIndex = 0; - let indiceIndex = 0; - let vertexStartIndex = 0; - let vertexCount = 0; - let curIndiceStartIndex = 0; - let curMeshIndex = 0; - let preElement: RenderElement = null; - for (let i = 0, len = batchedQueue.length; i < len; i++) { - const curElement = batchedQueue[i]; - const curData = curElement.data; - - // Batch vertex - vertexIndex = this.updateVertices(curData, vertices, vertexIndex); - - // Batch indice - const { triangles } = curData.verticesData; - const triangleNum = triangles.length; - for (let j = 0; j < triangleNum; j++) { - indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; - } - - curIndiceStartIndex += curData.verticesData.vertexCount; - - if (preElement === null) { - vertexCount += triangleNum; - } else { - if (this.canBatch(preElement, curElement)) { - vertexCount += triangleNum; - } else { - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - vertexStartIndex += vertexCount; - vertexCount = triangleNum; - batchedQueue[curMeshIndex++] = preElement; - } - } - - preElement = curElement; - } - - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - batchedQueue[curMeshIndex] = preElement; - - this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex); - this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex); - } - - private _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } - - /** - * @internal - */ - abstract createVertexElements(vertexElements: VertexElement[]): number; - - /** - * @internal - */ - abstract canBatch(preElement: RenderElement, curElement: RenderElement): boolean; - - /** - * @internal - */ - abstract updateVertices(element: SpriteData, vertices: Float32Array, vertexIndex: number): number; - - /** - * @internal - */ - abstract drawBatches(camera: Camera): void; -} diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 6f484226ec..6d1e7a511a 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -1,8 +1,6 @@ import { Vector2 } from "@galacean/engine-math"; -import { SpriteMask } from "../2d"; import { Background } from "../Background"; import { Camera } from "../Camera"; -import { DisorderedArray } from "../DisorderedArray"; import { Engine } from "../Engine"; import { Layer } from "../Layer"; import { BackgroundMode } from "../enums/BackgroundMode"; @@ -21,6 +19,7 @@ import { RenderData } from "./RenderData"; import { RenderPass } from "./RenderPass"; import { RenderQueue } from "./RenderQueue"; import { PipelineStage } from "./enums/PipelineStage"; +import { SpriteMaskManager } from "./SpriteMaskManager"; /** * Basic render pipeline. @@ -36,7 +35,7 @@ export class BasicRenderPipeline { /** @internal */ _alphaTestQueue: RenderQueue; /** @internal */ - _allSpriteMasks: DisorderedArray = new DisorderedArray(); + _spriteMaskManager: SpriteMaskManager; private _camera: Camera; private _defaultPass: RenderPass; @@ -50,11 +49,11 @@ export class BasicRenderPipeline { */ constructor(camera: Camera) { this._camera = camera; - const { engine } = camera; - this._opaqueQueue = new RenderQueue(engine); - this._alphaTestQueue = new RenderQueue(engine); - this._transparentQueue = new RenderQueue(engine); + this._opaqueQueue = new RenderQueue(); + this._alphaTestQueue = new RenderQueue(); + this._transparentQueue = new RenderQueue(); this._cascadedShadowCaster = new CascadedShadowCasterPass(camera); + this._spriteMaskManager = new SpriteMaskManager(camera.engine); this._renderPassArray = []; this._defaultPass = new RenderPass("default", 0, null, null, 0); @@ -129,7 +128,7 @@ export class BasicRenderPipeline { this._opaqueQueue.destroy(); this._alphaTestQueue.destroy(); this._transparentQueue.destroy(); - this._allSpriteMasks = null; + this._spriteMaskManager.destroy(); this._renderPassArray = null; this._defaultPass = null; this._camera = null; @@ -147,8 +146,7 @@ export class BasicRenderPipeline { const opaqueQueue = this._opaqueQueue; const alphaTestQueue = this._alphaTestQueue; const transparentQueue = this._transparentQueue; - - camera.engine._spriteMaskManager.clear(); + const batcherManager = camera._batcherManager; context.pipelineStageTagValue = BasicRenderPipeline._shadowCasterPipelineStageTagValue; if (scene.castShadows && scene._sunLight?.shadowType !== ShadowType.None) { @@ -157,12 +155,15 @@ export class BasicRenderPipeline { opaqueQueue.clear(); alphaTestQueue.clear(); transparentQueue.clear(); - this._allSpriteMasks.length = 0; + batcherManager.clear(); + this._spriteMaskManager.clear(); context.applyVirtualCamera(camera._virtualCamera); context.pipelineStageTagValue = BasicRenderPipeline._forwardPipelineStageTagValue; this._callRender(context); + batcherManager.flush(); + batcherManager.uploadBuffer(); opaqueQueue.sort(RenderQueue._compareFromNearToFar); alphaTestQueue.sort(RenderQueue._compareFromNearToFar); transparentQueue.sort(RenderQueue._compareFromFarToNear); diff --git a/packages/core/src/RenderPipeline/MeshRenderData.ts b/packages/core/src/RenderPipeline/MeshRenderData.ts index cfc41cd32c..556c2d1ffd 100644 --- a/packages/core/src/RenderPipeline/MeshRenderData.ts +++ b/packages/core/src/RenderPipeline/MeshRenderData.ts @@ -2,6 +2,7 @@ import { Mesh } from "../graphic/Mesh"; import { SubMesh } from "../graphic/SubMesh"; import { Material } from "../material/Material"; import { Renderer } from "../Renderer"; +import { RenderDataUsage } from "./enums/RenderDataUsage"; import { IPoolElement } from "./IPoolElement"; import { RenderData } from "./RenderData"; @@ -14,6 +15,11 @@ export class MeshRenderData extends RenderData implements IPoolElement { /** Sub mesh. */ subMesh: SubMesh; + constructor() { + super(); + this.usage = RenderDataUsage.Mesh; + } + set(component: Renderer, material: Material, mesh: Mesh, subMesh: SubMesh): void { this.component = component; this.material = material; diff --git a/packages/core/src/RenderPipeline/RenderData.ts b/packages/core/src/RenderPipeline/RenderData.ts index f5bcca0ce1..cd7b63dc5c 100644 --- a/packages/core/src/RenderPipeline/RenderData.ts +++ b/packages/core/src/RenderPipeline/RenderData.ts @@ -1,9 +1,9 @@ import { Material } from "../material"; import { Renderer } from "../Renderer"; +import { RenderDataUsage } from "./enums/RenderDataUsage"; export class RenderData { component: Renderer; material: Material; - - multiRenderData: boolean; + usage: RenderDataUsage; } diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 6fdb1a906b..e6bca4fc6a 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -1,11 +1,13 @@ +import { SpriteRenderer } from "../2d"; import { Camera } from "../Camera"; -import { Engine } from "../Engine"; import { Layer } from "../Layer"; +import { Renderer } from "../Renderer"; +import { MeshRenderer } from "../mesh"; import { Shader } from "../shader"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; import { MeshRenderData } from "./MeshRenderData"; import { RenderElement } from "./RenderElement"; -import { SpriteBatcher } from "./SpriteBatcher"; +import { RenderDataUsage } from "./enums/RenderDataUsage"; /** * Render queue. @@ -32,11 +34,6 @@ export class RenderQueue { } readonly elements: RenderElement[] = []; - private _spriteBatcher: SpriteBatcher; - - constructor(engine: Engine) { - this._initSpriteBatcher(engine); - } /** * Push a render element. @@ -52,6 +49,7 @@ export class RenderQueue { } const { engine, scene } = camera; + const { _spriteMaskManager } = camera._renderPipeline; const renderCount = engine._renderCount; const rhi = engine._hardwareRenderer; const sceneData = scene.shaderData; @@ -66,93 +64,89 @@ export class RenderQueue { continue; } - if (!!(data as MeshRenderData).mesh) { - this._spriteBatcher.flush(camera); + const isSprite = data.usage === RenderDataUsage.Sprite; + const meshData = data; + const renderer = meshData.component; + if (isSprite) { + _spriteMaskManager.preRender(camera, renderer); + } - const compileMacros = Shader._compileMacros; - const meshData = data; - const renderer = meshData.component; - const material = meshData.material.destroyed ? engine._magentaMaterial : meshData.material; - const rendererData = renderer.shaderData; - const materialData = material.shaderData; + const compileMacros = Shader._compileMacros; + const material = meshData.material.destroyed ? engine._magentaMaterial : meshData.material; + const rendererData = renderer.shaderData; + const materialData = material.shaderData; - // union render global macro and material self macro. - ShaderMacroCollection.unionCollection( - renderer._globalShaderMacro, - materialData._macroCollection, - compileMacros - ); + // union render global macro and material self macro. + ShaderMacroCollection.unionCollection(renderer._globalShaderMacro, materialData._macroCollection, compileMacros); - const shaderPass = element.shaderPass; - const program = shaderPass._getShaderProgram(engine, compileMacros); - if (!program.isValid) { - continue; - } + const shaderPass = element.shaderPass; + const program = shaderPass._getShaderProgram(engine, compileMacros); + if (!program.isValid) { + continue; + } - const switchProgram = program.bind(); - const switchRenderCount = renderCount !== program._uploadRenderCount; + const switchProgram = program.bind(); + const switchRenderCount = renderCount !== program._uploadRenderCount; - if (switchRenderCount) { - program.groupingOtherUniformBlock(); + if (switchRenderCount) { + program.groupingOtherUniformBlock(); + program.uploadAll(program.sceneUniformBlock, sceneData); + program.uploadAll(program.cameraUniformBlock, cameraData); + program.uploadAll(program.rendererUniformBlock, rendererData); + program.uploadAll(program.materialUniformBlock, materialData); + // UnGroup textures should upload default value, texture uint maybe change by logic of texture bind. + program.uploadUnGroupTextures(); + program._uploadScene = scene; + program._uploadCamera = camera; + program._uploadRenderer = renderer; + program._uploadMaterial = material; + program._uploadRenderCount = renderCount; + } else { + if (program._uploadScene !== scene) { program.uploadAll(program.sceneUniformBlock, sceneData); - program.uploadAll(program.cameraUniformBlock, cameraData); - program.uploadAll(program.rendererUniformBlock, rendererData); - program.uploadAll(program.materialUniformBlock, materialData); - // UnGroup textures should upload default value, texture uint maybe change by logic of texture bind. - program.uploadUnGroupTextures(); program._uploadScene = scene; - program._uploadCamera = camera; - program._uploadRenderer = renderer; - program._uploadMaterial = material; - program._uploadRenderCount = renderCount; - } else { - if (program._uploadScene !== scene) { - program.uploadAll(program.sceneUniformBlock, sceneData); - program._uploadScene = scene; - } else if (switchProgram) { - program.uploadTextures(program.sceneUniformBlock, sceneData); - } + } else if (switchProgram) { + program.uploadTextures(program.sceneUniformBlock, sceneData); + } - if (program._uploadCamera !== camera) { - program.uploadAll(program.cameraUniformBlock, cameraData); - program._uploadCamera = camera; - } else if (switchProgram) { - program.uploadTextures(program.cameraUniformBlock, cameraData); - } + if (program._uploadCamera !== camera) { + program.uploadAll(program.cameraUniformBlock, cameraData); + program._uploadCamera = camera; + } else if (switchProgram) { + program.uploadTextures(program.cameraUniformBlock, cameraData); + } - if (program._uploadRenderer !== renderer) { - program.uploadAll(program.rendererUniformBlock, rendererData); - program._uploadRenderer = renderer; - } else if (switchProgram) { - program.uploadTextures(program.rendererUniformBlock, rendererData); - } + if (program._uploadRenderer !== renderer) { + program.uploadAll(program.rendererUniformBlock, rendererData); + program._uploadRenderer = renderer; + } else if (switchProgram) { + program.uploadTextures(program.rendererUniformBlock, rendererData); + } - if (program._uploadMaterial !== material) { - program.uploadAll(program.materialUniformBlock, materialData); - program._uploadMaterial = material; - } else if (switchProgram) { - program.uploadTextures(program.materialUniformBlock, materialData); - } + if (program._uploadMaterial !== material) { + program.uploadAll(program.materialUniformBlock, materialData); + program._uploadMaterial = material; + } else if (switchProgram) { + program.uploadTextures(program.materialUniformBlock, materialData); + } - // We only consider switchProgram case, because UnGroup texture's value is always default. - if (switchProgram) { - program.uploadUnGroupTextures(); - } + // We only consider switchProgram case, because UnGroup texture's value is always default. + if (switchProgram) { + program.uploadUnGroupTextures(); } - element.renderState._apply( - engine, - renderer.entity.transform._isFrontFaceInvert(), - shaderPass._renderStateDataMap, - material.shaderData - ); + } + element.renderState._apply( + engine, + renderer.entity.transform._isFrontFaceInvert(), + shaderPass._renderStateDataMap, + material.shaderData + ); - rhi.drawPrimitive(meshData.mesh, meshData.subMesh, program); - } else { - this._spriteBatcher.drawElement(element, camera); + rhi.drawPrimitive(meshData.mesh, meshData.subMesh, program); + if (isSprite) { + _spriteMaskManager.postRender(renderer); } } - - this._spriteBatcher.flush(camera); } /** @@ -160,16 +154,12 @@ export class RenderQueue { */ clear(): void { this.elements.length = 0; - this._spriteBatcher.clear(); } /** * Destroy internal resources. */ - destroy(): void { - this._spriteBatcher.destroy(); - this._spriteBatcher = null; - } + destroy(): void {} /** * Sort the elements. @@ -178,14 +168,6 @@ export class RenderQueue { this._quickSort(this.elements, 0, this.elements.length, compareFunc); } - /** - * @internal - * Standalone for CanvasRenderer plugin. - */ - _initSpriteBatcher(engine: Engine): void { - this._spriteBatcher = new SpriteBatcher(engine); - } - /** * @remarks * Modified based on v8. diff --git a/packages/core/src/RenderPipeline/SpriteBatcher.ts b/packages/core/src/RenderPipeline/SpriteBatcher.ts deleted file mode 100644 index 15c6b4eda7..0000000000 --- a/packages/core/src/RenderPipeline/SpriteBatcher.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { SpriteMaskInteraction } from "../2d/enums/SpriteMaskInteraction"; -import { SpriteRenderer } from "../2d/sprite/SpriteRenderer"; -import { Camera } from "../Camera"; -import { VertexElementFormat } from "../graphic/enums/VertexElementFormat"; -import { VertexElement } from "../graphic/VertexElement"; -import { Shader } from "../shader/Shader"; -import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; -import { ShaderProperty } from "../shader/ShaderProperty"; -import { Basic2DBatcher } from "./Basic2DBatcher"; -import { RenderElement } from "./RenderElement"; -import { SpriteRenderData } from "./SpriteRenderData"; - -/** - * @internal - */ -export class SpriteBatcher extends Basic2DBatcher { - private static _textureProperty: ShaderProperty = ShaderProperty.getByName("renderer_SpriteTexture"); - - createVertexElements(vertexElements: VertexElement[]): number { - vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); - vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); - vertexElements[2] = new VertexElement("COLOR_0", 20, VertexElementFormat.Vector4, 0); - return 36; - } - - canBatch(preElement: RenderElement, curElement: RenderElement): boolean { - if (!this._engine._canSpriteBatch || curElement.shaderPass.getTagValue(Basic2DBatcher._disableBatchTag) === true) { - return false; - } - - const preSpriteData = preElement.data; - const curSpriteData = curElement.data; - const preRenderer = preSpriteData.component; - const curRenderer = curSpriteData.component; - - // Compare mask - if (!this.checkBatchWithMask(preRenderer, curRenderer)) { - return false; - } - - // Compare texture - if (preSpriteData.texture !== curSpriteData.texture) { - return false; - } - - // Compare material - return preSpriteData.material === curSpriteData.material; - } - - checkBatchWithMask(left: SpriteRenderer, right: SpriteRenderer): boolean { - const leftMaskInteraction = left.maskInteraction; - - if (leftMaskInteraction !== right.maskInteraction) { - return false; - } - if (leftMaskInteraction === SpriteMaskInteraction.None) { - return true; - } - return left.maskLayer === right.maskLayer; - } - - updateVertices(element: SpriteRenderData, vertices: Float32Array, vertexIndex: number): number { - const { positions, uvs, color, vertexCount } = element.verticesData; - for (let i = 0; i < vertexCount; i++) { - const curPos = positions[i]; - const curUV = uvs[i]; - vertices[vertexIndex++] = curPos.x; - vertices[vertexIndex++] = curPos.y; - vertices[vertexIndex++] = curPos.z; - vertices[vertexIndex++] = curUV.x; - vertices[vertexIndex++] = curUV.y; - vertices[vertexIndex++] = color.r; - vertices[vertexIndex++] = color.g; - vertices[vertexIndex++] = color.b; - vertices[vertexIndex++] = color.a; - } - - return vertexIndex; - } - - drawBatches(camera: Camera): void { - const { _engine: engine, _batchedQueue: batchedQueue } = this; - const mesh = this._meshes[this._flushId]; - const subMeshes = mesh.subMeshes; - const maskManager = engine._spriteMaskManager; - const sceneData = camera.scene.shaderData; - const cameraData = camera.shaderData; - - for (let i = 0, len = subMeshes.length; i < len; i++) { - const subMesh = subMeshes[i]; - const spriteElement = batchedQueue[i]; - const spriteData = spriteElement.data; - - if (!subMesh || !spriteElement) { - return; - } - - const renderer = spriteData.component; - const material = spriteData.material; - maskManager.preRender(camera, renderer); - - const compileMacros = Shader._compileMacros; - // union render global macro and material self macro. - ShaderMacroCollection.unionCollection( - renderer._globalShaderMacro, - material.shaderData._macroCollection, - compileMacros - ); - - const shaderPass = spriteElement.shaderPass; - const program = shaderPass._getShaderProgram(engine, compileMacros); - if (!program.isValid) { - return; - } - - renderer.shaderData.setTexture(SpriteBatcher._textureProperty, spriteData.texture); - - program.bind(); - program.groupingOtherUniformBlock(); - program.uploadAll(program.sceneUniformBlock, sceneData); - program.uploadAll(program.cameraUniformBlock, cameraData); - program.uploadAll(program.rendererUniformBlock, renderer.shaderData); - program.uploadAll(program.materialUniformBlock, material.shaderData); - - spriteElement.renderState._apply(engine, false, shaderPass._renderStateDataMap, material.shaderData); - engine._hardwareRenderer.drawPrimitive(mesh, subMesh, program); - - maskManager.postRender(renderer); - } - } - - override destroy(): void { - this._batchedQueue = null; - - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - meshes[i].destroy(); - } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; - } -} diff --git a/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts deleted file mode 100644 index 50b14ba5a3..0000000000 --- a/packages/core/src/RenderPipeline/SpriteMaskBatcher.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { SpriteMask } from "../2d/sprite/SpriteMask"; -import { Camera } from "../Camera"; -import { VertexElementFormat } from "../graphic/enums/VertexElementFormat"; -import { VertexElement } from "../graphic/VertexElement"; -import { StencilOperation } from "../shader/enums/StencilOperation"; -import { Shader } from "../shader/Shader"; -import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; -import { Basic2DBatcher } from "./Basic2DBatcher"; -import { RenderElement } from "./RenderElement"; -import { SpriteMaskRenderData } from "./SpriteMaskRenderData"; - -export class SpriteMaskBatcher extends Basic2DBatcher { - createVertexElements(vertexElements: VertexElement[]): number { - vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); - vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); - return 20; - } - - canBatch(preElement: RenderElement, curElement: RenderElement): boolean { - const preSpriteData = preElement.data; - const curSpriteData = curElement.data; - - if (preSpriteData.isAdd !== curSpriteData.isAdd) { - return false; - } - - // Compare renderer property - const preShaderData = (preSpriteData.component).shaderData; - const curShaderData = (curSpriteData.component).shaderData; - const textureProperty = SpriteMask._textureProperty; - const alphaCutoffProperty = SpriteMask._alphaCutoffProperty; - - return ( - preShaderData.getTexture(textureProperty) === curShaderData.getTexture(textureProperty) && - preShaderData.getTexture(alphaCutoffProperty) === curShaderData.getTexture(alphaCutoffProperty) - ); - } - - updateVertices(element: SpriteMaskRenderData, vertices: Float32Array, vertexIndex: number): number { - const { positions, uvs, vertexCount } = element.verticesData; - for (let i = 0; i < vertexCount; i++) { - const curPos = positions[i]; - const curUV = uvs[i]; - vertices[vertexIndex++] = curPos.x; - vertices[vertexIndex++] = curPos.y; - vertices[vertexIndex++] = curPos.z; - vertices[vertexIndex++] = curUV.x; - vertices[vertexIndex++] = curUV.y; - } - - return vertexIndex; - } - - drawBatches(camera: Camera): void { - const { _engine: engine, _batchedQueue: batchedQueue } = this; - const mesh = this._meshes[this._flushId]; - const subMeshes = mesh.subMeshes; - const sceneData = camera.scene.shaderData; - const cameraData = camera.shaderData; - - for (let i = 0, len = subMeshes.length; i < len; i++) { - const subMesh = subMeshes[i]; - const spriteMaskElement = batchedQueue[i]; - const spritMaskData = spriteMaskElement.data; - - if (!subMesh || !spriteMaskElement) { - return; - } - - const renderer = spritMaskData.component; - const material = spritMaskData.material; - - const compileMacros = Shader._compileMacros; - // union render global macro and material self macro. - ShaderMacroCollection.unionCollection( - renderer._globalShaderMacro, - material.shaderData._macroCollection, - compileMacros - ); - - // Update stencil state - const stencilState = material.renderState.stencilState; - const op = spritMaskData.isAdd ? StencilOperation.IncrementSaturate : StencilOperation.DecrementSaturate; - stencilState.passOperationFront = op; - stencilState.passOperationBack = op; - - const pass = material.shader.subShaders[0].passes[0]; - const program = pass._getShaderProgram(engine, compileMacros); - if (!program.isValid) { - return; - } - - program.bind(); - program.groupingOtherUniformBlock(); - program.uploadAll(program.sceneUniformBlock, sceneData); - program.uploadAll(program.cameraUniformBlock, cameraData); - program.uploadAll(program.rendererUniformBlock, renderer.shaderData); - program.uploadAll(program.materialUniformBlock, material.shaderData); - - material.renderState._apply(engine, false, pass._renderStateDataMap, material.shaderData); - - engine._hardwareRenderer.drawPrimitive(mesh, subMesh, program); - } - } -} diff --git a/packages/core/src/RenderPipeline/SpriteMaskManager.ts b/packages/core/src/RenderPipeline/SpriteMaskManager.ts index f224255171..fde52d64dd 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskManager.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskManager.ts @@ -1,15 +1,20 @@ +import { SpriteMask } from "../2d"; import { SpriteMaskInteraction } from "../2d/enums/SpriteMaskInteraction"; import { SpriteRenderer } from "../2d/sprite/SpriteRenderer"; import { Camera } from "../Camera"; +import { DisorderedArray } from "../DisorderedArray"; import { Engine } from "../Engine"; -import { SpriteMaskBatcher } from "./SpriteMaskBatcher"; -import { SpriteMaskRenderData } from "./SpriteMaskRenderData"; +import { StencilOperation } from "../shader"; +import { SpriteMaskBatcher } from "./batcher/SpriteMaskBatcher"; /** * @internal */ export class SpriteMaskManager { + /** @internal */ _batcher: SpriteMaskBatcher; + /** @internal */ + _allSpriteMasks: DisorderedArray = new DisorderedArray(); private _preMaskLayer: number = 0; @@ -17,7 +22,12 @@ export class SpriteMaskManager { this._batcher = new SpriteMaskBatcher(engine); } + addMask(mask: SpriteMask): void { + this._allSpriteMasks.add(mask); + } + clear(): void { + this._allSpriteMasks.length = 0; this._preMaskLayer = 0; this._batcher.clear(); } @@ -41,6 +51,7 @@ export class SpriteMaskManager { } destroy(): void { + this._allSpriteMasks.length = 0; this._batcher.destroy(); this._batcher = null; } @@ -49,13 +60,13 @@ export class SpriteMaskManager { const preMaskLayer = this._preMaskLayer; const curMaskLayer = renderer.maskLayer; if (preMaskLayer !== curMaskLayer) { - const allMasks = camera._renderPipeline._allSpriteMasks; + const { _allSpriteMasks: masks } = this; const commonLayer = preMaskLayer & curMaskLayer; const addLayer = curMaskLayer & ~preMaskLayer; const reduceLayer = preMaskLayer & ~curMaskLayer; - const allMaskElements = allMasks._elements; - for (let i = 0, n = allMasks.length; i < n; i++) { + const allMaskElements = masks._elements; + for (let i = 0, n = masks.length; i < n; i++) { const mask = allMaskElements[i]; const influenceLayers = mask.influenceLayers; @@ -65,15 +76,13 @@ export class SpriteMaskManager { if (influenceLayers & addLayer) { const maskRenderElement = mask._maskElement; - (maskRenderElement.data).isAdd = true; - this._batcher.drawElement(maskRenderElement, camera); + this._batcher.drawElement(maskRenderElement, camera, StencilOperation.IncrementSaturate); continue; } if (influenceLayers & reduceLayer) { const maskRenderElement = mask._maskElement; - (maskRenderElement.data).isAdd = false; - this._batcher.drawElement(maskRenderElement, camera); + this._batcher.drawElement(maskRenderElement, camera, StencilOperation.DecrementSaturate); } } } diff --git a/packages/core/src/RenderPipeline/SpriteMaskRenderData.ts b/packages/core/src/RenderPipeline/SpriteMaskRenderData.ts deleted file mode 100644 index d07d62cef6..0000000000 --- a/packages/core/src/RenderPipeline/SpriteMaskRenderData.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { VertexData2D } from "../2d/data/VertexData2D"; -import { Material } from "../material/Material"; -import { Renderer } from "../Renderer"; -import { IPoolElement } from "./IPoolElement"; -import { RenderData } from "./RenderData"; - -export class SpriteMaskRenderData extends RenderData implements IPoolElement { - isAdd: boolean = true; - verticesData: VertexData2D; - - constructor() { - super(); - this.multiRenderData = false; - } - - set(component: Renderer, material: Material, verticesData: VertexData2D): void { - this.component = component; - this.material = material; - this.verticesData = verticesData; - } - - dispose(): void { - this.component = this.material = this.verticesData = null; - } -} diff --git a/packages/core/src/RenderPipeline/SpriteRenderData.ts b/packages/core/src/RenderPipeline/SpriteRenderData.ts index 2cd8984bb3..9f3de48440 100644 --- a/packages/core/src/RenderPipeline/SpriteRenderData.ts +++ b/packages/core/src/RenderPipeline/SpriteRenderData.ts @@ -2,17 +2,17 @@ import { VertexData2D } from "../2d/data/VertexData2D"; import { Material } from "../material/Material"; import { Renderer } from "../Renderer"; import { Texture2D } from "../texture"; +import { RenderDataUsage } from "./enums/RenderDataUsage"; import { IPoolElement } from "./IPoolElement"; import { RenderData } from "./RenderData"; export class SpriteRenderData extends RenderData implements IPoolElement { verticesData: VertexData2D; texture: Texture2D; - dataIndex: number; // Add for CanvasRenderer plugin. constructor() { super(); - this.multiRenderData = false; + this.usage = RenderDataUsage.Sprite; } set( @@ -20,14 +20,11 @@ export class SpriteRenderData extends RenderData implements IPoolElement { material: Material, verticesData: VertexData2D, texture: Texture2D, - dataIndex: number = 0 ): void { this.component = component; this.material = material; - this.verticesData = verticesData; this.texture = texture; - this.dataIndex = dataIndex; } dispose(): void { diff --git a/packages/core/src/RenderPipeline/TextRenderData.ts b/packages/core/src/RenderPipeline/TextRenderData.ts deleted file mode 100644 index c02fcfec2f..0000000000 --- a/packages/core/src/RenderPipeline/TextRenderData.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { IPoolElement } from "./IPoolElement"; -import { RenderData } from "./RenderData"; -import { SpriteRenderData } from "./SpriteRenderData"; - -export class TextRenderData extends RenderData implements IPoolElement { - charsData: SpriteRenderData[] = []; - - constructor() { - super(); - this.multiRenderData = true; - } - - dispose(): void { - this.component = this.material = null; - this.charsData.length = 0; - } -} diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts new file mode 100644 index 0000000000..2c9987efd3 --- /dev/null +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -0,0 +1,279 @@ +import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; +import { Engine } from "../../Engine"; +import { + Buffer, + BufferBindFlag, + BufferUsage, + IndexFormat, + MeshTopology, + SubMesh, + VertexElement, + VertexElementFormat +} from "../../graphic"; +import { BufferMesh } from "../../mesh"; +import { ShaderProperty, ShaderTagKey } from "../../shader"; +import { ClassPool } from "../ClassPool"; +import { RenderContext } from "../RenderContext"; +import { SpriteRenderData } from "../SpriteRenderData"; +import { RenderDataUsage } from "../enums/RenderDataUsage"; +import { IBatcher } from "./IBatcher"; + +/** + * @internal + */ +export class Batcher2D implements IBatcher { + /** The maximum number of vertex. */ + static MAX_VERTEX_COUNT: number = 4096; + + protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); + private static _textureProperty: ShaderProperty = ShaderProperty.getByName("renderer_SpriteTexture"); + + /** @internal */ + _engine: Engine; + /** @internal */ + _meshes: BufferMesh[] = []; + /** @internal */ + _meshCount: number = 1; + /** @internal */ + _subMeshPool: ClassPool = new ClassPool(SubMesh); + /** @internal */ + _vertexBuffers: Buffer[] = []; + /** @internal */ + _indiceBuffers: Buffer[] = []; + /** @internal */ + _vertices: Float32Array; + /** @internal */ + _indices: Uint16Array; + /** @internal */ + _flushId: number = 0; + /** @internal */ + _vStartIndex: number = 0; + /** @internal */ + _vIndex: number = 0; + /** @internal */ + _iStartIndex: number = 0; + /** @internal */ + _iIndex: number = 0; + /** @internal */ + _vertexStartIndex: number = 0; + /** @internal */ + _vertexCount: number = 0; + /** @internal */ + _preContext: RenderContext = null; + /** @internal */ + _preSpriteRenderData: SpriteRenderData = null; + + constructor(engine: Engine) { + this._engine = engine; + this._initMeshes(engine); + } + + /** + * Destroy internal resources. + */ + destroy(): void { + const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; + + for (let i = 0, n = meshes.length; i < n; ++i) { + meshes[i].destroy(); + } + this._meshes = null; + + for (let i = 0, n = vertexBuffers.length; i < n; ++i) { + vertexBuffers[i].destroy(); + } + this._vertexBuffers = null; + + for (let i = 0, n = indiceBuffers.length; i < n; ++i) { + indiceBuffers[i].destroy(); + } + this._indiceBuffers = null; + } + + commitRenderData(context: RenderContext, data: SpriteRenderData): void { + if (this._preSpriteRenderData) { + if (this._vertexCount + data.verticesData.vertexCount > Batcher2D.MAX_VERTEX_COUNT) { + this.flush(); + this.uploadBuffer(); + const newFlushId = this._flushId + 1; + this._createMesh(this._engine, newFlushId); + this._reset(); + this._flushId = newFlushId; + } else { + if (!this._canBatch(this._preSpriteRenderData, data)) { + this.flush(); + } + } + } + + this._preContext = context; + this._preSpriteRenderData = data; + this._fillRenderData(data); + } + + flush(): void { + if (!this._preSpriteRenderData) { + return; + } + + const { _preSpriteRenderData, _iStartIndex, _iIndex } = this; + const mesh = this._meshes[this._flushId]; + const iCount = _iIndex - _iStartIndex; + const subMesh = this._getSubMeshFromPool(_iStartIndex, iCount); + mesh.addSubMesh(subMesh); + + this._vertexStartIndex += this._vertexCount; + this._vStartIndex = this._vIndex; + this._iStartIndex = _iIndex; + + const renderData = this._engine._meshRenderDataPool.getFromPool(); + renderData.usage = RenderDataUsage.Sprite; + renderData.set(_preSpriteRenderData.component, _preSpriteRenderData.material, mesh, subMesh); + renderData.component.shaderData.setTexture(Batcher2D._textureProperty, _preSpriteRenderData.texture); + this._preContext.camera._renderPipeline.pushRenderData(this._preContext, renderData); + } + + uploadBuffer(): void { + const { _flushId } = this; + this._vertexBuffers[_flushId].setData(this._vertices, 0, 0, this._vStartIndex); + this._indiceBuffers[_flushId].setData(this._indices, 0, 0, this._iStartIndex); + } + + clear() { + this._reset(); + this._subMeshPool.resetPool(); + const { _meshes, _meshCount } = this; + for (let i = 0; i < _meshCount; ++i) { + _meshes[i].clearSubMesh(); + } + } + + createVertexElements(vertexElements: VertexElement[]): number { + vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); + vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); + vertexElements[2] = new VertexElement("COLOR_0", 20, VertexElementFormat.Vector4, 0); + return 36; + } + + private _canBatch(preRenderData: SpriteRenderData, curRenderData: SpriteRenderData): boolean { + const preRender = preRenderData.component; + const curRender = curRenderData.component; + + // Compare mask. + if (!this._checkBatchWithMask(preRender, curRender)) { + return false; + } + + // Compare texture. + if (preRenderData.texture !== curRenderData.texture) { + return false; + } + + // Compare material. + return preRenderData.material === curRenderData.material; + } + + private _checkBatchWithMask(left: SpriteRenderer, right: SpriteRenderer): boolean { + const leftMaskInteraction = left.maskInteraction; + + if (leftMaskInteraction !== right.maskInteraction) { + return false; + } + if (leftMaskInteraction === SpriteMaskInteraction.None) { + return true; + } + return left.maskLayer === right.maskLayer; + } + + private _fillRenderData(data: SpriteRenderData): void { + const { _vertices, _indices, _vertexCount } = this; + const { positions, uvs, color, vertexCount, triangles } = data.verticesData; + + let index = this._vIndex; + for (let i = 0; i < vertexCount; ++i) { + const curPos = positions[i]; + const curUV = uvs[i]; + _vertices[index++] = curPos.x; + _vertices[index++] = curPos.y; + _vertices[index++] = curPos.z; + _vertices[index++] = curUV.x; + _vertices[index++] = curUV.y; + _vertices[index++] = color.r; + _vertices[index++] = color.g; + _vertices[index++] = color.b; + _vertices[index++] = color.a; + } + this._vIndex = index; + + index = this._iIndex; + for (let i = 0, len = triangles.length; i < len; ++i) { + _indices[index++] = triangles[i] + _vertexCount; + } + this._iIndex = index; + this._vertexCount += vertexCount; + } + + private _reset(): void { + this._flushId = 0; + this._vIndex = 0; + this._iIndex = 0; + this._vStartIndex = 0; + this._iStartIndex = 0; + this._vertexStartIndex = 0; + this._vertexCount = 0; + this._preContext = null; + this._preSpriteRenderData = null; + } + + private _initMeshes(engine: Engine) { + const { MAX_VERTEX_COUNT } = Batcher2D; + this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); + this._indices = new Uint16Array(MAX_VERTEX_COUNT * 4); + this._createMesh(engine, 0); + } + + private _createMesh(engine: Engine, index: number): BufferMesh { + const { _meshes } = this; + if (_meshes[index]) { + return _meshes[index]; + } + + const { MAX_VERTEX_COUNT } = Batcher2D; + const mesh = new BufferMesh(engine, `BufferMesh${index}`); + mesh.isGCIgnored = true; + const vertexElements: VertexElement[] = []; + const vertexStride = this.createVertexElements(vertexElements); + + // vertices + const vertexBuffer = (this._vertexBuffers[index] = new Buffer( + engine, + BufferBindFlag.VertexBuffer, + MAX_VERTEX_COUNT * vertexStride, + BufferUsage.Dynamic + )); + vertexBuffer.isGCIgnored = true; + // indices + const indiceBuffer = (this._indiceBuffers[index] = new Buffer( + engine, + BufferBindFlag.IndexBuffer, + MAX_VERTEX_COUNT * 8, + BufferUsage.Dynamic + )); + indiceBuffer.isGCIgnored = true; + mesh.setVertexBufferBinding(vertexBuffer, vertexStride); + mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); + mesh.setVertexElements(vertexElements); + index >= this._meshCount && (this._meshCount = index + 1); + this._meshes[index] = mesh; + + return mesh; + } + + private _getSubMeshFromPool(start: number, count: number): SubMesh { + const subMesh = this._subMeshPool.getFromPool(); + subMesh.start = start; + subMesh.count = count; + subMesh.topology = MeshTopology.Triangles; + return subMesh; + } +} diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts new file mode 100644 index 0000000000..f31d9614bd --- /dev/null +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -0,0 +1,58 @@ +import { Engine } from "../../Engine"; +import { RenderContext } from "../RenderContext"; +import { RenderData } from "../RenderData"; +import { SpriteRenderData } from "../SpriteRenderData"; +import { RenderDataUsage } from "../enums/RenderDataUsage"; +import { Batcher2D } from "./Batcher2D"; + +export class BatcherManager { + /** @internal */ + _engine: Engine; + /** @internal */ + _batcher2D: Batcher2D; + + constructor(engine: Engine) { + this._engine = engine; + this._batcher2D = new Batcher2D(engine); + } + + destroy() { + this._batcher2D.destroy(); + } + + commitRenderData(context: RenderContext, data: RenderData | Array): void { + if (!data) return; + + if (data instanceof Array) { + for (let i = 0, l = data.length; i < l; ++i) { + this._handleRenderData(context, data[i]); + } + } else { + this._handleRenderData(context, data); + } + } + + flush(): void { + this._batcher2D.flush(); + } + + uploadBuffer(): void { + this._batcher2D.uploadBuffer(); + } + + clear() { + this._batcher2D.clear(); + } + + private _handleRenderData(context: RenderContext, data: RenderData): void { + switch (data.usage) { + case RenderDataUsage.Mesh: + this._batcher2D.flush(); + context.camera._renderPipeline.pushRenderData(context, data); + break; + case RenderDataUsage.Sprite: + this._batcher2D.commitRenderData(context, data); + break; + } + } +} diff --git a/packages/core/src/RenderPipeline/batcher/IBatcher.ts b/packages/core/src/RenderPipeline/batcher/IBatcher.ts new file mode 100644 index 0000000000..b46e10136e --- /dev/null +++ b/packages/core/src/RenderPipeline/batcher/IBatcher.ts @@ -0,0 +1,9 @@ +import { RenderContext } from "../RenderContext"; +import { RenderData } from "../RenderData"; + +export interface IBatcher { + commitRenderData(context: RenderContext, data: RenderData): void; + flush(): void; + uploadBuffer(): void; + clear(): void; +} diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts new file mode 100644 index 0000000000..ad7bfac9ca --- /dev/null +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -0,0 +1,325 @@ +import { SpriteMask } from "../../2d/sprite/SpriteMask"; +import { Camera } from "../../Camera"; +import { Engine } from "../../Engine"; +import { Buffer, BufferBindFlag, BufferUsage, IndexFormat, MeshTopology, SubMesh, VertexElement } from "../../graphic"; +import { VertexElementFormat } from "../../graphic/enums/VertexElementFormat"; +import { BufferMesh } from "../../mesh"; +import { ShaderTagKey } from "../../shader"; +import { StencilOperation } from "../../shader/enums/StencilOperation"; +import { Shader } from "../../shader/Shader"; +import { ShaderMacroCollection } from "../../shader/ShaderMacroCollection"; +import { ClassPool } from "../ClassPool"; +import { RenderElement } from "../RenderElement"; +import { SpriteRenderData } from "../SpriteRenderData"; + +export class SpriteMaskBatcher { + protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); + + /** The maximum number of vertex. */ + static MAX_VERTEX_COUNT: number = 4096; + static _canUploadSameBuffer: boolean = true; + + /** @internal */ + _engine: Engine; + /** @internal */ + _subMeshPool: ClassPool = new ClassPool(SubMesh); + /** @internal */ + _batchedQueue: RenderElement[] = []; + /** @internal */ + _stencilOps: StencilOperation[] = []; + /** @internal */ + _meshes: BufferMesh[] = []; + /** @internal */ + _meshCount: number = 1; + /** @internal */ + _vertexBuffers: Buffer[] = []; + /** @internal */ + _indiceBuffers: Buffer[] = []; + /** @internal */ + _vertices: Float32Array; + /** @internal */ + _indices: Uint16Array; + /** @internal */ + _flushId: number = 0; + /** @internal */ + _vertexCount: number = 0; + /** @internal */ + _elementCount: number = 0; + + constructor(engine: Engine) { + this._engine = engine; + this._initMeshes(engine); + } + + createVertexElements(vertexElements: VertexElement[]): number { + vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); + vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); + return 20; + } + + drawElement(element: RenderElement, camera: Camera, op: StencilOperation): void { + const vertexCount = (element.data).verticesData.vertexCount; + if (this._vertexCount + vertexCount > SpriteMaskBatcher.MAX_VERTEX_COUNT) { + this.flush(camera); + } + + this._vertexCount += vertexCount; + this._batchedQueue[this._elementCount] = element; + this._stencilOps[this._elementCount++] = op; + } + + flush(camera: Camera): void { + const batchedQueue = this._batchedQueue; + + if (batchedQueue.length === 0) { + return; + } + this._updateData(this._engine); + this.drawBatches(camera); + + if (!SpriteMaskBatcher._canUploadSameBuffer) { + this._flushId++; + } + + batchedQueue.length = 0; + this._subMeshPool.resetPool(); + this._vertexCount = 0; + this._elementCount = 0; + } + + clear(): void { + this._flushId = 0; + this._vertexCount = 0; + this._elementCount = 0; + this._batchedQueue.length = 0; + this._stencilOps.length = 0; + } + + destroy(): void { + this._batchedQueue = null; + this._stencilOps = null; + + const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; + + for (let i = 0, n = meshes.length; i < n; ++i) { + meshes[i].destroy(); + } + this._meshes = null; + + for (let i = 0, n = vertexBuffers.length; i < n; ++i) { + vertexBuffers[i].destroy(); + } + this._vertexBuffers = null; + + for (let i = 0, n = indiceBuffers.length; i < n; ++i) { + indiceBuffers[i].destroy(); + } + this._indiceBuffers = null; + } + + canBatch( + preElement: RenderElement, + curElement: RenderElement, + preStencilOp: StencilOperation, + curStencilOp: StencilOperation + ): boolean { + const preSpriteData = preElement.data; + const curSpriteData = curElement.data; + + if (preStencilOp !== curStencilOp) { + return false; + } + + // Compare renderer property + const preShaderData = (preSpriteData.component).shaderData; + const curShaderData = (curSpriteData.component).shaderData; + const textureProperty = SpriteMask._textureProperty; + const alphaCutoffProperty = SpriteMask._alphaCutoffProperty; + + return ( + preShaderData.getTexture(textureProperty) === curShaderData.getTexture(textureProperty) && + preShaderData.getTexture(alphaCutoffProperty) === curShaderData.getTexture(alphaCutoffProperty) + ); + } + + updateVertices(element: SpriteRenderData, vertices: Float32Array, vertexIndex: number): number { + const { positions, uvs, vertexCount } = element.verticesData; + for (let i = 0; i < vertexCount; i++) { + const curPos = positions[i]; + const curUV = uvs[i]; + vertices[vertexIndex++] = curPos.x; + vertices[vertexIndex++] = curPos.y; + vertices[vertexIndex++] = curPos.z; + vertices[vertexIndex++] = curUV.x; + vertices[vertexIndex++] = curUV.y; + } + + return vertexIndex; + } + + drawBatches(camera: Camera): void { + const { _engine: engine, _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; + const mesh = this._meshes[this._flushId]; + const subMeshes = mesh.subMeshes; + const sceneData = camera.scene.shaderData; + const cameraData = camera.shaderData; + + for (let i = 0, len = subMeshes.length; i < len; i++) { + const subMesh = subMeshes[i]; + const spriteMaskElement = batchedQueue[i]; + const stencilOp = stencilOps[i]; + const renderData = spriteMaskElement.data; + + if (!subMesh || !spriteMaskElement) { + return; + } + + const renderer = renderData.component; + const material = renderData.material; + + const compileMacros = Shader._compileMacros; + // union render global macro and material self macro. + ShaderMacroCollection.unionCollection( + renderer._globalShaderMacro, + material.shaderData._macroCollection, + compileMacros + ); + + // Update stencil state + const stencilState = material.renderState.stencilState; + stencilState.passOperationFront = stencilOp; + stencilState.passOperationBack = stencilOp; + + const pass = material.shader.subShaders[0].passes[0]; + const program = pass._getShaderProgram(engine, compileMacros); + if (!program.isValid) { + return; + } + + program.bind(); + program.groupingOtherUniformBlock(); + program.uploadAll(program.sceneUniformBlock, sceneData); + program.uploadAll(program.cameraUniformBlock, cameraData); + program.uploadAll(program.rendererUniformBlock, renderer.shaderData); + program.uploadAll(program.materialUniformBlock, material.shaderData); + + material.renderState._apply(engine, false, pass._renderStateDataMap, material.shaderData); + + engine._hardwareRenderer.drawPrimitive(mesh, subMesh, program); + } + } + + /** + * @internal + * Standalone for canvas 2d renderer plugin. + */ + _initMeshes(engine: Engine) { + const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; + this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); + this._indices = new Uint16Array(MAX_VERTEX_COUNT * 3); + + const { _meshes, _meshCount } = this; + for (let i = 0; i < _meshCount; i++) { + _meshes[i] = this._createMesh(engine, i); + } + } + + private _createMesh(engine: Engine, index: number): BufferMesh { + const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; + const mesh = new BufferMesh(engine, `BufferMesh${index}`); + mesh.isGCIgnored = true; + const vertexElements: VertexElement[] = []; + const vertexStride = this.createVertexElements(vertexElements); + + // vertices + const vertexBuffer = (this._vertexBuffers[index] = new Buffer( + engine, + BufferBindFlag.VertexBuffer, + MAX_VERTEX_COUNT * vertexStride, + BufferUsage.Dynamic + )); + vertexBuffer.isGCIgnored = true; + // indices + const indiceBuffer = (this._indiceBuffers[index] = new Buffer( + engine, + BufferBindFlag.IndexBuffer, + MAX_VERTEX_COUNT * 6, + BufferUsage.Dynamic + )); + indiceBuffer.isGCIgnored = true; + mesh.setVertexBufferBinding(vertexBuffer, vertexStride); + mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); + mesh.setVertexElements(vertexElements); + + return mesh; + } + + private _updateData(engine: Engine): void { + const { _meshes, _flushId } = this; + + if (!SpriteMaskBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { + this._meshCount++; + _meshes[_flushId] = this._createMesh(engine, _flushId); + } + + const { _batchedQueue: batchedQueue, _stencilOps: stencilOps, _vertices: vertices, _indices: indices } = this; + const mesh = _meshes[_flushId]; + mesh.clearSubMesh(); + + let vertexIndex = 0; + let indiceIndex = 0; + let vertexStartIndex = 0; + let vertexCount = 0; + let curIndiceStartIndex = 0; + let curMeshIndex = 0; + let preElement: RenderElement = null; + let preStencilOp: StencilOperation = null; + for (let i = 0, len = batchedQueue.length; i < len; i++) { + const curElement = batchedQueue[i]; + const curStencilOp = stencilOps[i]; + const curData = curElement.data; + + // Batch vertex + vertexIndex = this.updateVertices(curData, vertices, vertexIndex); + + // Batch indice + const { triangles } = curData.verticesData; + const triangleNum = triangles.length; + for (let j = 0; j < triangleNum; j++) { + indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; + } + + curIndiceStartIndex += curData.verticesData.vertexCount; + + if (preElement === null) { + vertexCount += triangleNum; + } else { + if (this.canBatch(preElement, curElement, preStencilOp, curStencilOp)) { + vertexCount += triangleNum; + } else { + mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); + vertexStartIndex += vertexCount; + vertexCount = triangleNum; + batchedQueue[curMeshIndex++] = preElement; + } + } + + preElement = curElement; + preStencilOp = curStencilOp; + } + + mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); + batchedQueue[curMeshIndex] = preElement; + + this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex); + this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex); + } + + private _getSubMeshFromPool(start: number, count: number): SubMesh { + const subMesh = this._subMeshPool.getFromPool(); + subMesh.start = start; + subMesh.count = count; + subMesh.topology = MeshTopology.Triangles; + return subMesh; + } +} diff --git a/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts b/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts new file mode 100644 index 0000000000..961b9c383f --- /dev/null +++ b/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts @@ -0,0 +1,11 @@ +/** + * RenderData usage. + */ +export enum RenderDataUsage { + /** Usage for mesh. */ + Mesh, + /** Usage for sprite. */ + Sprite, + /** Usage for sprite mask. */ + SpriteMask +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 35f051cbc8..6b1fdcbf4b 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -57,5 +57,4 @@ export * from "./physics/index"; export * from "./Utils"; // Export for CanvasRenderer plugin. -export { Basic2DBatcher } from "./RenderPipeline/Basic2DBatcher"; export { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index de2ab5363f..f0561f311e 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -6,6 +6,7 @@ import { Logger } from "../base/Logger"; import { ignoreClone } from "../clone/CloneManager"; import { Mesh, MeshModifyFlags } from "../graphic/Mesh"; import { ShaderMacro } from "../shader/ShaderMacro"; +import { RenderDataUsage } from "../RenderPipeline/enums/RenderDataUsage"; /** * MeshRenderer Component. @@ -144,14 +145,15 @@ export class MeshRenderer extends Renderer { const materials = this._materials; const subMeshes = mesh.subMeshes; - const renderPipeline = context.camera._renderPipeline; + const batcherManager = context.camera._batcherManager; const meshRenderDataPool = this._engine._meshRenderDataPool; for (let i = 0, n = subMeshes.length; i < n; i++) { const material = materials[i]; if (!material) continue; const renderData = meshRenderDataPool.getFromPool(); + renderData.usage = RenderDataUsage.Mesh; renderData.set(this, material, mesh, subMeshes[i]); - renderPipeline.pushRenderData(context, renderData); + batcherManager.commitRenderData(context, renderData); } } diff --git a/tests/src/core/SpriteMask.test.ts b/tests/src/core/SpriteMask.test.ts index b0e0fa9c59..0d5b8a9de6 100644 --- a/tests/src/core/SpriteMask.test.ts +++ b/tests/src/core/SpriteMask.test.ts @@ -174,7 +174,7 @@ describe("SpriteMask", async () => { const rootEntity = scene.getRootEntity(); const spriteMask = rootEntity.addComponent(SpriteMask); const texture2d = new Texture2D(engine, 100, 200); - const context = { camera: { _renderPipeline: { _allSpriteMasks: { add: () => {} } } } }; + const context = { camera: { _renderPipeline: { _spriteMaskManager: { addMask: () => {} } } } }; // @ts-ignore spriteMask._render(context); // @ts-ignore From a44de9ead6a4693a565a09f66572a8068f02643a Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 22 Aug 2023 11:53:54 +0800 Subject: [PATCH 002/218] refactor(renderpipeline): opt code --- .../core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index ad7bfac9ca..5589de5485 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -82,6 +82,7 @@ export class SpriteMaskBatcher { } batchedQueue.length = 0; + this._stencilOps.length = 0; this._subMeshPool.resetPool(); this._vertexCount = 0; this._elementCount = 0; @@ -215,8 +216,8 @@ export class SpriteMaskBatcher { */ _initMeshes(engine: Engine) { const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 3); + this._vertices = new Float32Array(MAX_VERTEX_COUNT * 5); + this._indices = new Uint16Array(MAX_VERTEX_COUNT * 1.5); const { _meshes, _meshCount } = this; for (let i = 0; i < _meshCount; i++) { @@ -243,7 +244,7 @@ export class SpriteMaskBatcher { const indiceBuffer = (this._indiceBuffers[index] = new Buffer( engine, BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 6, + MAX_VERTEX_COUNT * 3, BufferUsage.Dynamic )); indiceBuffer.isGCIgnored = true; From 06c8e53eba69e69ca3519a00aa9d7386b2a52fa4 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 22 Aug 2023 15:07:56 +0800 Subject: [PATCH 003/218] refactor(renderpipeline): opt code --- packages/core/src/RenderPipeline/BasicRenderPipeline.ts | 4 +--- packages/core/src/RenderPipeline/CullingResults.ts | 9 ++++----- packages/core/src/RenderPipeline/RenderQueue.ts | 8 ++------ 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index d64d7811f9..5e40dce305 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -1,8 +1,6 @@ import { Vector2 } from "@galacean/engine-math"; -import { SpriteMask } from "../2d"; import { Background } from "../Background"; import { Camera } from "../Camera"; -import { DisorderedArray } from "../DisorderedArray"; import { Engine } from "../Engine"; import { Layer } from "../Layer"; import { BackgroundMode } from "../enums/BackgroundMode"; @@ -49,7 +47,7 @@ export class BasicRenderPipeline { constructor(camera: Camera) { this._camera = camera; const { engine } = camera; - this._cullingResults = new CullingResults(engine); + this._cullingResults = new CullingResults(); this._cascadedShadowCaster = new CascadedShadowCasterPass(camera); this._depthOnlyPass = new DepthOnlyPass(engine); this._spriteMaskManager = new SpriteMaskManager(camera.engine); diff --git a/packages/core/src/RenderPipeline/CullingResults.ts b/packages/core/src/RenderPipeline/CullingResults.ts index c439242910..dd34a24a56 100644 --- a/packages/core/src/RenderPipeline/CullingResults.ts +++ b/packages/core/src/RenderPipeline/CullingResults.ts @@ -1,4 +1,3 @@ -import { Engine } from "../Engine"; import { RenderQueue } from "./RenderQueue"; /** @@ -10,10 +9,10 @@ export class CullingResults { readonly transparentQueue: RenderQueue; readonly alphaTestQueue: RenderQueue; - constructor(engine: Engine) { - this.opaqueQueue = new RenderQueue(engine); - this.transparentQueue = new RenderQueue(engine); - this.alphaTestQueue = new RenderQueue(engine); + constructor() { + this.opaqueQueue = new RenderQueue(); + this.transparentQueue = new RenderQueue(); + this.alphaTestQueue = new RenderQueue(); } reset(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 1068ffa120..9f418ceaf9 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -69,9 +69,7 @@ export class RenderQueue { const isSprite = data.usage === RenderDataUsage.Sprite; const meshData = data; const renderer = meshData.component; - if (isSprite) { - _spriteMaskManager.preRender(camera, renderer); - } + isSprite && _spriteMaskManager.preRender(camera, renderer); const compileMacros = Shader._compileMacros; const material = meshData.material.destroyed ? engine._magentaMaterial : meshData.material; @@ -152,9 +150,7 @@ export class RenderQueue { ); rhi.drawPrimitive(meshData.mesh, meshData.subMesh, program); - if (isSprite) { - _spriteMaskManager.postRender(renderer); - } + isSprite && _spriteMaskManager.postRender(renderer); } } } From 60b240aaeebb135c875696e39bf1f608291ed6c6 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 29 Aug 2023 09:53:08 +0800 Subject: [PATCH 004/218] refactor(renderpipeline): opt code --- packages/core/src/RenderPipeline/BasicRenderPipeline.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 5e40dce305..f4e3fd283c 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -29,7 +29,6 @@ import { SpriteMaskManager } from "./SpriteMaskManager"; export class BasicRenderPipeline { /** @internal */ _cullingResults: CullingResults; - /** @internal */ _spriteMaskManager: SpriteMaskManager; @@ -50,7 +49,7 @@ export class BasicRenderPipeline { this._cullingResults = new CullingResults(); this._cascadedShadowCaster = new CascadedShadowCasterPass(camera); this._depthOnlyPass = new DepthOnlyPass(engine); - this._spriteMaskManager = new SpriteMaskManager(camera.engine); + this._spriteMaskManager = new SpriteMaskManager(engine); this._renderPassArray = []; this._defaultPass = new RenderPass("default", 0, null, null, 0); From 563bfbecf125462e99d50d2409e50f4a83669519 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 29 Aug 2023 11:15:00 +0800 Subject: [PATCH 005/218] refactor(renderpipeline): opt code --- packages/core/src/2d/sprite/SpriteMask.ts | 8 ++++---- packages/core/src/2d/sprite/SpriteRenderer.ts | 5 +++-- packages/core/src/2d/text/TextRenderer.ts | 13 ++++++++----- packages/core/src/Camera.ts | 7 ------- packages/core/src/Engine.ts | 10 ++++++++++ .../core/src/RenderPipeline/BasicRenderPipeline.ts | 9 ++------- packages/core/src/RenderPipeline/RenderQueue.ts | 6 +++--- .../src/RenderPipeline/batcher/BatcherManager.ts | 2 -- packages/core/src/mesh/MeshRenderer.ts | 2 +- tests/src/core/SpriteMask.test.ts | 2 +- 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index bc83d5d7de..529956438a 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -216,14 +216,14 @@ export class SpriteMask extends Renderer { this._dirtyUpdateFlag &= ~SpriteMaskUpdateFlags.UV; } - context.camera._renderPipeline._spriteMaskManager.addMask(this); - - const renderData = this._engine._spriteRenderDataPool.getFromPool(); + const { engine } = context.camera; + engine.spriteMaskManager.addMask(this); + const renderData = engine._spriteRenderDataPool.getFromPool(); const material = this.getMaterial(); renderData.set(this, material, this._verticesData, this.sprite.texture); renderData.usage = RenderDataUsage.SpriteMask; - const renderElement = this._engine._renderElementPool.getFromPool(); + const renderElement = engine._renderElementPool.getFromPool(); renderElement.set(renderData, material.shader.subShaders[0].passes); this._maskElement = renderElement; } diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 4ff93581ff..2d7286eeed 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -322,11 +322,12 @@ export class SpriteRenderer extends Renderer { } // Push primitive + const { engine } = context.camera; const material = this.getMaterial(); - const renderData = this._engine._spriteRenderDataPool.getFromPool(); + const renderData = engine._spriteRenderDataPool.getFromPool(); renderData.set(this, material, this._verticesData, this.sprite.texture); renderData.usage = RenderDataUsage.Sprite; - context.camera._batcherManager.commitRenderData(context, renderData); + engine.batcherManager.commitRenderData(context, renderData); } /** diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index ad46778b57..3f89fcf9cf 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -17,6 +17,7 @@ import { Font } from "./Font"; import { SubFont } from "./SubFont"; import { TextUtils } from "./TextUtils"; import { SpriteRenderData } from "../../RenderPipeline/SpriteRenderData"; +import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; /** * Renders a text for 2D graphics. @@ -387,7 +388,8 @@ export class TextRenderer extends Renderer { this._setDirtyFlagFalse(DirtyFlag.WorldPosition); } - const spriteRenderDataPool = this._engine._spriteRenderDataPool; + const { engine } = context.camera; + const spriteRenderDataPool = engine._spriteRenderDataPool; const material = this.getMaterial(); const charRenderDatas = this._charRenderDatas; const charCount = charRenderDatas.length; @@ -395,11 +397,12 @@ export class TextRenderer extends Renderer { let spriteRenderDatas: Array = []; for (let i = 0; i < charCount; ++i) { const charRenderData = charRenderDatas[i]; - const spriteRenderData = spriteRenderDataPool.getFromPool(); - spriteRenderData.set(this, material, charRenderData.renderData, charRenderData.texture); - spriteRenderDatas.push(spriteRenderData); + const renderData = spriteRenderDataPool.getFromPool(); + renderData.set(this, material, charRenderData.renderData, charRenderData.texture); + renderData.usage = RenderDataUsage.Sprite; + spriteRenderDatas.push(renderData); } - context.camera._batcherManager.commitRenderData(context, spriteRenderDatas); + engine.batcherManager.commitRenderData(context, spriteRenderDatas); } private _updateStencilState(): void { diff --git a/packages/core/src/Camera.ts b/packages/core/src/Camera.ts index 251169d838..d087f3ef8f 100644 --- a/packages/core/src/Camera.ts +++ b/packages/core/src/Camera.ts @@ -19,7 +19,6 @@ import { ShaderTagKey } from "./shader/ShaderTagKey"; import { ShaderDataGroup } from "./shader/enums/ShaderDataGroup"; import { RenderTarget } from "./texture/RenderTarget"; import { TextureCubeFace } from "./texture/enums/TextureCubeFace"; -import { BatcherManager } from "./RenderPipeline/batcher/BatcherManager"; class MathTemp { static tempVec4 = new Vector4(); @@ -71,9 +70,6 @@ export class Camera extends Component { _renderPipeline: BasicRenderPipeline; /** @internal */ @ignoreClone - _batcherManager: BatcherManager; - /** @internal */ - @ignoreClone _virtualCamera: VirtualCamera = new VirtualCamera(); /** @internal */ _replacementShader: Shader = null; @@ -333,7 +329,6 @@ export class Camera extends Component { this._isInvViewProjDirty = transform.registerWorldChangeFlag(); this._frustumViewChangeFlag = transform.registerWorldChangeFlag(); this._renderPipeline = new BasicRenderPipeline(this); - this._batcherManager = new BatcherManager(this.engine); this.shaderData._addReferCount(1); this._updatePixelViewport(); } @@ -585,7 +580,6 @@ export class Camera extends Component { protected override _onDestroy(): void { super._onDestroy(); this._renderPipeline?.destroy(); - this._batcherManager?.destroy(); this._isInvViewProjDirty.destroy(); this._isViewMatrixDirty.destroy(); this.shaderData._addReferCount(-1); @@ -594,7 +588,6 @@ export class Camera extends Component { this._globalShaderMacro = null; this._frustum = null; this._renderPipeline = null; - this._batcherManager = null; this._virtualCamera = null; this._shaderData = null; this._frustumViewChangeFlag = null; diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 2629584318..7bde33c2ad 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -35,6 +35,8 @@ import { CullMode } from "./shader/enums/CullMode"; import { RenderQueueType } from "./shader/enums/RenderQueueType"; import { RenderState } from "./shader/state/RenderState"; import { Texture2D, Texture2DArray, TextureCube, TextureCubeFace, TextureFormat } from "./texture"; +import { BatcherManager } from "./RenderPipeline/batcher/BatcherManager"; +import { SpriteMaskManager } from "./RenderPipeline/SpriteMaskManager"; ShaderPool.init(); @@ -51,6 +53,10 @@ export class Engine extends EventDispatcher { /** Input manager of Engine. */ readonly inputManager: InputManager; + /** batcher manager of Engine. */ + readonly batcherManager: BatcherManager; + /** sprite mask manager of Engine. */ + readonly spriteMaskManager: SpriteMaskManager; /** @internal */ _physicsInitialized: boolean = false; @@ -228,6 +234,8 @@ export class Engine extends EventDispatcher { this._textDefaultFont.isGCIgnored = true; this.inputManager = new InputManager(this); + this.batcherManager = new BatcherManager(this); + this.spriteMaskManager = new SpriteMaskManager(this); this._initMagentaTextures(hardwareRenderer); @@ -404,6 +412,8 @@ export class Engine extends EventDispatcher { this._fontMap = null; this.inputManager._destroy(); + this.batcherManager.destroy(); + this.spriteMaskManager.destroy(); this.dispatch("shutdown", this); // Cancel animation diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index f4e3fd283c..dcbdf3f6ce 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -21,7 +21,6 @@ import { RenderContext } from "./RenderContext"; import { RenderData } from "./RenderData"; import { RenderPass } from "./RenderPass"; import { PipelineStage } from "./enums/PipelineStage"; -import { SpriteMaskManager } from "./SpriteMaskManager"; /** * Basic render pipeline. @@ -29,8 +28,6 @@ import { SpriteMaskManager } from "./SpriteMaskManager"; export class BasicRenderPipeline { /** @internal */ _cullingResults: CullingResults; - /** @internal */ - _spriteMaskManager: SpriteMaskManager; private _camera: Camera; private _defaultPass: RenderPass; @@ -49,7 +46,6 @@ export class BasicRenderPipeline { this._cullingResults = new CullingResults(); this._cascadedShadowCaster = new CascadedShadowCasterPass(camera); this._depthOnlyPass = new DepthOnlyPass(engine); - this._spriteMaskManager = new SpriteMaskManager(engine); this._renderPassArray = []; this._defaultPass = new RenderPass("default", 0, null, null, 0); @@ -122,7 +118,6 @@ export class BasicRenderPipeline { */ destroy(): void { this._cullingResults.destroy(); - this._spriteMaskManager.destroy(); this._renderPassArray = null; this._defaultPass = null; this._camera = null; @@ -138,7 +133,7 @@ export class BasicRenderPipeline { const camera = this._camera; const scene = camera.scene; const cullingResults = this._cullingResults; - const batcherManager = camera._batcherManager; + const batcherManager = camera.engine.batcherManager; if (scene.castShadows && scene._sunLight?.shadowType !== ShadowType.None) { this._cascadedShadowCaster.onRender(context); @@ -146,7 +141,7 @@ export class BasicRenderPipeline { cullingResults.reset(); batcherManager.clear(); - this._spriteMaskManager.clear(); + camera.engine.spriteMaskManager.clear(); context.applyVirtualCamera(camera._virtualCamera); diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 9f418ceaf9..06e9b01316 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -48,7 +48,7 @@ export class RenderQueue { } const { engine, scene } = camera; - const { _spriteMaskManager } = camera._renderPipeline; + const { spriteMaskManager } = camera.engine; const renderCount = engine._renderCount; const rhi = engine._hardwareRenderer; const sceneData = scene.shaderData; @@ -69,7 +69,7 @@ export class RenderQueue { const isSprite = data.usage === RenderDataUsage.Sprite; const meshData = data; const renderer = meshData.component; - isSprite && _spriteMaskManager.preRender(camera, renderer); + isSprite && spriteMaskManager.preRender(camera, renderer); const compileMacros = Shader._compileMacros; const material = meshData.material.destroyed ? engine._magentaMaterial : meshData.material; @@ -150,7 +150,7 @@ export class RenderQueue { ); rhi.drawPrimitive(meshData.mesh, meshData.subMesh, program); - isSprite && _spriteMaskManager.postRender(renderer); + isSprite && spriteMaskManager.postRender(renderer); } } } diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts index f31d9614bd..f69331d275 100644 --- a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -21,8 +21,6 @@ export class BatcherManager { } commitRenderData(context: RenderContext, data: RenderData | Array): void { - if (!data) return; - if (data instanceof Array) { for (let i = 0, l = data.length; i < l; ++i) { this._handleRenderData(context, data[i]); diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index 48c5ef8fc8..65ef6c4290 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -145,7 +145,7 @@ export class MeshRenderer extends Renderer { const materials = this._materials; const subMeshes = mesh.subMeshes; - const batcherManager = context.camera._batcherManager; + const batcherManager = context.camera.engine.batcherManager; const meshRenderDataPool = this._engine._meshRenderDataPool; for (let i = 0, n = subMeshes.length; i < n; i++) { const material = materials[i]; diff --git a/tests/src/core/SpriteMask.test.ts b/tests/src/core/SpriteMask.test.ts index 0d5b8a9de6..51bc87ea77 100644 --- a/tests/src/core/SpriteMask.test.ts +++ b/tests/src/core/SpriteMask.test.ts @@ -174,7 +174,7 @@ describe("SpriteMask", async () => { const rootEntity = scene.getRootEntity(); const spriteMask = rootEntity.addComponent(SpriteMask); const texture2d = new Texture2D(engine, 100, 200); - const context = { camera: { _renderPipeline: { _spriteMaskManager: { addMask: () => {} } } } }; + const context = { camera: { engine: { spriteMaskManager: { addMask: () => {} } } } }; // @ts-ignore spriteMask._render(context); // @ts-ignore From a2a236b71b73e7fd0793a1320ce8b7610790b012 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 29 Aug 2023 16:14:19 +0800 Subject: [PATCH 006/218] refactor(rederpipeline): opt code --- packages/core/src/2d/sprite/SpriteMask.ts | 2 +- packages/core/src/2d/sprite/SpriteRenderer.ts | 2 +- packages/core/src/2d/text/TextRenderer.ts | 2 +- packages/core/src/Engine.ts | 17 +++++++++-------- .../src/RenderPipeline/BasicRenderPipeline.ts | 4 ++-- packages/core/src/RenderPipeline/RenderQueue.ts | 2 +- packages/core/src/mesh/MeshRenderer.ts | 2 +- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 529956438a..5b623ae9b7 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -217,7 +217,7 @@ export class SpriteMask extends Renderer { } const { engine } = context.camera; - engine.spriteMaskManager.addMask(this); + engine._spriteMaskManager.addMask(this); const renderData = engine._spriteRenderDataPool.getFromPool(); const material = this.getMaterial(); renderData.set(this, material, this._verticesData, this.sprite.texture); diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 2d7286eeed..6270afe516 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -327,7 +327,7 @@ export class SpriteRenderer extends Renderer { const renderData = engine._spriteRenderDataPool.getFromPool(); renderData.set(this, material, this._verticesData, this.sprite.texture); renderData.usage = RenderDataUsage.Sprite; - engine.batcherManager.commitRenderData(context, renderData); + engine._batcherManager.commitRenderData(context, renderData); } /** diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 3f89fcf9cf..4710b80376 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -402,7 +402,7 @@ export class TextRenderer extends Renderer { renderData.usage = RenderDataUsage.Sprite; spriteRenderDatas.push(renderData); } - engine.batcherManager.commitRenderData(context, spriteRenderDatas); + engine._batcherManager.commitRenderData(context, spriteRenderDatas); } private _updateStencilState(): void { diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 7bde33c2ad..7effd0622f 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -53,10 +53,11 @@ export class Engine extends EventDispatcher { /** Input manager of Engine. */ readonly inputManager: InputManager; - /** batcher manager of Engine. */ - readonly batcherManager: BatcherManager; - /** sprite mask manager of Engine. */ - readonly spriteMaskManager: SpriteMaskManager; + + /** @internal */ + _batcherManager: BatcherManager; + /** @internal */ + _spriteMaskManager: SpriteMaskManager; /** @internal */ _physicsInitialized: boolean = false; @@ -234,8 +235,8 @@ export class Engine extends EventDispatcher { this._textDefaultFont.isGCIgnored = true; this.inputManager = new InputManager(this); - this.batcherManager = new BatcherManager(this); - this.spriteMaskManager = new SpriteMaskManager(this); + this._batcherManager = new BatcherManager(this); + this._spriteMaskManager = new SpriteMaskManager(this); this._initMagentaTextures(hardwareRenderer); @@ -412,8 +413,8 @@ export class Engine extends EventDispatcher { this._fontMap = null; this.inputManager._destroy(); - this.batcherManager.destroy(); - this.spriteMaskManager.destroy(); + this._batcherManager.destroy(); + this._spriteMaskManager.destroy(); this.dispatch("shutdown", this); // Cancel animation diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index dcbdf3f6ce..b30ecaea12 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -133,7 +133,7 @@ export class BasicRenderPipeline { const camera = this._camera; const scene = camera.scene; const cullingResults = this._cullingResults; - const batcherManager = camera.engine.batcherManager; + const batcherManager = camera.engine._batcherManager; if (scene.castShadows && scene._sunLight?.shadowType !== ShadowType.None) { this._cascadedShadowCaster.onRender(context); @@ -141,7 +141,7 @@ export class BasicRenderPipeline { cullingResults.reset(); batcherManager.clear(); - camera.engine.spriteMaskManager.clear(); + camera.engine._spriteMaskManager.clear(); context.applyVirtualCamera(camera._virtualCamera); diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 06e9b01316..0d27936040 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -48,7 +48,7 @@ export class RenderQueue { } const { engine, scene } = camera; - const { spriteMaskManager } = camera.engine; + const { _spriteMaskManager: spriteMaskManager } = camera.engine; const renderCount = engine._renderCount; const rhi = engine._hardwareRenderer; const sceneData = scene.shaderData; diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index 65ef6c4290..23766c8511 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -145,7 +145,7 @@ export class MeshRenderer extends Renderer { const materials = this._materials; const subMeshes = mesh.subMeshes; - const batcherManager = context.camera.engine.batcherManager; + const batcherManager = context.camera.engine._batcherManager; const meshRenderDataPool = this._engine._meshRenderDataPool; for (let i = 0, n = subMeshes.length; i < n; i++) { const material = materials[i]; From 339f7eb3a35fd90ebef87d6ab10aaa9da61fac71 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 14 Sep 2023 15:03:40 +0800 Subject: [PATCH 007/218] refactor(renderpipeline): opt code --- packages/core/src/RenderPipeline/RenderQueue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 71b86f7a1a..f43c83ca5b 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -160,8 +160,8 @@ export class RenderQueue { ); rhi.drawPrimitive(primitive, data.subPrimitive, program); - isSprite && spriteMaskManager.postRender(renderer); } + isSprite && spriteMaskManager.postRender(renderer); } } From 8e028fb646d7a8aa7a717b91ad1ffae4d2700756 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 28 Dec 2023 16:00:41 +0800 Subject: [PATCH 008/218] refactor(render-pipeline): opt code --- .../src/RenderPipeline/SpriteMaskManager.ts | 2 +- .../src/RenderPipeline/batcher/Batcher2D.ts | 90 ++--- .../batcher/SpriteMaskBatcher.ts | 130 +------ .../batcher/SpriteMaskBatcherOld.ts | 326 ++++++++++++++++++ 4 files changed, 387 insertions(+), 161 deletions(-) create mode 100644 packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts diff --git a/packages/core/src/RenderPipeline/SpriteMaskManager.ts b/packages/core/src/RenderPipeline/SpriteMaskManager.ts index fde52d64dd..f478dbaf55 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskManager.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskManager.ts @@ -39,7 +39,7 @@ export class SpriteMaskManager { this._batcher.clear(); this._processMasksDiff(camera, renderer); - this._batcher.flush(camera); + this._batcher.uploadAndDraw(camera); } postRender(renderer: SpriteRenderer): void { diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index fe17e83907..6e42677f4e 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -155,6 +155,51 @@ export class Batcher2D implements IBatcher { return 36; } + protected _createMesh(engine: Engine, index: number): BufferMesh { + const { _meshes } = this; + if (_meshes[index]) { + return _meshes[index]; + } + + const { MAX_VERTEX_COUNT } = Batcher2D; + const mesh = new BufferMesh(engine, `BufferMesh${index}`); + mesh.isGCIgnored = true; + const vertexElements: VertexElement[] = []; + const vertexStride = this.createVertexElements(vertexElements); + + // vertices + const vertexBuffer = (this._vertexBuffers[index] = new Buffer( + engine, + BufferBindFlag.VertexBuffer, + MAX_VERTEX_COUNT * vertexStride, + BufferUsage.Dynamic + )); + vertexBuffer.isGCIgnored = true; + // indices + const indiceBuffer = (this._indiceBuffers[index] = new Buffer( + engine, + BufferBindFlag.IndexBuffer, + MAX_VERTEX_COUNT * 8, + BufferUsage.Dynamic + )); + indiceBuffer.isGCIgnored = true; + mesh.setVertexBufferBinding(vertexBuffer, vertexStride); + mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); + mesh.setVertexElements(vertexElements); + index >= this._meshCount && (this._meshCount = index + 1); + this._meshes[index] = mesh; + + return mesh; + } + + protected _getSubMeshFromPool(start: number, count: number): SubMesh { + const subMesh = this._subMeshPool.getFromPool(); + subMesh.start = start; + subMesh.count = count; + subMesh.topology = MeshTopology.Triangles; + return subMesh; + } + private _canBatch(preRenderData: SpriteRenderData, curRenderData: SpriteRenderData): boolean { const preRender = preRenderData.component; const curRender = curRenderData.component; @@ -231,49 +276,4 @@ export class Batcher2D implements IBatcher { this._indices = new Uint16Array(MAX_VERTEX_COUNT * 4); this._createMesh(engine, 0); } - - private _createMesh(engine: Engine, index: number): BufferMesh { - const { _meshes } = this; - if (_meshes[index]) { - return _meshes[index]; - } - - const { MAX_VERTEX_COUNT } = Batcher2D; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh.isGCIgnored = true; - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 8, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - index >= this._meshCount && (this._meshCount = index + 1); - this._meshes[index] = mesh; - - return mesh; - } - - private _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } } diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index ffbe102c25..152073e481 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -1,66 +1,32 @@ import { SpriteMask } from "../../2d/sprite/SpriteMask"; import { Camera } from "../../Camera"; import { Engine } from "../../Engine"; -import { Buffer, BufferBindFlag, BufferUsage, IndexFormat, MeshTopology, SubMesh, VertexElement } from "../../graphic"; -import { VertexElementFormat } from "../../graphic/enums/VertexElementFormat"; -import { BufferMesh } from "../../mesh"; -import { ShaderTagKey } from "../../shader"; import { StencilOperation } from "../../shader/enums/StencilOperation"; import { Shader } from "../../shader/Shader"; import { ShaderMacroCollection } from "../../shader/ShaderMacroCollection"; -import { ClassPool } from "../ClassPool"; import { RenderElement } from "../RenderElement"; import { SpriteRenderData } from "../SpriteRenderData"; +import { Batcher2D } from "./Batcher2D"; -export class SpriteMaskBatcher { - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - - /** The maximum number of vertex. */ - static MAX_VERTEX_COUNT: number = 4096; +export class SpriteMaskBatcher extends Batcher2D { + static override MAX_VERTEX_COUNT: number = 128; static _canUploadSameBuffer: boolean = true; - /** @internal */ - _engine: Engine; - /** @internal */ - _subMeshPool: ClassPool = new ClassPool(SubMesh); /** @internal */ _batchedQueue: RenderElement[] = []; /** @internal */ _stencilOps: StencilOperation[] = []; /** @internal */ - _meshes: BufferMesh[] = []; - /** @internal */ - _meshCount: number = 1; - /** @internal */ - _vertexBuffers: Buffer[] = []; - /** @internal */ - _indiceBuffers: Buffer[] = []; - /** @internal */ - _vertices: Float32Array; - /** @internal */ - _indices: Uint16Array; - /** @internal */ - _flushId: number = 0; - /** @internal */ - _vertexCount: number = 0; - /** @internal */ _elementCount: number = 0; constructor(engine: Engine) { - this._engine = engine; - this._initMeshes(engine); - } - - createVertexElements(vertexElements: VertexElement[]): number { - vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); - vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); - return 20; + super(engine); } drawElement(element: RenderElement, camera: Camera, op: StencilOperation): void { const vertexCount = (element.data).verticesData.vertexCount; if (this._vertexCount + vertexCount > SpriteMaskBatcher.MAX_VERTEX_COUNT) { - this.flush(camera); + this.uploadAndDraw(camera); } this._vertexCount += vertexCount; @@ -68,7 +34,7 @@ export class SpriteMaskBatcher { this._stencilOps[this._elementCount++] = op; } - flush(camera: Camera): void { + uploadAndDraw(camera: Camera): void { const batchedQueue = this._batchedQueue; if (batchedQueue.length === 0) { @@ -88,34 +54,18 @@ export class SpriteMaskBatcher { this._elementCount = 0; } - clear(): void { - this._flushId = 0; + override clear(): void { + super.clear(); this._vertexCount = 0; this._elementCount = 0; this._batchedQueue.length = 0; this._stencilOps.length = 0; } - destroy(): void { + override destroy(): void { this._batchedQueue = null; this._stencilOps = null; - - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - meshes[i].destroy(); - } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; + super.destroy(); } canBatch( @@ -153,6 +103,10 @@ export class SpriteMaskBatcher { vertices[vertexIndex++] = curPos.z; vertices[vertexIndex++] = curUV.x; vertices[vertexIndex++] = curUV.y; + vertices[vertexIndex++] = 1; + vertices[vertexIndex++] = 1; + vertices[vertexIndex++] = 1; + vertices[vertexIndex++] = 1; } return vertexIndex; @@ -210,57 +164,11 @@ export class SpriteMaskBatcher { } } - /** - * @internal - * Standalone for canvas 2d renderer plugin. - */ - _initMeshes(engine: Engine) { - const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 5); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 1.5); - - const { _meshes, _meshCount } = this; - for (let i = 0; i < _meshCount; i++) { - _meshes[i] = this._createMesh(engine, i); - } - } - - private _createMesh(engine: Engine, index: number): BufferMesh { - const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh.isGCIgnored = true; - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 3, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - - return mesh; - } - private _updateData(engine: Engine): void { const { _meshes, _flushId } = this; if (!SpriteMaskBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { - this._meshCount++; - _meshes[_flushId] = this._createMesh(engine, _flushId); + this._createMesh(engine, _flushId); } const { _batchedQueue: batchedQueue, _stencilOps: stencilOps, _vertices: vertices, _indices: indices } = this; @@ -315,12 +223,4 @@ export class SpriteMaskBatcher { this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex); this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex); } - - private _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } } diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts new file mode 100644 index 0000000000..ffbe102c25 --- /dev/null +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts @@ -0,0 +1,326 @@ +import { SpriteMask } from "../../2d/sprite/SpriteMask"; +import { Camera } from "../../Camera"; +import { Engine } from "../../Engine"; +import { Buffer, BufferBindFlag, BufferUsage, IndexFormat, MeshTopology, SubMesh, VertexElement } from "../../graphic"; +import { VertexElementFormat } from "../../graphic/enums/VertexElementFormat"; +import { BufferMesh } from "../../mesh"; +import { ShaderTagKey } from "../../shader"; +import { StencilOperation } from "../../shader/enums/StencilOperation"; +import { Shader } from "../../shader/Shader"; +import { ShaderMacroCollection } from "../../shader/ShaderMacroCollection"; +import { ClassPool } from "../ClassPool"; +import { RenderElement } from "../RenderElement"; +import { SpriteRenderData } from "../SpriteRenderData"; + +export class SpriteMaskBatcher { + protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); + + /** The maximum number of vertex. */ + static MAX_VERTEX_COUNT: number = 4096; + static _canUploadSameBuffer: boolean = true; + + /** @internal */ + _engine: Engine; + /** @internal */ + _subMeshPool: ClassPool = new ClassPool(SubMesh); + /** @internal */ + _batchedQueue: RenderElement[] = []; + /** @internal */ + _stencilOps: StencilOperation[] = []; + /** @internal */ + _meshes: BufferMesh[] = []; + /** @internal */ + _meshCount: number = 1; + /** @internal */ + _vertexBuffers: Buffer[] = []; + /** @internal */ + _indiceBuffers: Buffer[] = []; + /** @internal */ + _vertices: Float32Array; + /** @internal */ + _indices: Uint16Array; + /** @internal */ + _flushId: number = 0; + /** @internal */ + _vertexCount: number = 0; + /** @internal */ + _elementCount: number = 0; + + constructor(engine: Engine) { + this._engine = engine; + this._initMeshes(engine); + } + + createVertexElements(vertexElements: VertexElement[]): number { + vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); + vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); + return 20; + } + + drawElement(element: RenderElement, camera: Camera, op: StencilOperation): void { + const vertexCount = (element.data).verticesData.vertexCount; + if (this._vertexCount + vertexCount > SpriteMaskBatcher.MAX_VERTEX_COUNT) { + this.flush(camera); + } + + this._vertexCount += vertexCount; + this._batchedQueue[this._elementCount] = element; + this._stencilOps[this._elementCount++] = op; + } + + flush(camera: Camera): void { + const batchedQueue = this._batchedQueue; + + if (batchedQueue.length === 0) { + return; + } + this._updateData(this._engine); + this.drawBatches(camera); + + if (!SpriteMaskBatcher._canUploadSameBuffer) { + this._flushId++; + } + + batchedQueue.length = 0; + this._stencilOps.length = 0; + this._subMeshPool.resetPool(); + this._vertexCount = 0; + this._elementCount = 0; + } + + clear(): void { + this._flushId = 0; + this._vertexCount = 0; + this._elementCount = 0; + this._batchedQueue.length = 0; + this._stencilOps.length = 0; + } + + destroy(): void { + this._batchedQueue = null; + this._stencilOps = null; + + const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; + + for (let i = 0, n = meshes.length; i < n; ++i) { + meshes[i].destroy(); + } + this._meshes = null; + + for (let i = 0, n = vertexBuffers.length; i < n; ++i) { + vertexBuffers[i].destroy(); + } + this._vertexBuffers = null; + + for (let i = 0, n = indiceBuffers.length; i < n; ++i) { + indiceBuffers[i].destroy(); + } + this._indiceBuffers = null; + } + + canBatch( + preElement: RenderElement, + curElement: RenderElement, + preStencilOp: StencilOperation, + curStencilOp: StencilOperation + ): boolean { + const preSpriteData = preElement.data; + const curSpriteData = curElement.data; + + if (preStencilOp !== curStencilOp) { + return false; + } + + // Compare renderer property + const preShaderData = (preSpriteData.component).shaderData; + const curShaderData = (curSpriteData.component).shaderData; + const textureProperty = SpriteMask._textureProperty; + const alphaCutoffProperty = SpriteMask._alphaCutoffProperty; + + return ( + preShaderData.getTexture(textureProperty) === curShaderData.getTexture(textureProperty) && + preShaderData.getTexture(alphaCutoffProperty) === curShaderData.getTexture(alphaCutoffProperty) + ); + } + + updateVertices(element: SpriteRenderData, vertices: Float32Array, vertexIndex: number): number { + const { positions, uvs, vertexCount } = element.verticesData; + for (let i = 0; i < vertexCount; i++) { + const curPos = positions[i]; + const curUV = uvs[i]; + vertices[vertexIndex++] = curPos.x; + vertices[vertexIndex++] = curPos.y; + vertices[vertexIndex++] = curPos.z; + vertices[vertexIndex++] = curUV.x; + vertices[vertexIndex++] = curUV.y; + } + + return vertexIndex; + } + + drawBatches(camera: Camera): void { + const { _engine: engine, _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; + const mesh = this._meshes[this._flushId]; + const subMeshes = mesh.subMeshes; + const sceneData = camera.scene.shaderData; + const cameraData = camera.shaderData; + + for (let i = 0, len = subMeshes.length; i < len; i++) { + const subMesh = subMeshes[i]; + const spriteMaskElement = batchedQueue[i]; + const stencilOp = stencilOps[i]; + const renderData = spriteMaskElement.data; + + if (!subMesh || !spriteMaskElement) { + return; + } + + const renderer = renderData.component; + const material = renderData.material; + + const compileMacros = Shader._compileMacros; + // union render global macro and material self macro. + ShaderMacroCollection.unionCollection( + renderer._globalShaderMacro, + material.shaderData._macroCollection, + compileMacros + ); + + // Update stencil state + const stencilState = material.renderState.stencilState; + stencilState.passOperationFront = stencilOp; + stencilState.passOperationBack = stencilOp; + + const pass = material.shader.subShaders[0].passes[0]; + const program = pass._getShaderProgram(engine, compileMacros); + if (!program.isValid) { + return; + } + + program.bind(); + program.groupingOtherUniformBlock(); + program.uploadAll(program.sceneUniformBlock, sceneData); + program.uploadAll(program.cameraUniformBlock, cameraData); + program.uploadAll(program.rendererUniformBlock, renderer.shaderData); + program.uploadAll(program.materialUniformBlock, material.shaderData); + + material.renderState._apply(engine, false, pass._renderStateDataMap, material.shaderData); + + engine._hardwareRenderer.drawPrimitive(mesh._primitive, subMesh, program); + } + } + + /** + * @internal + * Standalone for canvas 2d renderer plugin. + */ + _initMeshes(engine: Engine) { + const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; + this._vertices = new Float32Array(MAX_VERTEX_COUNT * 5); + this._indices = new Uint16Array(MAX_VERTEX_COUNT * 1.5); + + const { _meshes, _meshCount } = this; + for (let i = 0; i < _meshCount; i++) { + _meshes[i] = this._createMesh(engine, i); + } + } + + private _createMesh(engine: Engine, index: number): BufferMesh { + const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; + const mesh = new BufferMesh(engine, `BufferMesh${index}`); + mesh.isGCIgnored = true; + const vertexElements: VertexElement[] = []; + const vertexStride = this.createVertexElements(vertexElements); + + // vertices + const vertexBuffer = (this._vertexBuffers[index] = new Buffer( + engine, + BufferBindFlag.VertexBuffer, + MAX_VERTEX_COUNT * vertexStride, + BufferUsage.Dynamic + )); + vertexBuffer.isGCIgnored = true; + // indices + const indiceBuffer = (this._indiceBuffers[index] = new Buffer( + engine, + BufferBindFlag.IndexBuffer, + MAX_VERTEX_COUNT * 3, + BufferUsage.Dynamic + )); + indiceBuffer.isGCIgnored = true; + mesh.setVertexBufferBinding(vertexBuffer, vertexStride); + mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); + mesh.setVertexElements(vertexElements); + + return mesh; + } + + private _updateData(engine: Engine): void { + const { _meshes, _flushId } = this; + + if (!SpriteMaskBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { + this._meshCount++; + _meshes[_flushId] = this._createMesh(engine, _flushId); + } + + const { _batchedQueue: batchedQueue, _stencilOps: stencilOps, _vertices: vertices, _indices: indices } = this; + const mesh = _meshes[_flushId]; + mesh.clearSubMesh(); + + let vertexIndex = 0; + let indiceIndex = 0; + let vertexStartIndex = 0; + let vertexCount = 0; + let curIndiceStartIndex = 0; + let curMeshIndex = 0; + let preElement: RenderElement = null; + let preStencilOp: StencilOperation = null; + for (let i = 0, len = batchedQueue.length; i < len; i++) { + const curElement = batchedQueue[i]; + const curStencilOp = stencilOps[i]; + const curData = curElement.data; + + // Batch vertex + vertexIndex = this.updateVertices(curData, vertices, vertexIndex); + + // Batch indice + const { triangles } = curData.verticesData; + const triangleNum = triangles.length; + for (let j = 0; j < triangleNum; j++) { + indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; + } + + curIndiceStartIndex += curData.verticesData.vertexCount; + + if (preElement === null) { + vertexCount += triangleNum; + } else { + if (this.canBatch(preElement, curElement, preStencilOp, curStencilOp)) { + vertexCount += triangleNum; + } else { + mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); + vertexStartIndex += vertexCount; + vertexCount = triangleNum; + batchedQueue[curMeshIndex++] = preElement; + } + } + + preElement = curElement; + preStencilOp = curStencilOp; + } + + mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); + batchedQueue[curMeshIndex] = preElement; + + this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex); + this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex); + } + + private _getSubMeshFromPool(start: number, count: number): SubMesh { + const subMesh = this._subMeshPool.getFromPool(); + subMesh.start = start; + subMesh.count = count; + subMesh.topology = MeshTopology.Triangles; + return subMesh; + } +} From eee57cf9b3d1e76934e02d24973e527abde637c4 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 16 Jan 2024 10:39:20 +0800 Subject: [PATCH 009/218] refactor(2d-render-pipeline): opt buffer update data --- .../core/src/RenderPipeline/Basic2DBatcher.ts | 266 ------------------ .../src/RenderPipeline/batcher/Batcher2D.ts | 7 +- .../batcher/SpriteMaskBatcher.ts | 7 +- 3 files changed, 10 insertions(+), 270 deletions(-) delete mode 100644 packages/core/src/RenderPipeline/Basic2DBatcher.ts diff --git a/packages/core/src/RenderPipeline/Basic2DBatcher.ts b/packages/core/src/RenderPipeline/Basic2DBatcher.ts deleted file mode 100644 index f5cdb073f4..0000000000 --- a/packages/core/src/RenderPipeline/Basic2DBatcher.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { Camera } from "../Camera"; -import { Engine } from "../Engine"; -import { - Buffer, - BufferBindFlag, - BufferUsage, - IndexFormat, - MeshTopology, - SetDataOptions, - SubMesh, - VertexElement -} from "../graphic"; -import { BufferMesh } from "../mesh"; -import { ShaderTagKey } from "../shader/ShaderTagKey"; -import { ClassPool } from "./ClassPool"; -import { RenderElement } from "./RenderElement"; -import { SpriteMaskRenderData } from "./SpriteMaskRenderData"; -import { SpriteRenderData } from "./SpriteRenderData"; -import { TextRenderData } from "./TextRenderData"; - -type SpriteData = SpriteRenderData | SpriteMaskRenderData; - -export abstract class Basic2DBatcher { - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - - /** The maximum number of vertex. */ - static MAX_VERTEX_COUNT: number = 4096; - static _canUploadSameBuffer: boolean = true; - - /** @internal */ - _engine: Engine; - /** @internal */ - _subMeshPool: ClassPool = new ClassPool(SubMesh); - /** @internal */ - _batchedQueue: RenderElement[] = []; - /** @internal */ - _meshes: BufferMesh[] = []; - /** @internal */ - _meshCount: number = 1; - /** @internal */ - _vertexBuffers: Buffer[] = []; - /** @internal */ - _indiceBuffers: Buffer[] = []; - /** @internal */ - _vertices: Float32Array; - /** @internal */ - _indices: Uint16Array; - /** @internal */ - _flushId: number = 0; - /** @internal */ - _vertexCount: number = 0; - /** @internal */ - _elementCount: number = 0; - - constructor(engine: Engine) { - this._engine = engine; - this._initMeshes(engine); - } - - drawElement(element: RenderElement, camera: Camera): void { - const data = element.data; - - if (data.multiRenderData) { - const charsData = (data).charsData; - const pool = camera.engine._renderElementPool; - - for (let i = 0, n = charsData.length; i < n; ++i) { - const charRenderElement = pool.getFromPool(); - charRenderElement.set(charsData[i], element.shaderPasses); - this._drawSubElement(charRenderElement, camera); - } - } else { - this._drawSubElement(element, camera); - } - } - - /** - * @internal - * Standalone for canvas 2d renderer plugin. - */ - _initMeshes(engine: Engine) { - const { MAX_VERTEX_COUNT } = Basic2DBatcher; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 3); - - const { _meshes, _meshCount } = this; - for (let i = 0; i < _meshCount; i++) { - _meshes[i] = this._createMesh(engine, i); - } - } - - flush(camera: Camera): void { - const batchedQueue = this._batchedQueue; - - if (batchedQueue.length === 0) { - return; - } - this._updateData(this._engine); - this.drawBatches(camera); - - if (!Basic2DBatcher._canUploadSameBuffer) { - this._flushId++; - } - - batchedQueue.length = 0; - this._subMeshPool.resetPool(); - this._vertexCount = 0; - this._elementCount = 0; - } - - clear(): void { - this._flushId = 0; - this._vertexCount = 0; - this._elementCount = 0; - this._batchedQueue.length = 0; - } - - destroy(): void { - this._batchedQueue = null; - - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - meshes[i].destroy(); - } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; - } - - private _drawSubElement(element: RenderElement, camera: Camera): void { - const vertexCount = (element.data).verticesData.vertexCount; - if (this._vertexCount + vertexCount > Basic2DBatcher.MAX_VERTEX_COUNT) { - this.flush(camera); - } - - this._vertexCount += vertexCount; - this._batchedQueue[this._elementCount++] = element; - } - - private _createMesh(engine: Engine, index: number): BufferMesh { - const { MAX_VERTEX_COUNT } = Basic2DBatcher; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh.isGCIgnored = true; - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 6, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - - return mesh; - } - - private _updateData(engine: Engine): void { - const { _meshes, _flushId } = this; - - if (!Basic2DBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { - this._meshCount++; - _meshes[_flushId] = this._createMesh(engine, _flushId); - } - - const { _batchedQueue: batchedQueue, _vertices: vertices, _indices: indices } = this; - const mesh = _meshes[_flushId]; - mesh.clearSubMesh(); - - let vertexIndex = 0; - let indiceIndex = 0; - let vertexStartIndex = 0; - let vertexCount = 0; - let curIndiceStartIndex = 0; - let curMeshIndex = 0; - let preElement: RenderElement = null; - for (let i = 0, len = batchedQueue.length; i < len; i++) { - const curElement = batchedQueue[i]; - const curData = curElement.data; - - // Batch vertex - vertexIndex = this.updateVertices(curData, vertices, vertexIndex); - - // Batch indice - const { triangles } = curData.verticesData; - const triangleNum = triangles.length; - for (let j = 0; j < triangleNum; j++) { - indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; - } - - curIndiceStartIndex += curData.verticesData.vertexCount; - - if (preElement === null) { - vertexCount += triangleNum; - } else { - if (this.canBatch(preElement, curElement)) { - vertexCount += triangleNum; - } else { - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - vertexStartIndex += vertexCount; - vertexCount = triangleNum; - batchedQueue[curMeshIndex++] = preElement; - } - } - - preElement = curElement; - } - - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - batchedQueue[curMeshIndex] = preElement; - - // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. - // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. - this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex, SetDataOptions.Discard); - this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex, SetDataOptions.Discard); - } - - private _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } - - /** - * @internal - */ - abstract createVertexElements(vertexElements: VertexElement[]): number; - - /** - * @internal - */ - abstract canBatch(preElement: RenderElement, curElement: RenderElement): boolean; - - /** - * @internal - */ - abstract updateVertices(element: SpriteData, vertices: Float32Array, vertexIndex: number): number; - - /** - * @internal - */ - abstract drawBatches(camera: Camera): void; -} diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 6e42677f4e..bfdaa9d1a7 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -6,6 +6,7 @@ import { BufferUsage, IndexFormat, MeshTopology, + SetDataOptions, SubMesh, VertexElement, VertexElementFormat @@ -135,8 +136,10 @@ export class Batcher2D implements IBatcher { uploadBuffer(): void { const { _flushId } = this; - this._vertexBuffers[_flushId].setData(this._vertices, 0, 0, this._vStartIndex); - this._indiceBuffers[_flushId].setData(this._indices, 0, 0, this._iStartIndex); + // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. + // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. + this._vertexBuffers[_flushId].setData(this._vertices, 0, 0, this._vStartIndex, SetDataOptions.Discard); + this._indiceBuffers[_flushId].setData(this._indices, 0, 0, this._iStartIndex, SetDataOptions.Discard); } clear() { diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index 152073e481..528fc17737 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -1,6 +1,7 @@ import { SpriteMask } from "../../2d/sprite/SpriteMask"; import { Camera } from "../../Camera"; import { Engine } from "../../Engine"; +import { SetDataOptions } from "../../graphic"; import { StencilOperation } from "../../shader/enums/StencilOperation"; import { Shader } from "../../shader/Shader"; import { ShaderMacroCollection } from "../../shader/ShaderMacroCollection"; @@ -220,7 +221,9 @@ export class SpriteMaskBatcher extends Batcher2D { mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); batchedQueue[curMeshIndex] = preElement; - this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex); - this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex); + // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. + // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. + this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex, SetDataOptions.Discard); + this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex, SetDataOptions.Discard); } } From 0d3f67b58889b836b98f496a7fab7ced5fadf66d Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 16 Jan 2024 10:51:45 +0800 Subject: [PATCH 010/218] refactor(2d-render-pipeline): opt code --- packages/core/src/RenderPipeline/CullingResults.ts | 8 ++++---- packages/core/src/RenderPipeline/RenderQueue.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/src/RenderPipeline/CullingResults.ts b/packages/core/src/RenderPipeline/CullingResults.ts index fc2933c5a3..deaf2b1e1a 100644 --- a/packages/core/src/RenderPipeline/CullingResults.ts +++ b/packages/core/src/RenderPipeline/CullingResults.ts @@ -11,10 +11,10 @@ export class CullingResults { readonly transparentQueue: RenderQueue; readonly alphaTestQueue: RenderQueue; - constructor(engine: Engine) { - this.opaqueQueue = new RenderQueue(engine, RenderQueueType.Opaque); - this.transparentQueue = new RenderQueue(engine, RenderQueueType.Transparent); - this.alphaTestQueue = new RenderQueue(engine, RenderQueueType.AlphaTest); + constructor() { + this.opaqueQueue = new RenderQueue(RenderQueueType.Opaque); + this.transparentQueue = new RenderQueue(RenderQueueType.Transparent); + this.alphaTestQueue = new RenderQueue(RenderQueueType.AlphaTest); } reset(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 376c041319..a87f5e3f22 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -69,7 +69,7 @@ export class RenderQueue { private readonly _renderQueueType: RenderQueueType; - constructor(engine: Engine, renderQueueType: RenderQueueType) { + constructor(renderQueueType: RenderQueueType) { this._renderQueueType = renderQueueType; } From 9dd5bf12e44c4fa168f15f3c3d80fd24288c9afc Mon Sep 17 00:00:00 2001 From: singlecoder Date: Sun, 4 Feb 2024 17:16:14 +0800 Subject: [PATCH 011/218] refactor(2d-render-pipeline): fix conflicts --- .../core/src/RenderPipeline/Basic2DBatcher.ts | 268 ------------------ 1 file changed, 268 deletions(-) delete mode 100644 packages/core/src/RenderPipeline/Basic2DBatcher.ts diff --git a/packages/core/src/RenderPipeline/Basic2DBatcher.ts b/packages/core/src/RenderPipeline/Basic2DBatcher.ts deleted file mode 100644 index d693b0d25c..0000000000 --- a/packages/core/src/RenderPipeline/Basic2DBatcher.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { Camera } from "../Camera"; -import { Engine } from "../Engine"; -import { - Buffer, - BufferBindFlag, - BufferUsage, - IndexFormat, - MeshTopology, - SetDataOptions, - SubMesh, - VertexElement -} from "../graphic"; -import { BufferMesh } from "../mesh"; -import { ShaderTagKey } from "../shader/ShaderTagKey"; -import { ClassPool } from "./ClassPool"; -import { RenderElement } from "./RenderElement"; -import { SpriteMaskRenderData } from "./SpriteMaskRenderData"; -import { SpriteRenderData } from "./SpriteRenderData"; -import { TextRenderData } from "./TextRenderData"; - -type SpriteData = SpriteRenderData | SpriteMaskRenderData; - -export abstract class Basic2DBatcher { - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - - /** The maximum number of vertex. */ - static MAX_VERTEX_COUNT: number = 4096; - static _canUploadSameBuffer: boolean = true; - - /** @internal */ - _engine: Engine; - /** @internal */ - _subMeshPool: ClassPool = new ClassPool(SubMesh); - /** @internal */ - _batchedQueue: RenderElement[] = []; - /** @internal */ - _meshes: BufferMesh[] = []; - /** @internal */ - _meshCount: number = 1; - /** @internal */ - _vertexBuffers: Buffer[] = []; - /** @internal */ - _indiceBuffers: Buffer[] = []; - /** @internal */ - _vertices: Float32Array; - /** @internal */ - _indices: Uint16Array; - /** @internal */ - _flushId: number = 0; - /** @internal */ - _vertexCount: number = 0; - /** @internal */ - _elementCount: number = 0; - - constructor(engine: Engine) { - this._engine = engine; - this._initMeshes(engine); - } - - drawElement(element: RenderElement, camera: Camera): void { - const data = element.data; - - if (data.multiRenderData) { - const charsData = (data).charsData; - const pool = camera.engine._renderElementPool; - - for (let i = 0, n = charsData.length; i < n; ++i) { - const charRenderElement = pool.getFromPool(); - charRenderElement.set(charsData[i], element.shaderPasses); - this._drawSubElement(charRenderElement, camera); - } - } else { - this._drawSubElement(element, camera); - } - } - - /** - * @internal - * Standalone for canvas 2d renderer plugin. - */ - _initMeshes(engine: Engine) { - const { MAX_VERTEX_COUNT } = Basic2DBatcher; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 3); - - const { _meshes, _meshCount } = this; - for (let i = 0; i < _meshCount; i++) { - _meshes[i] = this._createMesh(engine, i); - } - } - - flush(camera: Camera): void { - const batchedQueue = this._batchedQueue; - - if (batchedQueue.length === 0) { - return; - } - this._updateData(this._engine); - this.drawBatches(camera); - - if (!Basic2DBatcher._canUploadSameBuffer) { - this._flushId++; - } - - batchedQueue.length = 0; - this._subMeshPool.resetPool(); - this._vertexCount = 0; - this._elementCount = 0; - } - - clear(): void { - this._flushId = 0; - this._vertexCount = 0; - this._elementCount = 0; - this._batchedQueue.length = 0; - } - - destroy(): void { - this._batchedQueue = null; - - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - const mesh = meshes[i]; - mesh._addReferCount(-1); - mesh.destroy(); - } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; - } - - private _drawSubElement(element: RenderElement, camera: Camera): void { - const vertexCount = (element.data).verticesData.vertexCount; - if (this._vertexCount + vertexCount > Basic2DBatcher.MAX_VERTEX_COUNT) { - this.flush(camera); - } - - this._vertexCount += vertexCount; - this._batchedQueue[this._elementCount++] = element; - } - - private _createMesh(engine: Engine, index: number): BufferMesh { - const { MAX_VERTEX_COUNT } = Basic2DBatcher; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh._addReferCount(1); - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 6, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - - return mesh; - } - - private _updateData(engine: Engine): void { - const { _meshes, _flushId } = this; - - if (!Basic2DBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { - this._meshCount++; - _meshes[_flushId] = this._createMesh(engine, _flushId); - } - - const { _batchedQueue: batchedQueue, _vertices: vertices, _indices: indices } = this; - const mesh = _meshes[_flushId]; - mesh.clearSubMesh(); - - let vertexIndex = 0; - let indiceIndex = 0; - let vertexStartIndex = 0; - let vertexCount = 0; - let curIndiceStartIndex = 0; - let curMeshIndex = 0; - let preElement: RenderElement = null; - for (let i = 0, len = batchedQueue.length; i < len; i++) { - const curElement = batchedQueue[i]; - const curData = curElement.data; - - // Batch vertex - vertexIndex = this.updateVertices(curData, vertices, vertexIndex); - - // Batch indice - const { triangles } = curData.verticesData; - const triangleNum = triangles.length; - for (let j = 0; j < triangleNum; j++) { - indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; - } - - curIndiceStartIndex += curData.verticesData.vertexCount; - - if (preElement === null) { - vertexCount += triangleNum; - } else { - if (this.canBatch(preElement, curElement)) { - vertexCount += triangleNum; - } else { - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - vertexStartIndex += vertexCount; - vertexCount = triangleNum; - batchedQueue[curMeshIndex++] = preElement; - } - } - - preElement = curElement; - } - - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - batchedQueue[curMeshIndex] = preElement; - - // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. - // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. - this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex, SetDataOptions.Discard); - this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex, SetDataOptions.Discard); - } - - private _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } - - /** - * @internal - */ - abstract createVertexElements(vertexElements: VertexElement[]): number; - - /** - * @internal - */ - abstract canBatch(preElement: RenderElement, curElement: RenderElement): boolean; - - /** - * @internal - */ - abstract updateVertices(element: SpriteData, vertices: Float32Array, vertexIndex: number): number; - - /** - * @internal - */ - abstract drawBatches(camera: Camera): void; -} From 371550be40c44c8d8f70470e0ee7be079accbdeb Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 20 Feb 2024 15:02:50 +0800 Subject: [PATCH 012/218] refactor(2d-render-pipeline): opt render data api --- packages/core/src/2d/sprite/SpriteMask.ts | 2 +- packages/core/src/2d/sprite/SpriteRenderer.ts | 2 +- packages/core/src/2d/text/TextRenderer.ts | 2 +- packages/core/src/RenderPipeline/RenderData.ts | 2 +- packages/core/src/RenderPipeline/SpriteRenderData.ts | 2 +- packages/core/src/RenderPipeline/batcher/Batcher2D.ts | 2 +- packages/core/src/mesh/MeshRenderer.ts | 2 +- packages/core/src/particle/ParticleRenderer.ts | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index c2bd26308c..4c9e7bd437 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -221,7 +221,7 @@ export class SpriteMask extends Renderer { engine._spriteMaskManager.addMask(this); const renderData = engine._spriteRenderDataPool.getFromPool(); const material = this.getMaterial(); - renderData.set(this, material, this._verticesData, this.sprite.texture); + renderData.setX(this, material, this._verticesData, this.sprite.texture); renderData.usage = RenderDataUsage.SpriteMask; const renderElement = engine._renderElementPool.getFromPool(); diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index d6e58c434f..d335b9cfe6 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -325,7 +325,7 @@ export class SpriteRenderer extends Renderer { const { engine } = context.camera; const material = this.getMaterial(); const renderData = engine._spriteRenderDataPool.getFromPool(); - renderData.set(this, material, this._verticesData, this.sprite.texture); + renderData.setX(this, material, this._verticesData, this.sprite.texture); renderData.usage = RenderDataUsage.Sprite; engine._batcherManager.commitRenderData(context, renderData); } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 558368c6bd..51a9e8b762 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -404,7 +404,7 @@ export class TextRenderer extends Renderer { for (let i = 0; i < charCount; ++i) { const charRenderData = charRenderDatas[i]; const renderData = spriteRenderDataPool.getFromPool(); - renderData.set(this, material, charRenderData.renderData, charRenderData.texture); + renderData.setX(this, material, charRenderData.renderData, charRenderData.texture); renderData.usage = RenderDataUsage.Sprite; spriteRenderDatas.push(renderData); } diff --git a/packages/core/src/RenderPipeline/RenderData.ts b/packages/core/src/RenderPipeline/RenderData.ts index 2a87854817..11575e42aa 100644 --- a/packages/core/src/RenderPipeline/RenderData.ts +++ b/packages/core/src/RenderPipeline/RenderData.ts @@ -12,7 +12,7 @@ export class RenderData implements IPoolElement { subPrimitive: SubMesh; usage: RenderDataUsage = RenderDataUsage.Mesh; - setX(component: Renderer, material: Material, primitive: Primitive, subPrimitive: SubMesh): void { + set(component: Renderer, material: Material, primitive: Primitive, subPrimitive: SubMesh): void { this.component = component; this.material = material; diff --git a/packages/core/src/RenderPipeline/SpriteRenderData.ts b/packages/core/src/RenderPipeline/SpriteRenderData.ts index e9f232745e..af4088048d 100644 --- a/packages/core/src/RenderPipeline/SpriteRenderData.ts +++ b/packages/core/src/RenderPipeline/SpriteRenderData.ts @@ -15,7 +15,7 @@ export class SpriteRenderData extends RenderData implements IPoolElement { this.usage = RenderDataUsage.Sprite; } - set(component: Renderer, material: Material, verticesData: VertexData2D, texture: Texture2D): void { + setX(component: Renderer, material: Material, verticesData: VertexData2D, texture: Texture2D): void { this.component = component; this.material = material; this.verticesData = verticesData; diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index bfdaa9d1a7..110dee4558 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -129,7 +129,7 @@ export class Batcher2D implements IBatcher { const renderData = this._engine._renderDataPool.getFromPool(); renderData.usage = RenderDataUsage.Sprite; - renderData.setX(_preSpriteRenderData.component, _preSpriteRenderData.material, mesh._primitive, subMesh); + renderData.set(_preSpriteRenderData.component, _preSpriteRenderData.material, mesh._primitive, subMesh); renderData.component.shaderData.setTexture(Batcher2D._textureProperty, _preSpriteRenderData.texture); this._preContext.camera._renderPipeline.pushRenderData(this._preContext, renderData); } diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index c5417315d8..b4b33b93a6 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -162,7 +162,7 @@ export class MeshRenderer extends Renderer { const renderData = meshRenderDataPool.getFromPool(); renderData.usage = RenderDataUsage.Mesh; - renderData.setX(this, material, mesh._primitive, subMeshes[i]); + renderData.set(this, material, mesh._primitive, subMeshes[i]); batcherManager.commitRenderData(context, renderData); } } diff --git a/packages/core/src/particle/ParticleRenderer.ts b/packages/core/src/particle/ParticleRenderer.ts index fff0485071..1261e519dd 100644 --- a/packages/core/src/particle/ParticleRenderer.ts +++ b/packages/core/src/particle/ParticleRenderer.ts @@ -192,7 +192,7 @@ export class ParticleRenderer extends Renderer { } const renderData = this._engine._renderDataPool.getFromPool(); - renderData.setX(this, material, generator._primitive, generator._subPrimitive); + renderData.set(this, material, generator._primitive, generator._subPrimitive); context.camera._renderPipeline.pushRenderData(context, renderData); } From 08214c23cd69e0ecbd2ea26aeb44d5c7c2ca2a0e Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 22 Feb 2024 17:52:57 +0800 Subject: [PATCH 013/218] refactor(2d-render-pipeline): add MeshBuffer --- .../src/RenderPipeline/batcher/Batcher2D.ts | 123 ++----- .../src/RenderPipeline/batcher/MeshBuffer.ts | 83 +++++ .../batcher/SpriteMaskBatcher.ts | 20 +- .../batcher/SpriteMaskBatcherOld.ts | 326 ------------------ 4 files changed, 119 insertions(+), 433 deletions(-) create mode 100644 packages/core/src/RenderPipeline/batcher/MeshBuffer.ts delete mode 100644 packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 110dee4558..6f63d6ede6 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,23 +1,13 @@ import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; import { Engine } from "../../Engine"; -import { - Buffer, - BufferBindFlag, - BufferUsage, - IndexFormat, - MeshTopology, - SetDataOptions, - SubMesh, - VertexElement, - VertexElementFormat -} from "../../graphic"; -import { BufferMesh } from "../../mesh"; +import { MeshTopology, SetDataOptions, SubMesh } from "../../graphic"; import { ShaderProperty, ShaderTagKey } from "../../shader"; import { ClassPool } from "../ClassPool"; import { RenderContext } from "../RenderContext"; import { SpriteRenderData } from "../SpriteRenderData"; import { RenderDataUsage } from "../enums/RenderDataUsage"; import { IBatcher } from "./IBatcher"; +import { MeshBuffer } from "./MeshBuffer"; /** * @internal @@ -32,21 +22,13 @@ export class Batcher2D implements IBatcher { /** @internal */ _engine: Engine; /** @internal */ - _meshes: BufferMesh[] = []; - /** @internal */ - _meshCount: number = 1; - /** @internal */ _subMeshPool: ClassPool = new ClassPool(SubMesh); + /** @internal */ - _vertexBuffers: Buffer[] = []; - /** @internal */ - _indiceBuffers: Buffer[] = []; - /** @internal */ - _vertices: Float32Array; - /** @internal */ - _indices: Uint16Array; + _meshBuffers: MeshBuffer[] = []; /** @internal */ _flushId: number = 0; + /** @internal */ _vStartIndex: number = 0; /** @internal */ @@ -66,29 +48,19 @@ export class Batcher2D implements IBatcher { constructor(engine: Engine) { this._engine = engine; - this._initMeshes(engine); + this._createMeshBuffer(engine, 0); } /** * Destroy internal resources. */ destroy(): void { - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - meshes[i].destroy(); + const { _meshBuffers } = this; + for (let i = 0, l = _meshBuffers.length; i < l; ++i) { + _meshBuffers[i].destroy(); } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; + _meshBuffers.length = 0; + this._meshBuffers = null; } commitRenderData(context: RenderContext, data: SpriteRenderData): void { @@ -97,7 +69,7 @@ export class Batcher2D implements IBatcher { this.flush(); this.uploadBuffer(); const newFlushId = this._flushId + 1; - this._createMesh(this._engine, newFlushId); + this._createMeshBuffer(this._engine, newFlushId); this._reset(); this._flushId = newFlushId; } else { @@ -118,7 +90,7 @@ export class Batcher2D implements IBatcher { } const { _preSpriteRenderData, _iStartIndex, _iIndex } = this; - const mesh = this._meshes[this._flushId]; + const mesh = this._meshBuffers[this._flushId]._mesh; const iCount = _iIndex - _iStartIndex; const subMesh = this._getSubMeshFromPool(_iStartIndex, iCount); mesh.addSubMesh(subMesh); @@ -135,64 +107,30 @@ export class Batcher2D implements IBatcher { } uploadBuffer(): void { - const { _flushId } = this; - // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. - // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. - this._vertexBuffers[_flushId].setData(this._vertices, 0, 0, this._vStartIndex, SetDataOptions.Discard); - this._indiceBuffers[_flushId].setData(this._indices, 0, 0, this._iStartIndex, SetDataOptions.Discard); + this._meshBuffers[this._flushId].uploadBuffer(this._vStartIndex, this._iStartIndex); } clear() { this._reset(); this._subMeshPool.resetPool(); - const { _meshes, _meshCount } = this; - for (let i = 0; i < _meshCount; ++i) { - _meshes[i].clearSubMesh(); + const { _meshBuffers } = this; + for (let i = 0, l = _meshBuffers.length; i < l; ++i) { + _meshBuffers[i]._mesh.clearSubMesh(); } } - createVertexElements(vertexElements: VertexElement[]): number { - vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); - vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); - vertexElements[2] = new VertexElement("COLOR_0", 20, VertexElementFormat.Vector4, 0); - return 36; + getInfo(vertexCount, indiceCount) { + // TODO } - protected _createMesh(engine: Engine, index: number): BufferMesh { - const { _meshes } = this; - if (_meshes[index]) { - return _meshes[index]; + protected _createMeshBuffer(engine: Engine, index: number): MeshBuffer { + const { _meshBuffers } = this; + if (_meshBuffers[index]) { + return _meshBuffers[index]; } - const { MAX_VERTEX_COUNT } = Batcher2D; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh.isGCIgnored = true; - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 8, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - index >= this._meshCount && (this._meshCount = index + 1); - this._meshes[index] = mesh; - - return mesh; + const meshBuffer = (_meshBuffers[index] = new MeshBuffer(engine)); + return meshBuffer; } protected _getSubMeshFromPool(start: number, count: number): SubMesh { @@ -234,10 +172,12 @@ export class Batcher2D implements IBatcher { } private _fillRenderData(data: SpriteRenderData): void { - const { _vertices, _indices, _vertexCount } = this; + const { _flushId, _vertexCount } = this; const { positions, uvs, color, vertexCount, triangles } = data.verticesData; let index = this._vIndex; + const _vertices = this._meshBuffers[_flushId]._vertices; + const _indices = this._meshBuffers[_flushId]._indices; for (let i = 0; i < vertexCount; ++i) { const curPos = positions[i]; const curUV = uvs[i]; @@ -272,11 +212,4 @@ export class Batcher2D implements IBatcher { this._preContext = null; this._preSpriteRenderData = null; } - - private _initMeshes(engine: Engine) { - const { MAX_VERTEX_COUNT } = Batcher2D; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 4); - this._createMesh(engine, 0); - } } diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts new file mode 100644 index 0000000000..df206ef759 --- /dev/null +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -0,0 +1,83 @@ +import { Engine } from "../../Engine"; +import { + Buffer, + BufferBindFlag, + BufferUsage, + IndexFormat, + SetDataOptions, + VertexElement, + VertexElementFormat +} from "../../graphic"; +import { BufferMesh } from "../../mesh"; +import { Batcher2D } from "./Batcher2D"; + +/** + * @internal + */ +export class MeshBuffer { + /** @internal */ + _mesh: BufferMesh; + /** @internal */ + _vBuffer: Buffer; + /** @internal */ + _iBuffer: Buffer; + /** @internal */ + _vertices: Float32Array; + /** @internal */ + _indices: Uint16Array; + + constructor(engine: Engine) { + const mesh = (this._mesh = new BufferMesh(engine)); + mesh.isGCIgnored = true; + + const vertexElements: VertexElement[] = []; + const vertexStride = this.createVertexElements(vertexElements); + const { MAX_VERTEX_COUNT } = Batcher2D; + // vertices + const vertexBuffer = (this._vBuffer = new Buffer( + engine, + BufferBindFlag.VertexBuffer, + MAX_VERTEX_COUNT * vertexStride, + BufferUsage.Dynamic + )); + vertexBuffer.isGCIgnored = true; + this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); + // indices + const indiceBuffer = (this._iBuffer = new Buffer( + engine, + BufferBindFlag.IndexBuffer, + MAX_VERTEX_COUNT * 8, + BufferUsage.Dynamic + )); + indiceBuffer.isGCIgnored = true; + mesh.setVertexBufferBinding(vertexBuffer, vertexStride); + mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); + mesh.setVertexElements(vertexElements); + this._indices = new Uint16Array(MAX_VERTEX_COUNT * 4); + } + + destroy(): void { + this._mesh.destroy(); + this._mesh = null; + this._vBuffer.destroy(); + this._vBuffer = null; + this._iBuffer.destroy(); + this._iBuffer = null; + this._vertices = null; + this._indices = null; + } + + uploadBuffer(vLen: number, iLen: number): void { + // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. + // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. + this._vBuffer.setData(this._vertices, 0, 0, vLen, SetDataOptions.Discard); + this._iBuffer.setData(this._indices, 0, 0, iLen, SetDataOptions.Discard); + } + + createVertexElements(vertexElements: VertexElement[]): number { + vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); + vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); + vertexElements[2] = new VertexElement("COLOR_0", 20, VertexElementFormat.Vector4, 0); + return 36; + } +} diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index 528fc17737..0a593678c1 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -1,7 +1,6 @@ import { SpriteMask } from "../../2d/sprite/SpriteMask"; import { Camera } from "../../Camera"; import { Engine } from "../../Engine"; -import { SetDataOptions } from "../../graphic"; import { StencilOperation } from "../../shader/enums/StencilOperation"; import { Shader } from "../../shader/Shader"; import { ShaderMacroCollection } from "../../shader/ShaderMacroCollection"; @@ -115,7 +114,7 @@ export class SpriteMaskBatcher extends Batcher2D { drawBatches(camera: Camera): void { const { _engine: engine, _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; - const mesh = this._meshes[this._flushId]; + const mesh = this._meshBuffers[this._flushId]._mesh; const subMeshes = mesh.subMeshes; const sceneData = camera.scene.shaderData; const cameraData = camera.shaderData; @@ -166,14 +165,15 @@ export class SpriteMaskBatcher extends Batcher2D { } private _updateData(engine: Engine): void { - const { _meshes, _flushId } = this; + const { _meshBuffers, _flushId } = this; - if (!SpriteMaskBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { - this._createMesh(engine, _flushId); + if (!SpriteMaskBatcher._canUploadSameBuffer && _meshBuffers.length <= _flushId) { + this._createMeshBuffer(engine, _flushId); } - const { _batchedQueue: batchedQueue, _stencilOps: stencilOps, _vertices: vertices, _indices: indices } = this; - const mesh = _meshes[_flushId]; + const { _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; + const meshBuffer = _meshBuffers[_flushId]; + const { _vertices: vertices, _indices: indices, _mesh: mesh } = meshBuffer; mesh.clearSubMesh(); let vertexIndex = 0; @@ -220,10 +220,6 @@ export class SpriteMaskBatcher extends Batcher2D { mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); batchedQueue[curMeshIndex] = preElement; - - // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. - // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. - this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex, SetDataOptions.Discard); - this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex, SetDataOptions.Discard); + meshBuffer.uploadBuffer(vertexIndex, indiceIndex); } } diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts deleted file mode 100644 index ffbe102c25..0000000000 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcherOld.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { SpriteMask } from "../../2d/sprite/SpriteMask"; -import { Camera } from "../../Camera"; -import { Engine } from "../../Engine"; -import { Buffer, BufferBindFlag, BufferUsage, IndexFormat, MeshTopology, SubMesh, VertexElement } from "../../graphic"; -import { VertexElementFormat } from "../../graphic/enums/VertexElementFormat"; -import { BufferMesh } from "../../mesh"; -import { ShaderTagKey } from "../../shader"; -import { StencilOperation } from "../../shader/enums/StencilOperation"; -import { Shader } from "../../shader/Shader"; -import { ShaderMacroCollection } from "../../shader/ShaderMacroCollection"; -import { ClassPool } from "../ClassPool"; -import { RenderElement } from "../RenderElement"; -import { SpriteRenderData } from "../SpriteRenderData"; - -export class SpriteMaskBatcher { - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - - /** The maximum number of vertex. */ - static MAX_VERTEX_COUNT: number = 4096; - static _canUploadSameBuffer: boolean = true; - - /** @internal */ - _engine: Engine; - /** @internal */ - _subMeshPool: ClassPool = new ClassPool(SubMesh); - /** @internal */ - _batchedQueue: RenderElement[] = []; - /** @internal */ - _stencilOps: StencilOperation[] = []; - /** @internal */ - _meshes: BufferMesh[] = []; - /** @internal */ - _meshCount: number = 1; - /** @internal */ - _vertexBuffers: Buffer[] = []; - /** @internal */ - _indiceBuffers: Buffer[] = []; - /** @internal */ - _vertices: Float32Array; - /** @internal */ - _indices: Uint16Array; - /** @internal */ - _flushId: number = 0; - /** @internal */ - _vertexCount: number = 0; - /** @internal */ - _elementCount: number = 0; - - constructor(engine: Engine) { - this._engine = engine; - this._initMeshes(engine); - } - - createVertexElements(vertexElements: VertexElement[]): number { - vertexElements[0] = new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0); - vertexElements[1] = new VertexElement("TEXCOORD_0", 12, VertexElementFormat.Vector2, 0); - return 20; - } - - drawElement(element: RenderElement, camera: Camera, op: StencilOperation): void { - const vertexCount = (element.data).verticesData.vertexCount; - if (this._vertexCount + vertexCount > SpriteMaskBatcher.MAX_VERTEX_COUNT) { - this.flush(camera); - } - - this._vertexCount += vertexCount; - this._batchedQueue[this._elementCount] = element; - this._stencilOps[this._elementCount++] = op; - } - - flush(camera: Camera): void { - const batchedQueue = this._batchedQueue; - - if (batchedQueue.length === 0) { - return; - } - this._updateData(this._engine); - this.drawBatches(camera); - - if (!SpriteMaskBatcher._canUploadSameBuffer) { - this._flushId++; - } - - batchedQueue.length = 0; - this._stencilOps.length = 0; - this._subMeshPool.resetPool(); - this._vertexCount = 0; - this._elementCount = 0; - } - - clear(): void { - this._flushId = 0; - this._vertexCount = 0; - this._elementCount = 0; - this._batchedQueue.length = 0; - this._stencilOps.length = 0; - } - - destroy(): void { - this._batchedQueue = null; - this._stencilOps = null; - - const { _meshes: meshes, _vertexBuffers: vertexBuffers, _indiceBuffers: indiceBuffers } = this; - - for (let i = 0, n = meshes.length; i < n; ++i) { - meshes[i].destroy(); - } - this._meshes = null; - - for (let i = 0, n = vertexBuffers.length; i < n; ++i) { - vertexBuffers[i].destroy(); - } - this._vertexBuffers = null; - - for (let i = 0, n = indiceBuffers.length; i < n; ++i) { - indiceBuffers[i].destroy(); - } - this._indiceBuffers = null; - } - - canBatch( - preElement: RenderElement, - curElement: RenderElement, - preStencilOp: StencilOperation, - curStencilOp: StencilOperation - ): boolean { - const preSpriteData = preElement.data; - const curSpriteData = curElement.data; - - if (preStencilOp !== curStencilOp) { - return false; - } - - // Compare renderer property - const preShaderData = (preSpriteData.component).shaderData; - const curShaderData = (curSpriteData.component).shaderData; - const textureProperty = SpriteMask._textureProperty; - const alphaCutoffProperty = SpriteMask._alphaCutoffProperty; - - return ( - preShaderData.getTexture(textureProperty) === curShaderData.getTexture(textureProperty) && - preShaderData.getTexture(alphaCutoffProperty) === curShaderData.getTexture(alphaCutoffProperty) - ); - } - - updateVertices(element: SpriteRenderData, vertices: Float32Array, vertexIndex: number): number { - const { positions, uvs, vertexCount } = element.verticesData; - for (let i = 0; i < vertexCount; i++) { - const curPos = positions[i]; - const curUV = uvs[i]; - vertices[vertexIndex++] = curPos.x; - vertices[vertexIndex++] = curPos.y; - vertices[vertexIndex++] = curPos.z; - vertices[vertexIndex++] = curUV.x; - vertices[vertexIndex++] = curUV.y; - } - - return vertexIndex; - } - - drawBatches(camera: Camera): void { - const { _engine: engine, _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; - const mesh = this._meshes[this._flushId]; - const subMeshes = mesh.subMeshes; - const sceneData = camera.scene.shaderData; - const cameraData = camera.shaderData; - - for (let i = 0, len = subMeshes.length; i < len; i++) { - const subMesh = subMeshes[i]; - const spriteMaskElement = batchedQueue[i]; - const stencilOp = stencilOps[i]; - const renderData = spriteMaskElement.data; - - if (!subMesh || !spriteMaskElement) { - return; - } - - const renderer = renderData.component; - const material = renderData.material; - - const compileMacros = Shader._compileMacros; - // union render global macro and material self macro. - ShaderMacroCollection.unionCollection( - renderer._globalShaderMacro, - material.shaderData._macroCollection, - compileMacros - ); - - // Update stencil state - const stencilState = material.renderState.stencilState; - stencilState.passOperationFront = stencilOp; - stencilState.passOperationBack = stencilOp; - - const pass = material.shader.subShaders[0].passes[0]; - const program = pass._getShaderProgram(engine, compileMacros); - if (!program.isValid) { - return; - } - - program.bind(); - program.groupingOtherUniformBlock(); - program.uploadAll(program.sceneUniformBlock, sceneData); - program.uploadAll(program.cameraUniformBlock, cameraData); - program.uploadAll(program.rendererUniformBlock, renderer.shaderData); - program.uploadAll(program.materialUniformBlock, material.shaderData); - - material.renderState._apply(engine, false, pass._renderStateDataMap, material.shaderData); - - engine._hardwareRenderer.drawPrimitive(mesh._primitive, subMesh, program); - } - } - - /** - * @internal - * Standalone for canvas 2d renderer plugin. - */ - _initMeshes(engine: Engine) { - const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 5); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 1.5); - - const { _meshes, _meshCount } = this; - for (let i = 0; i < _meshCount; i++) { - _meshes[i] = this._createMesh(engine, i); - } - } - - private _createMesh(engine: Engine, index: number): BufferMesh { - const { MAX_VERTEX_COUNT } = SpriteMaskBatcher; - const mesh = new BufferMesh(engine, `BufferMesh${index}`); - mesh.isGCIgnored = true; - const vertexElements: VertexElement[] = []; - const vertexStride = this.createVertexElements(vertexElements); - - // vertices - const vertexBuffer = (this._vertexBuffers[index] = new Buffer( - engine, - BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, - BufferUsage.Dynamic - )); - vertexBuffer.isGCIgnored = true; - // indices - const indiceBuffer = (this._indiceBuffers[index] = new Buffer( - engine, - BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 3, - BufferUsage.Dynamic - )); - indiceBuffer.isGCIgnored = true; - mesh.setVertexBufferBinding(vertexBuffer, vertexStride); - mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); - mesh.setVertexElements(vertexElements); - - return mesh; - } - - private _updateData(engine: Engine): void { - const { _meshes, _flushId } = this; - - if (!SpriteMaskBatcher._canUploadSameBuffer && this._meshCount <= _flushId) { - this._meshCount++; - _meshes[_flushId] = this._createMesh(engine, _flushId); - } - - const { _batchedQueue: batchedQueue, _stencilOps: stencilOps, _vertices: vertices, _indices: indices } = this; - const mesh = _meshes[_flushId]; - mesh.clearSubMesh(); - - let vertexIndex = 0; - let indiceIndex = 0; - let vertexStartIndex = 0; - let vertexCount = 0; - let curIndiceStartIndex = 0; - let curMeshIndex = 0; - let preElement: RenderElement = null; - let preStencilOp: StencilOperation = null; - for (let i = 0, len = batchedQueue.length; i < len; i++) { - const curElement = batchedQueue[i]; - const curStencilOp = stencilOps[i]; - const curData = curElement.data; - - // Batch vertex - vertexIndex = this.updateVertices(curData, vertices, vertexIndex); - - // Batch indice - const { triangles } = curData.verticesData; - const triangleNum = triangles.length; - for (let j = 0; j < triangleNum; j++) { - indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; - } - - curIndiceStartIndex += curData.verticesData.vertexCount; - - if (preElement === null) { - vertexCount += triangleNum; - } else { - if (this.canBatch(preElement, curElement, preStencilOp, curStencilOp)) { - vertexCount += triangleNum; - } else { - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - vertexStartIndex += vertexCount; - vertexCount = triangleNum; - batchedQueue[curMeshIndex++] = preElement; - } - } - - preElement = curElement; - preStencilOp = curStencilOp; - } - - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - batchedQueue[curMeshIndex] = preElement; - - this._vertexBuffers[_flushId].setData(vertices, 0, 0, vertexIndex); - this._indiceBuffers[_flushId].setData(indices, 0, 0, indiceIndex); - } - - private _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } -} From 094b5e6913cecc95bd1ccb0dbc36239e9b310e84 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 5 Mar 2024 11:03:07 +0800 Subject: [PATCH 014/218] refactor(2d-render-pipeline): complete sprite renderer and sprite mask --- packages/core/src/2d/assembler/IAssembler.ts | 1 + .../src/2d/assembler/SimpleSpriteAssembler.ts | 63 ++++-- packages/core/src/2d/data/VertexData2D.ts | 12 +- packages/core/src/2d/sprite/SpriteMask.ts | 5 +- packages/core/src/2d/sprite/SpriteRenderer.ts | 17 +- .../src/RenderPipeline/SpriteRenderData.ts | 21 +- .../src/RenderPipeline/batcher/Batcher2D.ts | 181 ++++++++---------- .../src/RenderPipeline/batcher/MeshBuffer.ts | 149 +++++++++++++- .../batcher/SpriteMaskBatcher.ts | 169 ++++++---------- packages/core/src/utils/Pool.ts | 35 ++++ 10 files changed, 408 insertions(+), 245 deletions(-) create mode 100644 packages/core/src/utils/Pool.ts diff --git a/packages/core/src/2d/assembler/IAssembler.ts b/packages/core/src/2d/assembler/IAssembler.ts index 839e8395a1..de3ee30750 100644 --- a/packages/core/src/2d/assembler/IAssembler.ts +++ b/packages/core/src/2d/assembler/IAssembler.ts @@ -7,4 +7,5 @@ export interface IAssembler { resetData(renderer: Renderer): void; updatePositions?(renderer: Renderer): void; updateUVs?(renderer: Renderer): void; + updateColor?(renderer: Renderer): void; } diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index e135e77d9a..f48593a5b1 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -1,4 +1,4 @@ -import { BoundingBox, Matrix, Vector2, Vector3 } from "@galacean/engine-math"; +import { BoundingBox, Matrix } from "@galacean/engine-math"; import { StaticInterfaceImplement } from "../../base/StaticInterfaceImplement"; import { SpriteMask } from "../sprite"; import { SpriteRenderer } from "../sprite/SpriteRenderer"; @@ -13,14 +13,19 @@ export class SimpleSpriteAssembler { static _worldMatrix: Matrix = new Matrix(); static resetData(renderer: SpriteRenderer | SpriteMask): void { + const batcher = + renderer instanceof SpriteRenderer + ? renderer.engine._batcherManager._batcher2D + : renderer.engine._spriteMaskManager._batcher; const { _verticesData: verticesData } = renderer; - const { positions, uvs } = verticesData; - verticesData.vertexCount = positions.length = uvs.length = 4; - for (let i = 0; i < 4; i++) { - positions[i] ||= new Vector3(); - uvs[i] ||= new Vector2(); + verticesData.vertexCount = 4; + if (verticesData.mbChunk) { + batcher.freeChunk(verticesData.mbChunk); + verticesData.mbChunk = batcher.allocateChunk(4, 6); + } else { + verticesData.mbChunk = batcher.allocateChunk(4, 6); } - verticesData.triangles = SimpleSpriteAssembler._rectangleTriangles; + verticesData.mbChunk._indices = SimpleSpriteAssembler._rectangleTriangles; } static updatePositions(renderer: SpriteRenderer | SpriteMask): void { @@ -47,10 +52,15 @@ export class SimpleSpriteAssembler { // --------------- // Update positions. const spritePositions = sprite._getPositions(); - const { positions } = renderer._verticesData; - for (let i = 0; i < 4; i++) { + const { mbChunk: chunk } = renderer._verticesData; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { const { x, y } = spritePositions[i]; - positions[i].set(wE[0] * x + wE[4] * y + wE[12], wE[1] * x + wE[5] * y + wE[13], wE[2] * x + wE[6] * y + wE[14]); + vertices[index] = wE[0] * x + wE[4] * y + wE[12]; + vertices[index + 1] = wE[1] * x + wE[5] * y + wE[13]; + vertices[index + 2] = wE[2] * x + wE[6] * y + wE[14]; + index += 9; } BoundingBox.transform(sprite._getBounds(), worldMatrix, renderer._bounds); @@ -58,12 +68,35 @@ export class SimpleSpriteAssembler { static updateUVs(renderer: SpriteRenderer | SpriteMask): void { const spriteUVs = renderer.sprite._getUVs(); - const renderUVs = renderer._verticesData.uvs; const { x: left, y: bottom } = spriteUVs[0]; const { x: right, y: top } = spriteUVs[3]; - renderUVs[0].set(left, bottom); - renderUVs[1].set(right, bottom); - renderUVs[2].set(left, top); - renderUVs[3].set(right, top); + const { mbChunk: chunk } = renderer._verticesData; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start + 3; + vertices[index] = left; + vertices[index + 1] = bottom; + index += 9; + vertices[index] = right; + vertices[index + 1] = bottom; + index += 9; + vertices[index] = left; + vertices[index + 1] = top; + index += 9; + vertices[index] = right; + vertices[index + 1] = top; + } + + static updateColor(renderer: SpriteRenderer): void { + const { mbChunk: chunk } = renderer._verticesData; + const { color } = renderer; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start + 5; + for (let i = 0; i < 4; ++i) { + vertices[index] = color.r; + vertices[index + 1] = color.g; + vertices[index + 2] = color.b; + vertices[index + 3] = color.a; + index += 9; + } } } diff --git a/packages/core/src/2d/data/VertexData2D.ts b/packages/core/src/2d/data/VertexData2D.ts index 3ef83911d4..a1c64f5b84 100644 --- a/packages/core/src/2d/data/VertexData2D.ts +++ b/packages/core/src/2d/data/VertexData2D.ts @@ -1,14 +1,10 @@ -import { Color, Vector2, Vector3 } from "@galacean/engine-math"; +import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; /** * @internal */ export class VertexData2D { - constructor( - public vertexCount: number, - public positions: Vector3[], - public uvs: Vector2[], - public triangles: number[] = null, - public color: Color = null - ) {} + public mbChunk: MBChunk = null; + + constructor(public vertexCount: number) {} } diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 4c9e7bd437..8aa6cbbd71 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -169,7 +169,7 @@ export class SpriteMask extends Renderer { */ constructor(entity: Entity) { super(entity); - this._verticesData = new VertexData2D(4, [], []); + this._verticesData = new VertexData2D(4); SimpleSpriteAssembler.resetData(this); this.setMaterial(this._engine._spriteMaskDefaultMaterial); this.shaderData.setFloat(SpriteMask._alphaCutoffProperty, this._alphaCutoff); @@ -221,7 +221,8 @@ export class SpriteMask extends Renderer { engine._spriteMaskManager.addMask(this); const renderData = engine._spriteRenderDataPool.getFromPool(); const material = this.getMaterial(); - renderData.setX(this, material, this._verticesData, this.sprite.texture); + const { mbChunk: chunk } = this._verticesData; + renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, this.sprite.texture, chunk); renderData.usage = RenderDataUsage.SpriteMask; const renderElement = engine._renderElementPool.getFromPool(); diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index d335b9cfe6..897be5c7bb 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -158,6 +158,7 @@ export class SpriteRenderer extends Renderer { set color(value: Color) { if (this._color !== value) { this._color.copyFrom(value); + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.Color; } } @@ -265,8 +266,9 @@ export class SpriteRenderer extends Renderer { */ constructor(entity: Entity) { super(entity); - this._verticesData = new VertexData2D(4, [], [], null, this._color); + this._verticesData = new VertexData2D(4); this.drawMode = SpriteDrawMode.Simple; + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.Color; this.setMaterial(this._engine._spriteDefaultMaterial); this._onSpriteChange = this._onSpriteChange.bind(this); } @@ -321,11 +323,18 @@ export class SpriteRenderer extends Renderer { this._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.UV; } + // Update color + if (this._dirtyUpdateFlag & SpriteRendererUpdateFlags.Color) { + this._assembler.updateColor(this); + this._dirtyUpdateFlag &= ~SpriteRendererUpdateFlags.Color; + } + // Push primitive const { engine } = context.camera; const material = this.getMaterial(); const renderData = engine._spriteRenderDataPool.getFromPool(); - renderData.setX(this, material, this._verticesData, this.sprite.texture); + const { mbChunk: chunk } = this._verticesData; + renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, this.sprite.texture, chunk); renderData.usage = RenderDataUsage.Sprite; engine._batcherManager.commitRenderData(context, renderData); } @@ -432,5 +441,7 @@ enum SpriteRendererUpdateFlags { /** Automatic Size. */ AutomaticSize = 0x4, /** All. */ - All = 0x7 + All = 0x7, + /** Color. */ + Color = 0x8 } diff --git a/packages/core/src/RenderPipeline/SpriteRenderData.ts b/packages/core/src/RenderPipeline/SpriteRenderData.ts index af4088048d..f338362373 100644 --- a/packages/core/src/RenderPipeline/SpriteRenderData.ts +++ b/packages/core/src/RenderPipeline/SpriteRenderData.ts @@ -1,28 +1,35 @@ -import { VertexData2D } from "../2d/data/VertexData2D"; +import { Primitive, SubMesh } from "../graphic"; import { Material } from "../material/Material"; import { Renderer } from "../Renderer"; import { Texture2D } from "../texture"; +import { MBChunk } from "./batcher/MeshBuffer"; import { RenderDataUsage } from "./enums/RenderDataUsage"; import { IPoolElement } from "./IPoolElement"; import { RenderData } from "./RenderData"; export class SpriteRenderData extends RenderData implements IPoolElement { - verticesData: VertexData2D; texture: Texture2D; + chunk: MBChunk; constructor() { super(); this.usage = RenderDataUsage.Sprite; } - setX(component: Renderer, material: Material, verticesData: VertexData2D, texture: Texture2D): void { - this.component = component; - this.material = material; - this.verticesData = verticesData; + override set( + component: Renderer, + material: Material, + primitive: Primitive, + subPrimitive: SubMesh, + texture?: Texture2D, + chunk?: MBChunk + ): void { + super.set(component, material, primitive, subPrimitive); this.texture = texture; + this.chunk = chunk; } override dispose(): void { - this.component = this.material = this.verticesData = this.texture = null; + this.component = this.material = this.texture = this.chunk = null; } } diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 6f63d6ede6..2808021cb7 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,13 +1,12 @@ import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; import { Engine } from "../../Engine"; -import { MeshTopology, SetDataOptions, SubMesh } from "../../graphic"; +import { MeshTopology, SubMesh } from "../../graphic"; import { ShaderProperty, ShaderTagKey } from "../../shader"; import { ClassPool } from "../ClassPool"; import { RenderContext } from "../RenderContext"; import { SpriteRenderData } from "../SpriteRenderData"; -import { RenderDataUsage } from "../enums/RenderDataUsage"; import { IBatcher } from "./IBatcher"; -import { MeshBuffer } from "./MeshBuffer"; +import { MBChunk, MeshBuffer } from "./MeshBuffer"; /** * @internal @@ -27,28 +26,13 @@ export class Batcher2D implements IBatcher { /** @internal */ _meshBuffers: MeshBuffer[] = []; /** @internal */ - _flushId: number = 0; - - /** @internal */ - _vStartIndex: number = 0; - /** @internal */ - _vIndex: number = 0; - /** @internal */ - _iStartIndex: number = 0; - /** @internal */ - _iIndex: number = 0; - /** @internal */ - _vertexStartIndex: number = 0; - /** @internal */ - _vertexCount: number = 0; - /** @internal */ _preContext: RenderContext = null; /** @internal */ - _preSpriteRenderData: SpriteRenderData = null; + _preRenderData: SpriteRenderData = null; constructor(engine: Engine) { this._engine = engine; - this._createMeshBuffer(engine, 0); + this._createMeshBuffer(0); } /** @@ -64,72 +48,76 @@ export class Batcher2D implements IBatcher { } commitRenderData(context: RenderContext, data: SpriteRenderData): void { - if (this._preSpriteRenderData) { - if (this._vertexCount + data.verticesData.vertexCount > Batcher2D.MAX_VERTEX_COUNT) { - this.flush(); - this.uploadBuffer(); - const newFlushId = this._flushId + 1; - this._createMeshBuffer(this._engine, newFlushId); - this._reset(); - this._flushId = newFlushId; + const { _preRenderData: preRenderData } = this; + if (preRenderData) { + if (this._canBatch(preRenderData, data)) { + this._udpateRenderData(context, preRenderData, data, true); } else { - if (!this._canBatch(this._preSpriteRenderData, data)) { - this.flush(); - } + this.flush(); + this._udpateRenderData(context, preRenderData, data, false); } + } else { + this._udpateRenderData(context, preRenderData, data, false); } - - this._preContext = context; - this._preSpriteRenderData = data; - this._fillRenderData(data); } flush(): void { - if (!this._preSpriteRenderData) { - return; + const { _preRenderData: preRenderData } = this; + if (preRenderData) { + preRenderData.component.shaderData.setTexture(Batcher2D._textureProperty, preRenderData.texture); + this._preContext.camera._renderPipeline.pushRenderData(this._preContext, preRenderData); } - - const { _preSpriteRenderData, _iStartIndex, _iIndex } = this; - const mesh = this._meshBuffers[this._flushId]._mesh; - const iCount = _iIndex - _iStartIndex; - const subMesh = this._getSubMeshFromPool(_iStartIndex, iCount); - mesh.addSubMesh(subMesh); - - this._vertexStartIndex += this._vertexCount; - this._vStartIndex = this._vIndex; - this._iStartIndex = _iIndex; - - const renderData = this._engine._renderDataPool.getFromPool(); - renderData.usage = RenderDataUsage.Sprite; - renderData.set(_preSpriteRenderData.component, _preSpriteRenderData.material, mesh._primitive, subMesh); - renderData.component.shaderData.setTexture(Batcher2D._textureProperty, _preSpriteRenderData.texture); - this._preContext.camera._renderPipeline.pushRenderData(this._preContext, renderData); } uploadBuffer(): void { - this._meshBuffers[this._flushId].uploadBuffer(this._vStartIndex, this._iStartIndex); + const { _meshBuffers: meshBuffers } = this; + for (let i = 0, l = meshBuffers.length; i < l; ++i) { + meshBuffers[i].uploadBuffer(); + } } clear() { this._reset(); - this._subMeshPool.resetPool(); + const { _meshBuffers: meshBuffers } = this; + for (let i = 0, l = meshBuffers.length; i < l; ++i) { + meshBuffers[i].clear(); + } + } + + allocateChunk(vertexCount, indiceCount): MBChunk | null { const { _meshBuffers } = this; - for (let i = 0, l = _meshBuffers.length; i < l; ++i) { - _meshBuffers[i]._mesh.clearSubMesh(); + let chunk: MBChunk = null; + let i = 0; + const len = _meshBuffers.length; + for (; i < len; ++i) { + chunk = _meshBuffers[i].allocateChunk(vertexCount, indiceCount); + if (chunk) { + chunk._mbId = i; + return chunk; + } + } + + const meshBuffer = this._createMeshBuffer(len); + chunk = meshBuffer.allocateChunk(vertexCount, indiceCount); + if (chunk) { + chunk._mbId = len; + return chunk; } + return null; } - getInfo(vertexCount, indiceCount) { - // TODO + freeChunk(chunk: MBChunk): void { + const meshBuffer = this._meshBuffers[chunk._mbId]; + meshBuffer && meshBuffer.freeChunk(chunk); } - protected _createMeshBuffer(engine: Engine, index: number): MeshBuffer { + protected _createMeshBuffer(index: number): MeshBuffer { const { _meshBuffers } = this; if (_meshBuffers[index]) { return _meshBuffers[index]; } - const meshBuffer = (_meshBuffers[index] = new MeshBuffer(engine)); + const meshBuffer = (_meshBuffers[index] = new MeshBuffer(this._engine)); return meshBuffer; } @@ -142,6 +130,10 @@ export class Batcher2D implements IBatcher { } private _canBatch(preRenderData: SpriteRenderData, curRenderData: SpriteRenderData): boolean { + if (preRenderData.chunk._meshBuffer !== curRenderData.chunk._meshBuffer) { + return false; + } + const preRender = preRenderData.component; const curRender = curRenderData.component; @@ -171,45 +163,40 @@ export class Batcher2D implements IBatcher { return left.maskLayer === right.maskLayer; } - private _fillRenderData(data: SpriteRenderData): void { - const { _flushId, _vertexCount } = this; - const { positions, uvs, color, vertexCount, triangles } = data.verticesData; - - let index = this._vIndex; - const _vertices = this._meshBuffers[_flushId]._vertices; - const _indices = this._meshBuffers[_flushId]._indices; - for (let i = 0; i < vertexCount; ++i) { - const curPos = positions[i]; - const curUV = uvs[i]; - _vertices[index++] = curPos.x; - _vertices[index++] = curPos.y; - _vertices[index++] = curPos.z; - _vertices[index++] = curUV.x; - _vertices[index++] = curUV.y; - _vertices[index++] = color.r; - _vertices[index++] = color.g; - _vertices[index++] = color.b; - _vertices[index++] = color.a; - } - this._vIndex = index; - - index = this._iIndex; - for (let i = 0, len = triangles.length; i < len; ++i) { - _indices[index++] = triangles[i] + _vertexCount; - } - this._iIndex = index; - this._vertexCount += vertexCount; + private _udpateRenderData( + context: RenderContext, + preRenderData: SpriteRenderData, + curRenderData: SpriteRenderData, + canBatch: boolean + ): void { + const { chunk } = curRenderData; + const { _meshBuffer: meshBuffer, _indices: tempIndices, _vEntry: vEntry } = chunk; + const { _indices: indices } = meshBuffer; + const vertexStartIndex = vEntry.start / 9; + const len = tempIndices.length; + let startIndex = meshBuffer._iLen; + if (canBatch) { + const { _subMesh } = preRenderData.chunk; + _subMesh.count += len; + } else { + const { _subMesh } = chunk; + _subMesh.start = startIndex; + _subMesh.count = len; + meshBuffer._mesh.addSubMesh(_subMesh); + } + for (let i = 0; i < len; ++i) { + indices[startIndex++] = vertexStartIndex + tempIndices[i]; + } + meshBuffer._iLen += len; + meshBuffer._vLen = Math.max(meshBuffer._vLen, vEntry.start + vEntry.len); + if (!canBatch) { + this._preContext = context; + this._preRenderData = curRenderData; + } } private _reset(): void { - this._flushId = 0; - this._vIndex = 0; - this._iIndex = 0; - this._vStartIndex = 0; - this._iStartIndex = 0; - this._vertexStartIndex = 0; - this._vertexCount = 0; this._preContext = null; - this._preSpriteRenderData = null; + this._preRenderData = null; } } diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index df206ef759..9465165d70 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -4,13 +4,47 @@ import { BufferBindFlag, BufferUsage, IndexFormat, + MeshTopology, SetDataOptions, + SubMesh, VertexElement, VertexElementFormat } from "../../graphic"; import { BufferMesh } from "../../mesh"; +import { Pool } from "../../utils/Pool"; +import { IPoolElement } from "../IPoolElement"; import { Batcher2D } from "./Batcher2D"; +/** + * @internal + */ +export class MBChunk implements IPoolElement { + _mbId: number = -1; + _meshBuffer: MeshBuffer; + _subMesh: SubMesh; + _vEntry: Entry; + _indices: number[]; + + reset() { + this._mbId = -1; + // TODO + } + + dispose?(): void {} +} + +/** + * @internal + */ +class Entry implements IPoolElement { + constructor( + public start: number = -1, + public len: number = 0 + ) {} + + dispose?(): void {} +} + /** * @internal */ @@ -26,6 +60,22 @@ export class MeshBuffer { /** @internal */ _indices: Uint16Array; + /** @internal */ + _vLen: number = 0; // _vertices 需要上传的数据长度 + /** @internal */ + _iLen: number = 0; // _indices 需要上传的数据长度 + + /** @internal */ + _vFreeEntries: Entry[] = []; + /** @internal */ + _iFreeEntries: Entry[] = []; + /** @internal */ + _entryPool: Pool = new Pool(Entry, 10); + /** @internal */ + _chunkPool: Pool = new Pool(MBChunk, 10); + /** @internal */ + _subMeshPool: Pool = new Pool(SubMesh, 10); + constructor(engine: Engine) { const mesh = (this._mesh = new BufferMesh(engine)); mesh.isGCIgnored = true; @@ -41,7 +91,6 @@ export class MeshBuffer { BufferUsage.Dynamic )); vertexBuffer.isGCIgnored = true; - this._vertices = new Float32Array(MAX_VERTEX_COUNT * 9); // indices const indiceBuffer = (this._iBuffer = new Buffer( engine, @@ -53,7 +102,13 @@ export class MeshBuffer { mesh.setVertexBufferBinding(vertexBuffer, vertexStride); mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); mesh.setVertexElements(vertexElements); - this._indices = new Uint16Array(MAX_VERTEX_COUNT * 4); + + const vertexLen = MAX_VERTEX_COUNT * 9; + const indiceLen = MAX_VERTEX_COUNT * 4; + this._vertices = new Float32Array(vertexLen); + this._indices = new Uint16Array(indiceLen); + this._vFreeEntries.push(new Entry(0, vertexLen)); + this._iFreeEntries.push(new Entry(0, indiceLen)); } destroy(): void { @@ -65,13 +120,44 @@ export class MeshBuffer { this._iBuffer = null; this._vertices = null; this._indices = null; + this._entryPool.garbageCollection(); + this._entryPool = null; + } + + clear(): void { + this._mesh.clearSubMesh(); + this._vLen = this._iLen = 0; } - uploadBuffer(vLen: number, iLen: number): void { + uploadBuffer(): void { // Set data option use Discard, or will resulted in performance slowdown when open antialias and cross-rendering of 3D and 2D elements. // Device: iphone X(16.7.2)、iphone 15 pro max(17.1.1)、iphone XR(17.1.2) etc. - this._vBuffer.setData(this._vertices, 0, 0, vLen, SetDataOptions.Discard); - this._iBuffer.setData(this._indices, 0, 0, iLen, SetDataOptions.Discard); + this._vBuffer.setData(this._vertices, 0, 0, this._vLen, SetDataOptions.Discard); + this._iBuffer.setData(this._indices, 0, 0, this._iLen, SetDataOptions.Discard); + } + + allocateChunk(vertexCount: number, indiceCount: number): MBChunk | null { + const vEntry = this._allocateEntry(this._vFreeEntries, vertexCount * 9); + if (vEntry) { + const chunk = this._chunkPool.alloc(); + chunk._meshBuffer = this; + chunk._vEntry = vEntry; + chunk._subMesh = this._subMeshPool.alloc(); + const { _subMesh: subMesh } = chunk; + subMesh.topology = MeshTopology.Triangles; + return chunk; + } + + return null; + } + + freeChunk(chunk: MBChunk): void { + this._freeEntry(this._vFreeEntries, chunk._vEntry); + this._subMeshPool.free(chunk._subMesh); + chunk._vEntry = null; + chunk._subMesh = null; + chunk._indices = null; + this._chunkPool.free(chunk); } createVertexElements(vertexElements: VertexElement[]): number { @@ -80,4 +166,57 @@ export class MeshBuffer { vertexElements[2] = new VertexElement("COLOR_0", 20, VertexElementFormat.Vector4, 0); return 36; } + + private _allocateEntry(entries: Entry[], needLen: number): Entry | null { + const { _entryPool: pool } = this; + for (let i = 0, l = entries.length; i < l; ++i) { + const entry = entries[i]; + const len = entry.len; + if (len > needLen) { + const newEntry = pool.alloc(); + newEntry.start = entry.start; + newEntry.len = needLen; + entry.start += needLen; + entry.len -= needLen; + return newEntry; + } else if (len === needLen) { + entries.splice(i, 1); + return entry; + } + } + return null; + } + + private _freeEntry(entries: Entry[], entry: Entry): void { + const entryLen = entries.length; + if (entryLen === 0) { + entries.push(entry); + return; + } + + const { _entryPool: pool } = this; + let preEntry = entry; + for (let i = 0; i < entryLen; ++i) { + const curEntry = entries[i]; + const { start, len } = preEntry; + const preEnd = start + len; + const curEnd = curEntry.start + curEntry.len; + if (preEnd < curEntry.start) { + entries.splice(i, 0, preEntry); + return; + } else if (preEnd === curEntry.start) { + curEntry.start = preEntry.start; + curEntry.len += preEntry.len; + pool.free(preEntry); + preEntry = curEntry; + } else if (start === curEnd) { + curEntry.len += preEntry.len; + pool.free(preEntry); + preEntry = curEntry; + } else if (start > curEnd) { + entries.splice(i + 1, 0, preEntry); + preEntry = curEntry; + } + } + } } diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index 0a593678c1..0bdd7aa3eb 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -9,57 +9,51 @@ import { SpriteRenderData } from "../SpriteRenderData"; import { Batcher2D } from "./Batcher2D"; export class SpriteMaskBatcher extends Batcher2D { - static override MAX_VERTEX_COUNT: number = 128; - static _canUploadSameBuffer: boolean = true; - /** @internal */ _batchedQueue: RenderElement[] = []; /** @internal */ _stencilOps: StencilOperation[] = []; /** @internal */ - _elementCount: number = 0; + _preRenderElement: RenderElement = null; + /** @internal */ + _preOp: StencilOperation = null; constructor(engine: Engine) { super(engine); } drawElement(element: RenderElement, camera: Camera, op: StencilOperation): void { - const vertexCount = (element.data).verticesData.vertexCount; - if (this._vertexCount + vertexCount > SpriteMaskBatcher.MAX_VERTEX_COUNT) { - this.uploadAndDraw(camera); + const { _preRenderElement: preRenderElement } = this; + if (preRenderElement) { + if (this.canBatch(preRenderElement, element, this._preOp, op)) { + this._updateRenderElement(preRenderElement, element, true, op); + } else { + this._batchedQueue.push(preRenderElement); + this._stencilOps.push(this._preOp); + this._updateRenderElement(preRenderElement, element, false, op); + } + } else { + this._updateRenderElement(preRenderElement, element, false, op); } - - this._vertexCount += vertexCount; - this._batchedQueue[this._elementCount] = element; - this._stencilOps[this._elementCount++] = op; } uploadAndDraw(camera: Camera): void { - const batchedQueue = this._batchedQueue; - - if (batchedQueue.length === 0) { - return; - } - this._updateData(this._engine); - this.drawBatches(camera); - - if (!SpriteMaskBatcher._canUploadSameBuffer) { - this._flushId++; + const { _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; + if (this._preRenderElement) { + batchedQueue.push(this._preRenderElement); + stencilOps.push(this._preOp); } - batchedQueue.length = 0; - this._stencilOps.length = 0; - this._subMeshPool.resetPool(); - this._vertexCount = 0; - this._elementCount = 0; + this.uploadBuffer(); + this.drawBatches(camera); } override clear(): void { super.clear(); - this._vertexCount = 0; - this._elementCount = 0; this._batchedQueue.length = 0; this._stencilOps.length = 0; + this._preRenderElement = null; + this._preOp = null; } override destroy(): void { @@ -77,6 +71,10 @@ export class SpriteMaskBatcher extends Batcher2D { const preSpriteData = preElement.data; const curSpriteData = curElement.data; + if (preSpriteData.chunk._meshBuffer !== curSpriteData.chunk._meshBuffer) { + return false; + } + if (preStencilOp !== curStencilOp) { return false; } @@ -93,39 +91,19 @@ export class SpriteMaskBatcher extends Batcher2D { ); } - updateVertices(element: SpriteRenderData, vertices: Float32Array, vertexIndex: number): number { - const { positions, uvs, vertexCount } = element.verticesData; - for (let i = 0; i < vertexCount; i++) { - const curPos = positions[i]; - const curUV = uvs[i]; - vertices[vertexIndex++] = curPos.x; - vertices[vertexIndex++] = curPos.y; - vertices[vertexIndex++] = curPos.z; - vertices[vertexIndex++] = curUV.x; - vertices[vertexIndex++] = curUV.y; - vertices[vertexIndex++] = 1; - vertices[vertexIndex++] = 1; - vertices[vertexIndex++] = 1; - vertices[vertexIndex++] = 1; - } - - return vertexIndex; - } - drawBatches(camera: Camera): void { const { _engine: engine, _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; - const mesh = this._meshBuffers[this._flushId]._mesh; - const subMeshes = mesh.subMeshes; const sceneData = camera.scene.shaderData; const cameraData = camera.shaderData; - for (let i = 0, len = subMeshes.length; i < len; i++) { - const subMesh = subMeshes[i]; + for (let i = 0, len = batchedQueue.length; i < len; i++) { + // const subMesh = subMeshes[i]; const spriteMaskElement = batchedQueue[i]; const stencilOp = stencilOps[i]; const renderData = spriteMaskElement.data; + const mesh = renderData.chunk._meshBuffer._mesh; - if (!subMesh || !spriteMaskElement) { + if (!spriteMaskElement) { return; } @@ -160,66 +138,41 @@ export class SpriteMaskBatcher extends Batcher2D { material.renderState._apply(engine, false, pass._renderStateDataMap, material.shaderData); - engine._hardwareRenderer.drawPrimitive(mesh._primitive, subMesh, program); + engine._hardwareRenderer.drawPrimitive(mesh._primitive, renderData.chunk._subMesh, program); } } - private _updateData(engine: Engine): void { - const { _meshBuffers, _flushId } = this; - - if (!SpriteMaskBatcher._canUploadSameBuffer && _meshBuffers.length <= _flushId) { - this._createMeshBuffer(engine, _flushId); + private _updateRenderElement( + preRenderElement: RenderElement, + curRenderElement: RenderElement, + canBatch: boolean, + op: StencilOperation + ): void { + const curRenderData = curRenderElement.data; + const { chunk } = curRenderData; + const { _meshBuffer: meshBuffer, _indices: tempIndices, _vEntry: vEntry } = chunk; + const { _indices: indices } = meshBuffer; + const vertexStartIndex = vEntry.start / 9; + const len = tempIndices.length; + let startIndex = meshBuffer._iLen; + if (canBatch) { + const preRenderData = preRenderElement.data; + const { _subMesh } = preRenderData.chunk; + _subMesh.count += len; + } else { + const { _subMesh } = chunk; + _subMesh.start = startIndex; + _subMesh.count = len; + meshBuffer._mesh.addSubMesh(_subMesh); } - - const { _batchedQueue: batchedQueue, _stencilOps: stencilOps } = this; - const meshBuffer = _meshBuffers[_flushId]; - const { _vertices: vertices, _indices: indices, _mesh: mesh } = meshBuffer; - mesh.clearSubMesh(); - - let vertexIndex = 0; - let indiceIndex = 0; - let vertexStartIndex = 0; - let vertexCount = 0; - let curIndiceStartIndex = 0; - let curMeshIndex = 0; - let preElement: RenderElement = null; - let preStencilOp: StencilOperation = null; - for (let i = 0, len = batchedQueue.length; i < len; i++) { - const curElement = batchedQueue[i]; - const curStencilOp = stencilOps[i]; - const curData = curElement.data; - - // Batch vertex - vertexIndex = this.updateVertices(curData, vertices, vertexIndex); - - // Batch indice - const { triangles } = curData.verticesData; - const triangleNum = triangles.length; - for (let j = 0; j < triangleNum; j++) { - indices[indiceIndex++] = triangles[j] + curIndiceStartIndex; - } - - curIndiceStartIndex += curData.verticesData.vertexCount; - - if (preElement === null) { - vertexCount += triangleNum; - } else { - if (this.canBatch(preElement, curElement, preStencilOp, curStencilOp)) { - vertexCount += triangleNum; - } else { - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - vertexStartIndex += vertexCount; - vertexCount = triangleNum; - batchedQueue[curMeshIndex++] = preElement; - } - } - - preElement = curElement; - preStencilOp = curStencilOp; + for (let i = 0; i < len; ++i) { + indices[startIndex++] = vertexStartIndex + tempIndices[i]; + } + meshBuffer._iLen += len; + meshBuffer._vLen = Math.max(meshBuffer._vLen, vEntry.start + vEntry.len); + if (!canBatch) { + this._preRenderElement = curRenderElement; + this._preOp = op; } - - mesh.addSubMesh(this._getSubMeshFromPool(vertexStartIndex, vertexCount)); - batchedQueue[curMeshIndex] = preElement; - meshBuffer.uploadBuffer(vertexIndex, indiceIndex); } } diff --git a/packages/core/src/utils/Pool.ts b/packages/core/src/utils/Pool.ts new file mode 100644 index 0000000000..d41f2ee5ee --- /dev/null +++ b/packages/core/src/utils/Pool.ts @@ -0,0 +1,35 @@ +import { IPoolElement } from "../RenderPipeline/IPoolElement"; + +export class Pool { + private _type: new () => T; + private _elementPool: T[] = []; + private _elementPoolIndex: number; + + constructor(type: new () => T, count: number = 1) { + this._type = type; + this._elementPoolIndex = count - 1; + const { _elementPool } = this; + for (let i = 0; i < count; ++i) { + _elementPool.push(new type()); + } + } + + alloc(): T { + if (this._elementPoolIndex < 0) { + return new this._type(); + } + return this._elementPool[this._elementPoolIndex--]; + } + + free(element: T): void { + this._elementPool[++this._elementPoolIndex] = element; + } + + garbageCollection(): void { + const { _elementPool: pool } = this; + for (let i = pool.length - 1; i >= 0; i--) { + pool[i].dispose && pool[i].dispose(); + } + pool.length = 0; + } +} From 04eb47c48843cb103a6a32b28c2ddd91b6fc7cde Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 5 Mar 2024 16:05:29 +0800 Subject: [PATCH 015/218] refactor(2d-render-pipeline): complete sprite renderer draw mode --- packages/core/src/2d/assembler/IAssembler.ts | 2 +- .../src/2d/assembler/SimpleSpriteAssembler.ts | 20 ++- .../src/2d/assembler/SlicedSpriteAssembler.ts | 64 +++++--- .../src/2d/assembler/TiledSpriteAssembler.ts | 143 ++++++++++++------ packages/core/src/2d/data/VertexData2D.ts | 2 +- packages/core/src/2d/sprite/SpriteMask.ts | 12 +- packages/core/src/2d/sprite/SpriteRenderer.ts | 12 +- 7 files changed, 167 insertions(+), 88 deletions(-) diff --git a/packages/core/src/2d/assembler/IAssembler.ts b/packages/core/src/2d/assembler/IAssembler.ts index de3ee30750..03b8665eaa 100644 --- a/packages/core/src/2d/assembler/IAssembler.ts +++ b/packages/core/src/2d/assembler/IAssembler.ts @@ -4,7 +4,7 @@ import { Renderer } from "../../Renderer"; * @internal */ export interface IAssembler { - resetData(renderer: Renderer): void; + resetData(renderer: Renderer, vCount?: number, iCount?: number): void; updatePositions?(renderer: Renderer): void; updateUVs?(renderer: Renderer): void; updateColor?(renderer: Renderer): void; diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index f48593a5b1..53f117ef6c 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -17,22 +17,20 @@ export class SimpleSpriteAssembler { renderer instanceof SpriteRenderer ? renderer.engine._batcherManager._batcher2D : renderer.engine._spriteMaskManager._batcher; - const { _verticesData: verticesData } = renderer; - verticesData.vertexCount = 4; - if (verticesData.mbChunk) { - batcher.freeChunk(verticesData.mbChunk); - verticesData.mbChunk = batcher.allocateChunk(4, 6); + if (renderer._chunk) { + batcher.freeChunk(renderer._chunk); + renderer._chunk = batcher.allocateChunk(4, 6); } else { - verticesData.mbChunk = batcher.allocateChunk(4, 6); + renderer._chunk = batcher.allocateChunk(4, 6); } - verticesData.mbChunk._indices = SimpleSpriteAssembler._rectangleTriangles; + renderer._chunk._indices = this._rectangleTriangles; } static updatePositions(renderer: SpriteRenderer | SpriteMask): void { const { width, height, sprite } = renderer; const { x: pivotX, y: pivotY } = sprite.pivot; // Renderer's worldMatrix; - const { _worldMatrix: worldMatrix } = SimpleSpriteAssembler; + const { _worldMatrix: worldMatrix } = this; const { elements: wE } = worldMatrix; // Parent's worldMatrix. const { elements: pWE } = renderer.entity.transform.worldMatrix; @@ -52,7 +50,7 @@ export class SimpleSpriteAssembler { // --------------- // Update positions. const spritePositions = sprite._getPositions(); - const { mbChunk: chunk } = renderer._verticesData; + const { _chunk: chunk } = renderer; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start; for (let i = 0; i < 4; ++i) { @@ -70,7 +68,7 @@ export class SimpleSpriteAssembler { const spriteUVs = renderer.sprite._getUVs(); const { x: left, y: bottom } = spriteUVs[0]; const { x: right, y: top } = spriteUVs[3]; - const { mbChunk: chunk } = renderer._verticesData; + const { _chunk: chunk } = renderer; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start + 3; vertices[index] = left; @@ -87,7 +85,7 @@ export class SimpleSpriteAssembler { } static updateColor(renderer: SpriteRenderer): void { - const { mbChunk: chunk } = renderer._verticesData; + const { _chunk: chunk } = renderer; const { color } = renderer; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start + 5; diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts index 19aebf5bcf..c63b73bc0c 100644 --- a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts @@ -2,7 +2,6 @@ import { Matrix, Vector2, Vector3 } from "@galacean/engine-math"; import { StaticInterfaceImplement } from "../../base/StaticInterfaceImplement"; import { SpriteRenderer } from "../sprite/SpriteRenderer"; import { IAssembler } from "./IAssembler"; -import { SimpleSpriteAssembler } from "./SimpleSpriteAssembler"; /** * @internal @@ -14,22 +13,21 @@ export class SlicedSpriteAssembler { 9, 12, 9, 13, 12, 9, 10, 13, 10, 14, 13, 10, 11, 14, 11, 15, 14 ]; static _worldMatrix: Matrix = new Matrix(); + static resetData(renderer: SpriteRenderer): void { - const { _verticesData: verticesData } = renderer; - const { positions, uvs } = verticesData; - verticesData.vertexCount = positions.length = uvs.length = 16; - for (let i = 0; i < 16; i++) { - positions[i] ||= new Vector3(); - uvs[i] ||= new Vector2(); + const batcher = renderer.engine._batcherManager._batcher2D; + if (renderer._chunk) { + batcher.freeChunk(renderer._chunk); + renderer._chunk = batcher.allocateChunk(16, 54); + } else { + renderer._chunk = batcher.allocateChunk(16, 54); } - verticesData.triangles = SlicedSpriteAssembler._rectangleTriangles; + renderer._chunk._indices = this._rectangleTriangles; } static updatePositions(renderer: SpriteRenderer): void { const { width, height, sprite } = renderer; - const { positions, uvs } = renderer._verticesData; const { border } = sprite; - const spriteUVs = sprite._getUVs(); // Update local positions. const spritePositions = sprite._getPositions(); const { x: left, y: bottom } = spritePositions[0]; @@ -81,7 +79,7 @@ export class SlicedSpriteAssembler { const localTransX = renderer.width * pivotX; const localTransY = renderer.height * pivotY; // Renderer's worldMatrix. - const { _worldMatrix: worldMatrix } = SlicedSpriteAssembler; + const { _worldMatrix: worldMatrix } = this; const { elements: wE } = worldMatrix; // Parent's worldMatrix. const { elements: pWE } = renderer.entity.transform.worldMatrix; @@ -104,18 +102,17 @@ export class SlicedSpriteAssembler { // 0 - 4 - 8 - 12 // ------------------------ // Assemble position and uv. + const { _chunk: chunk } = renderer; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start; for (let i = 0; i < 4; i++) { const rowValue = row[i]; - const rowU = spriteUVs[i].x; for (let j = 0; j < 4; j++) { const columnValue = column[j]; - const idx = i * 4 + j; - positions[idx].set( - wE[0] * rowValue + wE[4] * columnValue + wE[12], - wE[1] * rowValue + wE[5] * columnValue + wE[13], - wE[2] * rowValue + wE[6] * columnValue + wE[14] - ); - uvs[idx].set(rowU, spriteUVs[j].y); + vertices[index] = wE[0] * rowValue + wE[4] * columnValue + wE[12]; + vertices[index + 1] = wE[1] * rowValue + wE[5] * columnValue + wE[13]; + vertices[index + 2] = wE[2] * rowValue + wE[6] * columnValue + wE[14]; + index += 9; } } @@ -125,5 +122,32 @@ export class SlicedSpriteAssembler { renderer._bounds.transform(worldMatrix); } - static updateUVs(renderer: SpriteRenderer): void {} + static updateUVs(renderer: SpriteRenderer): void { + const { _chunk: chunk } = renderer; + const vertices = chunk._meshBuffer._vertices; + const spriteUVs = renderer.sprite._getUVs(); + let index = chunk._vEntry.start + 3; + for (let i = 0; i < 4; i++) { + const rowU = spriteUVs[i].x; + for (let j = 0; j < 4; j++) { + vertices[index] = rowU; + vertices[index + 1] = spriteUVs[j].y; + index += 9; + } + } + } + + static updateColor(renderer: SpriteRenderer): void { + const { _chunk: chunk } = renderer; + const { color } = renderer; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start + 5; + for (let i = 0; i < 16; ++i) { + vertices[index] = color.r; + vertices[index + 1] = color.g; + vertices[index + 2] = color.b; + vertices[index + 3] = color.a; + index += 9; + } + } } diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 1aa16cb5be..b3a70e1b07 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -1,4 +1,4 @@ -import { MathUtil, Matrix, Vector2, Vector3 } from "@galacean/engine-math"; +import { MathUtil, Matrix } from "@galacean/engine-math"; import { StaticInterfaceImplement } from "../../base/StaticInterfaceImplement"; import { DisorderedArray } from "../../DisorderedArray"; import { SpriteTileMode } from "../enums/SpriteTileMode"; @@ -19,13 +19,25 @@ export class TiledSpriteAssembler { static _uvRow: DisorderedArray = new DisorderedArray(); static _uvColumn: DisorderedArray = new DisorderedArray(); - static resetData(renderer: SpriteRenderer): void { - renderer._verticesData.triangles = []; + static resetData(renderer: SpriteRenderer, vCount: number, iCount: number): void { + if (vCount && iCount) { + const batcher = renderer.engine._batcherManager._batcher2D; + const { _chunk: chunk } = renderer; + if (chunk) { + if (chunk._vEntry.len !== vCount * 9) { + batcher.freeChunk(chunk); + renderer._chunk = batcher.allocateChunk(vCount, iCount); + renderer._chunk._indices = []; + } + } else { + renderer._chunk = batcher.allocateChunk(vCount, iCount); + renderer._chunk._indices = []; + } + } } static updatePositions(renderer: SpriteRenderer): void { const { width, height, sprite, tileMode, tiledAdaptiveThreshold: threshold } = renderer; - const { positions, uvs, triangles } = renderer._verticesData; // Calculate row and column const { _posRow: posRow, _posColumn: posColumn, _uvRow: uvRow, _uvColumn: uvColumn } = this; posRow.length = posColumn.length = uvRow.length = uvColumn.length = 0; @@ -54,6 +66,30 @@ export class TiledSpriteAssembler { // Assemble position and uv const rowLength = posRow.length - 1; const columnLength = posColumn.length - 1; + + // Calculate total vertex count and indices count, to be optimized. + let vertexCount = 0; + let indicesCount = 0; + for (let j = 0; j < columnLength; j++) { + const doubleJ = 2 * j; + for (let i = 0; i < rowLength; i++) { + const uvL = uvRow.get(2 * i); + const uvR = uvRow.get(2 * i + 1); + const uvT = uvColumn.get(doubleJ + 1); + if (isNaN(uvL) || isNaN(uvL) || isNaN(uvR) || isNaN(uvT)) { + continue; + } + vertexCount += 4; + indicesCount += 6; + } + } + this.resetData(renderer, vertexCount, indicesCount); + + const { r: colorR, g: colorG, b: colorB, a: colorA } = renderer.color; + const { _chunk: chunk } = renderer; + const vertices = chunk._meshBuffer._vertices; + const indices = chunk._indices; + let index = chunk._vEntry.start; let count = 0; let trianglesOffset = 0; for (let j = 0; j < columnLength; j++) { @@ -66,62 +102,65 @@ export class TiledSpriteAssembler { if (isNaN(uvL) || isNaN(uvL) || isNaN(uvR) || isNaN(uvT)) { continue; } - triangles[trianglesOffset++] = count; - triangles[trianglesOffset++] = count + 1; - triangles[trianglesOffset++] = count + 2; - triangles[trianglesOffset++] = count + 2; - triangles[trianglesOffset++] = count + 1; - triangles[trianglesOffset++] = count + 3; + + indices[trianglesOffset++] = count; + indices[trianglesOffset++] = count + 1; + indices[trianglesOffset++] = count + 2; + indices[trianglesOffset++] = count + 2; + indices[trianglesOffset++] = count + 1; + indices[trianglesOffset++] = count + 3; + count += 4; const l = posRow.get(i); const b = posColumn.get(j); const r = posRow.get(i + 1); const t = posColumn.get(j + 1); // left and bottom - uvs[count] ? uvs[count].set(uvL, uvB) : (uvs[count] = new Vector2(uvL, uvB)); - let pos = positions[count]; - if (pos) { - pos.set(wE0 * l + wE4 * b + wE12, wE1 * l + wE5 * b + wE13, wE2 * l + wE6 * b + wE14); - } else { - positions[count] = new Vector3(wE0 * l + wE4 * b + wE12, wE1 * l + wE5 * b + wE13, wE2 * l + wE6 * b + wE14); - } - count++; + vertices[index++] = wE0 * l + wE4 * b + wE12; + vertices[index++] = wE1 * l + wE5 * b + wE13; + vertices[index++] = wE2 * l + wE6 * b + wE14; + vertices[index++] = uvL; + vertices[index++] = uvB; + vertices[index++] = colorR; + vertices[index++] = colorG; + vertices[index++] = colorB; + vertices[index++] = colorA; // right and bottom - uvs[count] ? uvs[count].set(uvR, uvB) : (uvs[count] = new Vector2(uvR, uvB)); - pos = positions[count]; - if (pos) { - pos.set(wE0 * r + wE4 * b + wE12, wE1 * r + wE5 * b + wE13, wE2 * r + wE6 * b + wE14); - } else { - positions[count] = new Vector3(wE0 * r + wE4 * b + wE12, wE1 * r + wE5 * b + wE13, wE2 * r + wE6 * b + wE14); - } - count++; + vertices[index++] = wE0 * r + wE4 * b + wE12; + vertices[index++] = wE1 * r + wE5 * b + wE13; + vertices[index++] = wE2 * r + wE6 * b + wE14; + vertices[index++] = uvR; + vertices[index++] = uvB; + vertices[index++] = colorR; + vertices[index++] = colorG; + vertices[index++] = colorB; + vertices[index++] = colorA; // left and top - uvs[count] ? uvs[count].set(uvL, uvT) : (uvs[count] = new Vector2(uvL, uvT)); - pos = positions[count]; - if (pos) { - pos.set(wE0 * l + wE4 * t + wE12, wE1 * l + wE5 * t + wE13, wE2 * l + wE6 * t + wE14); - } else { - positions[count] = new Vector3(wE0 * l + wE4 * t + wE12, wE1 * l + wE5 * t + wE13, wE2 * l + wE6 * t + wE14); - } - count++; + vertices[index++] = wE0 * l + wE4 * t + wE12; + vertices[index++] = wE1 * l + wE5 * t + wE13; + vertices[index++] = wE2 * l + wE6 * t + wE14; + vertices[index++] = uvL; + vertices[index++] = uvT; + vertices[index++] = colorR; + vertices[index++] = colorG; + vertices[index++] = colorB; + vertices[index++] = colorA; // right and top - uvs[count] ? uvs[count].set(uvR, uvT) : (uvs[count] = new Vector2(uvR, uvT)); - pos = positions[count]; - if (pos) { - pos.set(wE0 * r + wE4 * t + wE12, wE1 * r + wE5 * t + wE13, wE2 * r + wE6 * t + wE14); - } else { - positions[count] = new Vector3(wE0 * r + wE4 * t + wE12, wE1 * r + wE5 * t + wE13, wE2 * r + wE6 * t + wE14); - } - count++; + vertices[index++] = wE0 * r + wE4 * t + wE12; + vertices[index++] = wE1 * r + wE5 * t + wE13; + vertices[index++] = wE2 * r + wE6 * t + wE14; + vertices[index++] = uvR; + vertices[index++] = uvT; + vertices[index++] = colorR; + vertices[index++] = colorG; + vertices[index++] = colorB; + vertices[index++] = colorA; } } - renderer._verticesData.vertexCount = count; - triangles.length = trianglesOffset; - const { min, max } = renderer._bounds; min.set(posRow.get(0), posColumn.get(0), 0); max.set(posRow.get(rowLength), posColumn.get(columnLength), 0); @@ -130,6 +169,20 @@ export class TiledSpriteAssembler { static updateUVs(renderer: SpriteRenderer): void {} + static updateColor(renderer: SpriteRenderer): void { + const { _chunk: chunk } = renderer; + const { color } = renderer; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start + 5; + for (let i = 0, l = chunk._vEntry.len / 9; i < l; ++i) { + vertices[index] = color.r; + vertices[index + 1] = color.g; + vertices[index + 2] = color.b; + vertices[index + 3] = color.a; + index += 9; + } + } + private static _calculateAdaptiveDividing( sprite: Sprite, width: number, diff --git a/packages/core/src/2d/data/VertexData2D.ts b/packages/core/src/2d/data/VertexData2D.ts index a1c64f5b84..c14d26cc3b 100644 --- a/packages/core/src/2d/data/VertexData2D.ts +++ b/packages/core/src/2d/data/VertexData2D.ts @@ -6,5 +6,5 @@ import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; export class VertexData2D { public mbChunk: MBChunk = null; - constructor(public vertexCount: number) {} + constructor() {} } diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 8aa6cbbd71..780748042a 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -6,11 +6,11 @@ import { Renderer, RendererUpdateFlags } from "../../Renderer"; import { assignmentClone, ignoreClone } from "../../clone/CloneManager"; import { ShaderProperty } from "../../shader/ShaderProperty"; import { SimpleSpriteAssembler } from "../assembler/SimpleSpriteAssembler"; -import { VertexData2D } from "../data/VertexData2D"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { SpriteModifyFlags } from "../enums/SpriteModifyFlags"; import { Sprite } from "./Sprite"; import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; +import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; /** * A component for masking Sprites. @@ -29,7 +29,7 @@ export class SpriteMask extends Renderer { /** @internal */ @ignoreClone - _verticesData: VertexData2D; + _chunk: MBChunk; @ignoreClone private _sprite: Sprite = null; @@ -169,7 +169,6 @@ export class SpriteMask extends Renderer { */ constructor(entity: Entity) { super(entity); - this._verticesData = new VertexData2D(4); SimpleSpriteAssembler.resetData(this); this.setMaterial(this._engine._spriteMaskDefaultMaterial); this.shaderData.setFloat(SpriteMask._alphaCutoffProperty, this._alphaCutoff); @@ -221,7 +220,7 @@ export class SpriteMask extends Renderer { engine._spriteMaskManager.addMask(this); const renderData = engine._spriteRenderDataPool.getFromPool(); const material = this.getMaterial(); - const { mbChunk: chunk } = this._verticesData; + const { _chunk: chunk } = this; renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, this.sprite.texture, chunk); renderData.usage = RenderDataUsage.SpriteMask; @@ -243,7 +242,10 @@ export class SpriteMask extends Renderer { } this._entity = null; this._sprite = null; - this._verticesData = null; + if (this._chunk) { + this.engine._batcherManager._batcher2D.freeChunk(this._chunk); + this._chunk = null; + } } private _calDefaultSize(): void { diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 897be5c7bb..da22545ba0 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -9,7 +9,6 @@ import { IAssembler } from "../assembler/IAssembler"; import { SimpleSpriteAssembler } from "../assembler/SimpleSpriteAssembler"; import { SlicedSpriteAssembler } from "../assembler/SlicedSpriteAssembler"; import { TiledSpriteAssembler } from "../assembler/TiledSpriteAssembler"; -import { VertexData2D } from "../data/VertexData2D"; import { SpriteDrawMode } from "../enums/SpriteDrawMode"; import { SpriteMaskInteraction } from "../enums/SpriteMaskInteraction"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; @@ -17,6 +16,7 @@ import { SpriteModifyFlags } from "../enums/SpriteModifyFlags"; import { SpriteTileMode } from "../enums/SpriteTileMode"; import { Sprite } from "./Sprite"; import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; +import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; /** * Renders a Sprite for 2D graphics. @@ -27,7 +27,7 @@ export class SpriteRenderer extends Renderer { /** @internal */ @ignoreClone - _verticesData: VertexData2D; + _chunk: MBChunk; @ignoreClone private _drawMode: SpriteDrawMode; @@ -266,7 +266,6 @@ export class SpriteRenderer extends Renderer { */ constructor(entity: Entity) { super(entity); - this._verticesData = new VertexData2D(4); this.drawMode = SpriteDrawMode.Simple; this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.Color; this.setMaterial(this._engine._spriteDefaultMaterial); @@ -333,7 +332,7 @@ export class SpriteRenderer extends Renderer { const { engine } = context.camera; const material = this.getMaterial(); const renderData = engine._spriteRenderDataPool.getFromPool(); - const { mbChunk: chunk } = this._verticesData; + const { _chunk: chunk } = this; renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, this.sprite.texture, chunk); renderData.usage = RenderDataUsage.Sprite; engine._batcherManager.commitRenderData(context, renderData); @@ -353,7 +352,10 @@ export class SpriteRenderer extends Renderer { this._color = null; this._sprite = null; this._assembler = null; - this._verticesData = null; + if (this._chunk) { + this.engine._batcherManager._batcher2D.freeChunk(this._chunk); + this._chunk = null; + } } private _calDefaultSize(): void { From 650b1353d9072fe6dd19597e1a8312dbac3bacbc Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 5 Mar 2024 17:24:35 +0800 Subject: [PATCH 016/218] refactor(2d-render-pipeline): complete text renderer --- packages/core/src/2d/data/VertexData2D.ts | 10 ----- packages/core/src/2d/text/CharRenderData.ts | 13 +++--- packages/core/src/2d/text/TextRenderer.ts | 48 ++++++++++++++++----- 3 files changed, 46 insertions(+), 25 deletions(-) delete mode 100644 packages/core/src/2d/data/VertexData2D.ts diff --git a/packages/core/src/2d/data/VertexData2D.ts b/packages/core/src/2d/data/VertexData2D.ts deleted file mode 100644 index c14d26cc3b..0000000000 --- a/packages/core/src/2d/data/VertexData2D.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; - -/** - * @internal - */ -export class VertexData2D { - public mbChunk: MBChunk = null; - - constructor() {} -} diff --git a/packages/core/src/2d/text/CharRenderData.ts b/packages/core/src/2d/text/CharRenderData.ts index 1e2b2efab4..7abdfff5c0 100644 --- a/packages/core/src/2d/text/CharRenderData.ts +++ b/packages/core/src/2d/text/CharRenderData.ts @@ -1,6 +1,7 @@ import { Vector3, Vector4 } from "@galacean/engine-math"; import { Texture2D } from "../../texture"; -import { VertexData2D } from "../data/VertexData2D"; +import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; +import { Engine } from "../../Engine"; /** * @internal @@ -11,10 +12,12 @@ export class CharRenderData { texture: Texture2D; /** x:Top y:Left z:Bottom w:Right */ localPositions: Vector4 = new Vector4(); - renderData: VertexData2D; + chunk: MBChunk; - constructor() { - const positions = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; - this.renderData = new VertexData2D(4, positions, null, CharRenderData.triangles, null); + init(engine: Engine) { + if (!this.chunk) { + this.chunk = engine._batcherManager._batcher2D.allocateChunk(4, 6); + this.chunk._indices = CharRenderData.triangles; + } } } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 51a9e8b762..4c4563d8dd 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -26,6 +26,10 @@ export class TextRenderer extends Renderer { private static _charRenderDataPool: CharRenderDataPool = new CharRenderDataPool(CharRenderData, 50); private static _tempVec30: Vector3 = new Vector3(); private static _tempVec31: Vector3 = new Vector3(); + private static _worldPosition0: Vector3 = new Vector3(); + private static _worldPosition1: Vector3 = new Vector3(); + private static _worldPosition2: Vector3 = new Vector3(); + private static _worldPosition3: Vector3 = new Vector3(); /** @internal */ @assignmentClone @@ -310,6 +314,7 @@ export class TextRenderer extends Renderer { // Clear render data. const charRenderDatas = this._charRenderDatas; for (let i = 0, n = charRenderDatas.length; i < n; ++i) { + this.engine._batcherManager._batcher2D.freeChunk(charRenderDatas[i].chunk); TextRenderer._charRenderDataPool.put(charRenderDatas[i]); } charRenderDatas.length = 0; @@ -404,7 +409,8 @@ export class TextRenderer extends Renderer { for (let i = 0; i < charCount; ++i) { const charRenderData = charRenderDatas[i]; const renderData = spriteRenderDataPool.getFromPool(); - renderData.setX(this, material, charRenderData.renderData, charRenderData.texture); + const { chunk } = charRenderData; + renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, charRenderData.texture, chunk); renderData.usage = RenderDataUsage.Sprite; spriteRenderDatas.push(renderData); } @@ -456,31 +462,40 @@ export class TextRenderer extends Renderer { for (let i = 0, n = charRenderDatas.length; i < n; ++i) { const charRenderData = charRenderDatas[i]; const { localPositions } = charRenderData; - const { positions } = charRenderData.renderData; - const { x: topLeftX, y: topLeftY } = localPositions; // Top-Left - const worldPosition0 = positions[0]; + const worldPosition0 = TextRenderer._worldPosition0; worldPosition0.x = topLeftX * e0 + topLeftY * e4 + e12; worldPosition0.y = topLeftX * e1 + topLeftY * e5 + e13; worldPosition0.z = topLeftX * e2 + topLeftY * e6 + e14; // Right offset - const worldPosition1 = positions[1]; + const worldPosition1 = TextRenderer._worldPosition1; Vector3.scale(right, localPositions.z - topLeftX, worldPosition1); // Top-Right Vector3.add(worldPosition0, worldPosition1, worldPosition1); // Up offset - const worldPosition2 = positions[2]; + const worldPosition2 = TextRenderer._worldPosition2; Vector3.scale(up, localPositions.w - topLeftY, worldPosition2); // Bottom-Left - Vector3.add(worldPosition0, worldPosition2, positions[3]); + Vector3.add(worldPosition0, worldPosition2, TextRenderer._worldPosition3); // Bottom-Right Vector3.add(worldPosition1, worldPosition2, worldPosition2); + + const { chunk } = charRenderData; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + const position = TextRenderer[`_worldPosition${i}`]; + vertices[index] = position.x; + vertices[index + 1] = position.y; + vertices[index + 2] = position.z; + index += 9; + } } } @@ -550,10 +565,22 @@ export class TextRenderer extends Renderer { if (charInfo.h > 0) { firstRow < 0 && (firstRow = j); const charRenderData = (charRenderDatas[renderDataCount++] ||= charRenderDataPool.get()); - const { renderData, localPositions } = charRenderData; + charRenderData.init(this.engine); + const { chunk, localPositions } = charRenderData; charRenderData.texture = charFont._getTextureByIndex(charInfo.index); - renderData.color = color; - renderData.uvs = charInfo.uvs; + const vertices = chunk._meshBuffer._vertices; + const { uvs } = charInfo; + const { r, g, b, a } = color; + let index = chunk._vEntry.start + 3; + for (let i = 0; i < 4; ++i) { + vertices[index] = uvs[i].x; + vertices[index + 1] = uvs[i].y; + vertices[index + 2] = r; + vertices[index + 3] = g; + vertices[index + 4] = b; + vertices[index + 5] = a; + index += 9; + } const { w, ascent, descent } = charInfo; const left = startX * pixelsPerUnitReciprocal; @@ -587,6 +614,7 @@ export class TextRenderer extends Renderer { const lastRenderDataCount = charRenderDatas.length; if (lastRenderDataCount > renderDataCount) { for (let i = renderDataCount; i < lastRenderDataCount; ++i) { + this.engine._batcherManager._batcher2D.freeChunk(charRenderDatas[i].chunk); charRenderDataPool.put(charRenderDatas[i]); } charRenderDatas.length = renderDataCount; From 7e33812b63dc05785e4abf3b0a7ef73496aaed6b Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 15 Mar 2024 15:15:29 +0800 Subject: [PATCH 017/218] refactor(2d-render-pipeline): fix conflicts from dev/1.2 --- packages/core/src/RenderPipeline/BasicRenderPipeline.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index bbb9d5fc2d..6213c4b211 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -44,7 +44,6 @@ export class BasicRenderPipeline { this._camera = camera; const { engine } = camera; this._cullingResults = new CullingResults(); - this._cullingResults = new CullingResults(); this._cascadedShadowCasterPass = new CascadedShadowCasterPass(camera); this._depthOnlyPass = new DepthOnlyPass(engine); this._opaqueTexturePass = new OpaqueTexturePass(engine); From 7a09c01378e7a72ca07257899c5ad7a0cf28bca4 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 11 Apr 2024 15:16:45 +0800 Subject: [PATCH 018/218] refactor(2d-render-pipeline): delete IBatcher --- packages/core/src/RenderPipeline/batcher/Batcher2D.ts | 3 +-- packages/core/src/RenderPipeline/batcher/IBatcher.ts | 9 --------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 packages/core/src/RenderPipeline/batcher/IBatcher.ts diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 2808021cb7..fa95a45c5e 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -5,13 +5,12 @@ import { ShaderProperty, ShaderTagKey } from "../../shader"; import { ClassPool } from "../ClassPool"; import { RenderContext } from "../RenderContext"; import { SpriteRenderData } from "../SpriteRenderData"; -import { IBatcher } from "./IBatcher"; import { MBChunk, MeshBuffer } from "./MeshBuffer"; /** * @internal */ -export class Batcher2D implements IBatcher { +export class Batcher2D { /** The maximum number of vertex. */ static MAX_VERTEX_COUNT: number = 4096; diff --git a/packages/core/src/RenderPipeline/batcher/IBatcher.ts b/packages/core/src/RenderPipeline/batcher/IBatcher.ts deleted file mode 100644 index b46e10136e..0000000000 --- a/packages/core/src/RenderPipeline/batcher/IBatcher.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { RenderContext } from "../RenderContext"; -import { RenderData } from "../RenderData"; - -export interface IBatcher { - commitRenderData(context: RenderContext, data: RenderData): void; - flush(): void; - uploadBuffer(): void; - clear(): void; -} From 901ba132ed3a3e1722d28cf5db4f87929472e4ec Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 11 Apr 2024 16:09:48 +0800 Subject: [PATCH 019/218] refactor(2d-render-pipeline): move IPoolElement to Pool --- packages/core/src/RenderPipeline/ClassPool.ts | 2 +- packages/core/src/RenderPipeline/IPoolElement.ts | 3 --- packages/core/src/RenderPipeline/RenderData.ts | 2 +- packages/core/src/RenderPipeline/RenderElement.ts | 2 +- packages/core/src/RenderPipeline/SpriteRenderData.ts | 2 +- packages/core/src/RenderPipeline/batcher/MeshBuffer.ts | 5 ++--- .../core/src/animation/internal/AnimationEventHandler.ts | 2 +- packages/core/src/graphic/SubMesh.ts | 2 +- packages/core/src/index.ts | 1 + packages/core/src/utils/Pool.ts | 6 ++++-- 10 files changed, 13 insertions(+), 14 deletions(-) delete mode 100644 packages/core/src/RenderPipeline/IPoolElement.ts diff --git a/packages/core/src/RenderPipeline/ClassPool.ts b/packages/core/src/RenderPipeline/ClassPool.ts index 98e17cde2c..9eaa2565e3 100644 --- a/packages/core/src/RenderPipeline/ClassPool.ts +++ b/packages/core/src/RenderPipeline/ClassPool.ts @@ -1,4 +1,4 @@ -import { IPoolElement } from "./IPoolElement"; +import { IPoolElement } from "../utils/Pool"; /** * Class pool utils. diff --git a/packages/core/src/RenderPipeline/IPoolElement.ts b/packages/core/src/RenderPipeline/IPoolElement.ts deleted file mode 100644 index 547ba01e4d..0000000000 --- a/packages/core/src/RenderPipeline/IPoolElement.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface IPoolElement { - dispose?(): void; -} diff --git a/packages/core/src/RenderPipeline/RenderData.ts b/packages/core/src/RenderPipeline/RenderData.ts index 11575e42aa..a9e0847c10 100644 --- a/packages/core/src/RenderPipeline/RenderData.ts +++ b/packages/core/src/RenderPipeline/RenderData.ts @@ -2,8 +2,8 @@ import { SubMesh } from "../graphic"; import { Primitive } from "../graphic/Primitive"; import { Material } from "../material"; import { Renderer } from "../Renderer"; +import { IPoolElement } from "../utils/Pool"; import { RenderDataUsage } from "./enums/RenderDataUsage"; -import { IPoolElement } from "./IPoolElement"; export class RenderData implements IPoolElement { component: Renderer; diff --git a/packages/core/src/RenderPipeline/RenderElement.ts b/packages/core/src/RenderPipeline/RenderElement.ts index 519d7ad73a..e916ce24e8 100644 --- a/packages/core/src/RenderPipeline/RenderElement.ts +++ b/packages/core/src/RenderPipeline/RenderElement.ts @@ -1,5 +1,5 @@ import { ShaderPass } from "../shader/ShaderPass"; -import { IPoolElement } from "./IPoolElement"; +import { IPoolElement } from "../utils/Pool"; import { RenderData } from "./RenderData"; export class RenderElement implements IPoolElement { diff --git a/packages/core/src/RenderPipeline/SpriteRenderData.ts b/packages/core/src/RenderPipeline/SpriteRenderData.ts index f338362373..8c5b2ee524 100644 --- a/packages/core/src/RenderPipeline/SpriteRenderData.ts +++ b/packages/core/src/RenderPipeline/SpriteRenderData.ts @@ -2,9 +2,9 @@ import { Primitive, SubMesh } from "../graphic"; import { Material } from "../material/Material"; import { Renderer } from "../Renderer"; import { Texture2D } from "../texture"; +import { IPoolElement } from "../utils/Pool"; import { MBChunk } from "./batcher/MeshBuffer"; import { RenderDataUsage } from "./enums/RenderDataUsage"; -import { IPoolElement } from "./IPoolElement"; import { RenderData } from "./RenderData"; export class SpriteRenderData extends RenderData implements IPoolElement { diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index 9465165d70..9149270780 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -11,8 +11,7 @@ import { VertexElementFormat } from "../../graphic"; import { BufferMesh } from "../../mesh"; -import { Pool } from "../../utils/Pool"; -import { IPoolElement } from "../IPoolElement"; +import { IPoolElement, Pool } from "../../utils/Pool"; import { Batcher2D } from "./Batcher2D"; /** @@ -120,7 +119,7 @@ export class MeshBuffer { this._iBuffer = null; this._vertices = null; this._indices = null; - this._entryPool.garbageCollection(); + this._entryPool.dispose(); this._entryPool = null; } diff --git a/packages/core/src/animation/internal/AnimationEventHandler.ts b/packages/core/src/animation/internal/AnimationEventHandler.ts index 53d1cf267e..21313c7a78 100644 --- a/packages/core/src/animation/internal/AnimationEventHandler.ts +++ b/packages/core/src/animation/internal/AnimationEventHandler.ts @@ -1,4 +1,4 @@ -import { IPoolElement } from "../../RenderPipeline/IPoolElement"; +import { IPoolElement } from "../../utils/Pool"; import { AnimationEvent } from "../AnimationEvent"; /** * @internal diff --git a/packages/core/src/graphic/SubMesh.ts b/packages/core/src/graphic/SubMesh.ts index edb0f7f68a..c366696bc0 100644 --- a/packages/core/src/graphic/SubMesh.ts +++ b/packages/core/src/graphic/SubMesh.ts @@ -1,4 +1,4 @@ -import { IPoolElement } from "../RenderPipeline/IPoolElement"; +import { IPoolElement } from "../utils/Pool"; import { MeshTopology } from "./enums/MeshTopology"; /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 32bda2f4d0..546fcc1e5c 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -40,6 +40,7 @@ export { Downsampling } from "./enums/Downsampling"; export { ColorSpace } from "./enums/ColorSpace"; export { BackgroundTextureFillMode } from "./enums/BackgroundTextureFillMode"; export { XRManager } from "./xr/XRManager"; +export { Pool, IPoolElement } from "./utils/Pool"; export * from "./input/index"; export * from "./lighting/index"; export * from "./shadow/index"; diff --git a/packages/core/src/utils/Pool.ts b/packages/core/src/utils/Pool.ts index d41f2ee5ee..e7d42e0516 100644 --- a/packages/core/src/utils/Pool.ts +++ b/packages/core/src/utils/Pool.ts @@ -1,4 +1,6 @@ -import { IPoolElement } from "../RenderPipeline/IPoolElement"; +export interface IPoolElement { + dispose?(): void; +} export class Pool { private _type: new () => T; @@ -25,7 +27,7 @@ export class Pool { this._elementPool[++this._elementPoolIndex] = element; } - garbageCollection(): void { + dispose(): void { const { _elementPool: pool } = this; for (let i = pool.length - 1; i >= 0; i--) { pool[i].dispose && pool[i].dispose(); From b25615528ff45ad75a30f0e4c6cdde7b60cc928b Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 11 Apr 2024 16:31:08 +0800 Subject: [PATCH 020/218] refactor(2d-render-pipeline): replace CharRenderDataPool with Pool --- packages/core/src/2d/text/CharRenderData.ts | 9 +++++-- .../core/src/2d/text/CharRenderDataPool.ts | 26 ------------------- packages/core/src/2d/text/TextRenderer.ts | 11 ++++---- packages/core/src/index.ts | 3 ++- 4 files changed, 15 insertions(+), 34 deletions(-) delete mode 100644 packages/core/src/2d/text/CharRenderDataPool.ts diff --git a/packages/core/src/2d/text/CharRenderData.ts b/packages/core/src/2d/text/CharRenderData.ts index 7abdfff5c0..b4836d29f9 100644 --- a/packages/core/src/2d/text/CharRenderData.ts +++ b/packages/core/src/2d/text/CharRenderData.ts @@ -1,12 +1,13 @@ -import { Vector3, Vector4 } from "@galacean/engine-math"; +import { Vector4 } from "@galacean/engine-math"; import { Texture2D } from "../../texture"; import { MBChunk } from "../../RenderPipeline/batcher/MeshBuffer"; import { Engine } from "../../Engine"; +import { IPoolElement } from "../../utils/Pool"; /** * @internal */ -export class CharRenderData { +export class CharRenderData implements IPoolElement { static triangles: number[] = [0, 2, 1, 2, 0, 3]; texture: Texture2D; @@ -20,4 +21,8 @@ export class CharRenderData { this.chunk._indices = CharRenderData.triangles; } } + + dispose(): void { + this.texture = this.chunk = null; + } } diff --git a/packages/core/src/2d/text/CharRenderDataPool.ts b/packages/core/src/2d/text/CharRenderDataPool.ts deleted file mode 100644 index ac4e89a9d5..0000000000 --- a/packages/core/src/2d/text/CharRenderDataPool.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @internal - */ -export class CharRenderDataPool { - private _elements: T[] = []; - private _type: new () => T; - - constructor(type: new () => T, length: number) { - this._type = type; - const elements = this._elements; - for (let i = 0; i < length; ++i) { - elements[i] = new type(); - } - } - - get(): T { - if (this._elements.length > 0) { - return this._elements.pop(); - } - return new this._type(); - } - - put(data: T): void { - this._elements.push(data); - } -} diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 900bb77335..03a48ad0a1 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -12,18 +12,18 @@ import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { TextHorizontalAlignment, TextVerticalAlignment } from "../enums/TextAlignment"; import { OverflowMode } from "../enums/TextOverflow"; import { CharRenderData } from "./CharRenderData"; -import { CharRenderDataPool } from "./CharRenderDataPool"; import { Font } from "./Font"; import { SubFont } from "./SubFont"; import { TextUtils } from "./TextUtils"; import { SpriteRenderData } from "../../RenderPipeline/SpriteRenderData"; import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; +import { Pool } from "../../utils/Pool"; /** * Renders a text for 2D graphics. */ export class TextRenderer extends Renderer { - private static _charRenderDataPool: CharRenderDataPool = new CharRenderDataPool(CharRenderData, 50); + private static _charRenderDataPool: Pool = new Pool(CharRenderData, 50); private static _tempVec30: Vector3 = new Vector3(); private static _tempVec31: Vector3 = new Vector3(); private static _worldPosition0: Vector3 = new Vector3(); @@ -317,10 +317,11 @@ export class TextRenderer extends Renderer { super._onDestroy(); // Clear render data. + const pool = TextRenderer._charRenderDataPool; const charRenderDatas = this._charRenderDatas; for (let i = 0, n = charRenderDatas.length; i < n; ++i) { this.engine._batcherManager._batcher2D.freeChunk(charRenderDatas[i].chunk); - TextRenderer._charRenderDataPool.put(charRenderDatas[i]); + pool.free(charRenderDatas[i]); } charRenderDatas.length = 0; @@ -570,7 +571,7 @@ export class TextRenderer extends Renderer { const charInfo = charFont._getCharInfo(char); if (charInfo.h > 0) { firstRow < 0 && (firstRow = j); - const charRenderData = (charRenderDatas[renderDataCount++] ||= charRenderDataPool.get()); + const charRenderData = (charRenderDatas[renderDataCount++] ||= charRenderDataPool.alloc()); charRenderData.init(this.engine); const { chunk, localPositions } = charRenderData; charRenderData.texture = charFont._getTextureByIndex(charInfo.index); @@ -621,7 +622,7 @@ export class TextRenderer extends Renderer { if (lastRenderDataCount > renderDataCount) { for (let i = renderDataCount; i < lastRenderDataCount; ++i) { this.engine._batcherManager._batcher2D.freeChunk(charRenderDatas[i].chunk); - charRenderDataPool.put(charRenderDatas[i]); + charRenderDataPool.free(charRenderDatas[i]); } charRenderDatas.length = renderDataCount; } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 546fcc1e5c..8fef89d5ae 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -40,7 +40,8 @@ export { Downsampling } from "./enums/Downsampling"; export { ColorSpace } from "./enums/ColorSpace"; export { BackgroundTextureFillMode } from "./enums/BackgroundTextureFillMode"; export { XRManager } from "./xr/XRManager"; -export { Pool, IPoolElement } from "./utils/Pool"; +export { Pool } from "./utils/Pool"; +export type { IPoolElement } from "./utils/Pool"; export * from "./input/index"; export * from "./lighting/index"; export * from "./shadow/index"; From 10bb95b91a2bcc974f132361dc75c3e8333c3173 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 12 Apr 2024 11:30:23 +0800 Subject: [PATCH 021/218] refactor(2d-render-pipeline): create mesh buffer support custom size --- packages/core/src/Engine.ts | 1 - packages/core/src/RenderPipeline/SpriteMaskManager.ts | 2 +- packages/core/src/RenderPipeline/batcher/Batcher2D.ts | 8 ++++---- .../core/src/RenderPipeline/batcher/MeshBuffer.ts | 11 +++++------ .../src/RenderPipeline/batcher/SpriteMaskBatcher.ts | 4 ++-- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index e0afff3580..17a1107cc7 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -250,7 +250,6 @@ export class Engine extends EventDispatcher { this._canvas = canvas; - this._spriteMaskManager = new SpriteMaskManager(this); const { _spriteDefaultMaterials: spriteDefaultMaterials } = this; this._spriteDefaultMaterial = spriteDefaultMaterials[SpriteMaskInteraction.None] = this._createSpriteMaterial( SpriteMaskInteraction.None diff --git a/packages/core/src/RenderPipeline/SpriteMaskManager.ts b/packages/core/src/RenderPipeline/SpriteMaskManager.ts index f478dbaf55..be8410f9b7 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskManager.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskManager.ts @@ -19,7 +19,7 @@ export class SpriteMaskManager { private _preMaskLayer: number = 0; constructor(engine: Engine) { - this._batcher = new SpriteMaskBatcher(engine); + this._batcher = new SpriteMaskBatcher(engine, 128); } addMask(mask: SpriteMask): void { diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index fa95a45c5e..6b7ed292ac 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -29,9 +29,9 @@ export class Batcher2D { /** @internal */ _preRenderData: SpriteRenderData = null; - constructor(engine: Engine) { + constructor(engine: Engine, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT) { this._engine = engine; - this._createMeshBuffer(0); + this._createMeshBuffer(0, maxVertexCount); } /** @@ -110,13 +110,13 @@ export class Batcher2D { meshBuffer && meshBuffer.freeChunk(chunk); } - protected _createMeshBuffer(index: number): MeshBuffer { + protected _createMeshBuffer(index: number, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT): MeshBuffer { const { _meshBuffers } = this; if (_meshBuffers[index]) { return _meshBuffers[index]; } - const meshBuffer = (_meshBuffers[index] = new MeshBuffer(this._engine)); + const meshBuffer = (_meshBuffers[index] = new MeshBuffer(this._engine, maxVertexCount)); return meshBuffer; } diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index 9149270780..b8b80f60fb 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -75,18 +75,17 @@ export class MeshBuffer { /** @internal */ _subMeshPool: Pool = new Pool(SubMesh, 10); - constructor(engine: Engine) { + constructor(engine: Engine, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT) { const mesh = (this._mesh = new BufferMesh(engine)); mesh.isGCIgnored = true; const vertexElements: VertexElement[] = []; const vertexStride = this.createVertexElements(vertexElements); - const { MAX_VERTEX_COUNT } = Batcher2D; // vertices const vertexBuffer = (this._vBuffer = new Buffer( engine, BufferBindFlag.VertexBuffer, - MAX_VERTEX_COUNT * vertexStride, + maxVertexCount * vertexStride, BufferUsage.Dynamic )); vertexBuffer.isGCIgnored = true; @@ -94,7 +93,7 @@ export class MeshBuffer { const indiceBuffer = (this._iBuffer = new Buffer( engine, BufferBindFlag.IndexBuffer, - MAX_VERTEX_COUNT * 8, + maxVertexCount * 8, BufferUsage.Dynamic )); indiceBuffer.isGCIgnored = true; @@ -102,8 +101,8 @@ export class MeshBuffer { mesh.setIndexBufferBinding(indiceBuffer, IndexFormat.UInt16); mesh.setVertexElements(vertexElements); - const vertexLen = MAX_VERTEX_COUNT * 9; - const indiceLen = MAX_VERTEX_COUNT * 4; + const vertexLen = maxVertexCount * 9; + const indiceLen = maxVertexCount * 4; this._vertices = new Float32Array(vertexLen); this._indices = new Uint16Array(indiceLen); this._vFreeEntries.push(new Entry(0, vertexLen)); diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index 0bdd7aa3eb..bfe7fe4d49 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -18,8 +18,8 @@ export class SpriteMaskBatcher extends Batcher2D { /** @internal */ _preOp: StencilOperation = null; - constructor(engine: Engine) { - super(engine); + constructor(engine: Engine, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT) { + super(engine, maxVertexCount); } drawElement(element: RenderElement, camera: Camera, op: StencilOperation): void { From b62df3a7697ffb07043d8e6d87a2e3a5bb978f6a Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 18 Apr 2024 10:59:28 +0800 Subject: [PATCH 022/218] refactor(2d-render-pipeline): opt code --- packages/core/src/2d/assembler/SimpleSpriteAssembler.ts | 4 ++-- packages/core/src/2d/assembler/SlicedSpriteAssembler.ts | 4 ++-- packages/core/src/2d/assembler/TiledSpriteAssembler.ts | 4 ++-- packages/core/src/2d/text/CharRenderData.ts | 2 +- packages/core/src/RenderPipeline/batcher/Batcher2D.ts | 6 +++--- packages/core/src/RenderPipeline/batcher/MeshBuffer.ts | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index 53f117ef6c..de850d8b24 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -19,9 +19,9 @@ export class SimpleSpriteAssembler { : renderer.engine._spriteMaskManager._batcher; if (renderer._chunk) { batcher.freeChunk(renderer._chunk); - renderer._chunk = batcher.allocateChunk(4, 6); + renderer._chunk = batcher.allocateChunk(4); } else { - renderer._chunk = batcher.allocateChunk(4, 6); + renderer._chunk = batcher.allocateChunk(4); } renderer._chunk._indices = this._rectangleTriangles; } diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts index c63b73bc0c..a0a8b81bb8 100644 --- a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts @@ -18,9 +18,9 @@ export class SlicedSpriteAssembler { const batcher = renderer.engine._batcherManager._batcher2D; if (renderer._chunk) { batcher.freeChunk(renderer._chunk); - renderer._chunk = batcher.allocateChunk(16, 54); + renderer._chunk = batcher.allocateChunk(16); } else { - renderer._chunk = batcher.allocateChunk(16, 54); + renderer._chunk = batcher.allocateChunk(16); } renderer._chunk._indices = this._rectangleTriangles; } diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index b3a70e1b07..d583087e48 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -26,11 +26,11 @@ export class TiledSpriteAssembler { if (chunk) { if (chunk._vEntry.len !== vCount * 9) { batcher.freeChunk(chunk); - renderer._chunk = batcher.allocateChunk(vCount, iCount); + renderer._chunk = batcher.allocateChunk(vCount); renderer._chunk._indices = []; } } else { - renderer._chunk = batcher.allocateChunk(vCount, iCount); + renderer._chunk = batcher.allocateChunk(vCount); renderer._chunk._indices = []; } } diff --git a/packages/core/src/2d/text/CharRenderData.ts b/packages/core/src/2d/text/CharRenderData.ts index b4836d29f9..e1cf99da4e 100644 --- a/packages/core/src/2d/text/CharRenderData.ts +++ b/packages/core/src/2d/text/CharRenderData.ts @@ -17,7 +17,7 @@ export class CharRenderData implements IPoolElement { init(engine: Engine) { if (!this.chunk) { - this.chunk = engine._batcherManager._batcher2D.allocateChunk(4, 6); + this.chunk = engine._batcherManager._batcher2D.allocateChunk(4); this.chunk._indices = CharRenderData.triangles; } } diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 6b7ed292ac..fa3f279dfb 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -83,13 +83,13 @@ export class Batcher2D { } } - allocateChunk(vertexCount, indiceCount): MBChunk | null { + allocateChunk(vertexCount: number): MBChunk | null { const { _meshBuffers } = this; let chunk: MBChunk = null; let i = 0; const len = _meshBuffers.length; for (; i < len; ++i) { - chunk = _meshBuffers[i].allocateChunk(vertexCount, indiceCount); + chunk = _meshBuffers[i].allocateChunk(vertexCount); if (chunk) { chunk._mbId = i; return chunk; @@ -97,7 +97,7 @@ export class Batcher2D { } const meshBuffer = this._createMeshBuffer(len); - chunk = meshBuffer.allocateChunk(vertexCount, indiceCount); + chunk = meshBuffer.allocateChunk(vertexCount); if (chunk) { chunk._mbId = len; return chunk; diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index b8b80f60fb..8c4f2f2c31 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -134,7 +134,7 @@ export class MeshBuffer { this._iBuffer.setData(this._indices, 0, 0, this._iLen, SetDataOptions.Discard); } - allocateChunk(vertexCount: number, indiceCount: number): MBChunk | null { + allocateChunk(vertexCount: number): MBChunk | null { const vEntry = this._allocateEntry(this._vFreeEntries, vertexCount * 9); if (vEntry) { const chunk = this._chunkPool.alloc(); From 0dbad8df86d5c31993444d3019f5199ab8998571 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 18 Apr 2024 11:21:22 +0800 Subject: [PATCH 023/218] refactor(2d-render-pipeline): opt code --- .../core/src/RenderPipeline/batcher/Batcher2D.ts | 12 ------------ .../core/src/RenderPipeline/batcher/MeshBuffer.ts | 13 ++++++++----- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index fa3f279dfb..f73ecfd124 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,8 +1,6 @@ import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; import { Engine } from "../../Engine"; -import { MeshTopology, SubMesh } from "../../graphic"; import { ShaderProperty, ShaderTagKey } from "../../shader"; -import { ClassPool } from "../ClassPool"; import { RenderContext } from "../RenderContext"; import { SpriteRenderData } from "../SpriteRenderData"; import { MBChunk, MeshBuffer } from "./MeshBuffer"; @@ -19,8 +17,6 @@ export class Batcher2D { /** @internal */ _engine: Engine; - /** @internal */ - _subMeshPool: ClassPool = new ClassPool(SubMesh); /** @internal */ _meshBuffers: MeshBuffer[] = []; @@ -120,14 +116,6 @@ export class Batcher2D { return meshBuffer; } - protected _getSubMeshFromPool(start: number, count: number): SubMesh { - const subMesh = this._subMeshPool.getFromPool(); - subMesh.start = start; - subMesh.count = count; - subMesh.topology = MeshTopology.Triangles; - return subMesh; - } - private _canBatch(preRenderData: SpriteRenderData, curRenderData: SpriteRenderData): boolean { if (preRenderData.chunk._meshBuffer !== curRenderData.chunk._meshBuffer) { return false; diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index 8c4f2f2c31..5fce7eed3c 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -26,10 +26,15 @@ export class MBChunk implements IPoolElement { reset() { this._mbId = -1; - // TODO + this._meshBuffer = null; + this._subMesh = null; + this._vEntry = null; + this._indices = null; } - dispose?(): void {} + dispose?(): void { + this.reset(); + } } /** @@ -152,9 +157,7 @@ export class MeshBuffer { freeChunk(chunk: MBChunk): void { this._freeEntry(this._vFreeEntries, chunk._vEntry); this._subMeshPool.free(chunk._subMesh); - chunk._vEntry = null; - chunk._subMesh = null; - chunk._indices = null; + chunk.reset(); this._chunkPool.free(chunk); } From 9e50d30f4bc5ced0cbcabfecd8cca4a07209f2cf Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 19 Apr 2024 15:09:21 +0800 Subject: [PATCH 024/218] refactor(2d-render-pipeline): opt text renderer upload texture --- packages/core/src/2d/text/TextRenderer.ts | 3 +-- packages/core/src/2d/text/TextUtils.ts | 2 -- packages/core/src/2d/text/index.ts | 1 - packages/core/src/Engine.ts | 1 - .../core/src/RenderPipeline/RenderQueue.ts | 18 +++++++++++++----- .../src/RenderPipeline/batcher/Batcher2D.ts | 6 +----- .../RenderPipeline/batcher/BatcherManager.ts | 1 + .../RenderPipeline/enums/RenderDataUsage.ts | 4 +++- packages/core/src/index.ts | 1 - 9 files changed, 19 insertions(+), 18 deletions(-) diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 03a48ad0a1..d6f43a14d9 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -297,7 +297,6 @@ export class TextRenderer extends Renderer { /** * @internal - * Standalone for CanvasRenderer plugin. */ _init(): void { const { engine } = this; @@ -418,7 +417,7 @@ export class TextRenderer extends Renderer { const renderData = spriteRenderDataPool.getFromPool(); const { chunk } = charRenderData; renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, charRenderData.texture, chunk); - renderData.usage = RenderDataUsage.Sprite; + renderData.usage = RenderDataUsage.Text; spriteRenderDatas.push(renderData); } engine._batcherManager.commitRenderData(context, spriteRenderDatas); diff --git a/packages/core/src/2d/text/TextUtils.ts b/packages/core/src/2d/text/TextUtils.ts index b2ee009de8..214bddb517 100644 --- a/packages/core/src/2d/text/TextUtils.ts +++ b/packages/core/src/2d/text/TextUtils.ts @@ -342,7 +342,6 @@ export class TextUtils { /** * @internal - * Use internal for CanvasRenderer plugin. */ static _measureFontOrChar(fontString: string, char: string = ""): FontSizeInfo | CharInfo { const { canvas, context } = TextUtils.textContext(); @@ -435,7 +434,6 @@ export class TextUtils { /** * @internal - * Use internal for CanvasRenderer plugin. */ static _getCharInfo(char: string, fontString: string, font: SubFont): CharInfo { let charInfo = font._getCharInfo(char); diff --git a/packages/core/src/2d/text/index.ts b/packages/core/src/2d/text/index.ts index 6ea6c77d8f..b7df472e7e 100644 --- a/packages/core/src/2d/text/index.ts +++ b/packages/core/src/2d/text/index.ts @@ -1,4 +1,3 @@ export { Font } from "./Font"; export { TextRenderer } from "./TextRenderer"; -// Export for CanvasRenderer plugin. export { TextUtils } from "./TextUtils"; diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 17a1107cc7..9d0b49b317 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -557,7 +557,6 @@ export class Engine extends EventDispatcher { /** * @internal - * Standalone for CanvasRenderer plugin. */ _initMagentaTextures(hardwareRenderer: IHardwareRenderer) { const whitePixel = new Uint8Array([255, 255, 255, 255]); diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 76e677f33f..3771857a9b 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -1,7 +1,7 @@ import { SpriteRenderer } from "../2d"; import { Camera } from "../Camera"; import { Utils } from "../Utils"; -import { RenderQueueType, Shader } from "../shader"; +import { RenderQueueType, Shader, ShaderProperty } from "../shader"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; import { RenderContext } from "./RenderContext"; import { RenderElement } from "./RenderElement"; @@ -11,6 +11,8 @@ import { RenderDataUsage } from "./enums/RenderDataUsage"; * Render queue. */ export class RenderQueue { + private static _textureProperty: ShaderProperty = ShaderProperty.getByName("renderer_SpriteTexture"); + /** * @internal */ @@ -95,9 +97,10 @@ export class RenderQueue { const element = elements[i]; const { data, shaderPasses } = element; - const isSprite = data.usage === RenderDataUsage.Sprite; + const { usage } = data; + const needMask = usage === RenderDataUsage.Sprite || usage === RenderDataUsage.Text; const renderer = data.component; - isSprite && spriteMaskManager.preRender(camera, renderer); + needMask && spriteMaskManager.preRender(camera, renderer); const compileMacros = Shader._compileMacros; const primitive = data.primitive; @@ -105,6 +108,11 @@ export class RenderQueue { const { shaderData: rendererData, instanceId: rendererId } = renderer; const { shaderData: materialData, instanceId: materialId, renderStates } = material; + // TextRenderer may be has multi-texture. + const isText = usage === RenderDataUsage.Text; + // @ts-ignore + isText && rendererData.setTexture(RenderQueue._textureProperty, data.texture); + // union render global macro and material self macro. ShaderMacroCollection.unionCollection(renderer._globalShaderMacro, materialData._macroCollection, compileMacros); @@ -157,7 +165,7 @@ export class RenderQueue { if (program._uploadRendererId !== rendererId) { program.uploadAll(program.rendererUniformBlock, rendererData); program._uploadRendererId = rendererId; - } else if (switchProgram) { + } else if (switchProgram || isText) { program.uploadTextures(program.rendererUniformBlock, rendererData); } @@ -184,7 +192,7 @@ export class RenderQueue { rhi.drawPrimitive(primitive, data.subPrimitive, program); } - isSprite && spriteMaskManager.postRender(renderer); + needMask && spriteMaskManager.postRender(renderer); } } diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index f73ecfd124..6a6f1fc072 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -13,7 +13,6 @@ export class Batcher2D { static MAX_VERTEX_COUNT: number = 4096; protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - private static _textureProperty: ShaderProperty = ShaderProperty.getByName("renderer_SpriteTexture"); /** @internal */ _engine: Engine; @@ -58,10 +57,7 @@ export class Batcher2D { flush(): void { const { _preRenderData: preRenderData } = this; - if (preRenderData) { - preRenderData.component.shaderData.setTexture(Batcher2D._textureProperty, preRenderData.texture); - this._preContext.camera._renderPipeline.pushRenderData(this._preContext, preRenderData); - } + preRenderData && this._preContext.camera._renderPipeline.pushRenderData(this._preContext, preRenderData); } uploadBuffer(): void { diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts index f69331d275..d4e755b16e 100644 --- a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -49,6 +49,7 @@ export class BatcherManager { context.camera._renderPipeline.pushRenderData(context, data); break; case RenderDataUsage.Sprite: + case RenderDataUsage.Text: this._batcher2D.commitRenderData(context, data); break; } diff --git a/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts b/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts index 961b9c383f..f0acb5ff00 100644 --- a/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts +++ b/packages/core/src/RenderPipeline/enums/RenderDataUsage.ts @@ -7,5 +7,7 @@ export enum RenderDataUsage { /** Usage for sprite. */ Sprite, /** Usage for sprite mask. */ - SpriteMask + SpriteMask, + /** Usage for text. */ + Text } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 8fef89d5ae..94dbfbf082 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -63,5 +63,4 @@ export * from "./renderingHardwareInterface/index"; export * from "./physics/index"; export * from "./Utils"; -// Export for CanvasRenderer plugin. export { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; From ebd27df3a4a043294d086ae240deac5240b8745e Mon Sep 17 00:00:00 2001 From: singlecoder Date: Wed, 24 Apr 2024 11:09:21 +0800 Subject: [PATCH 025/218] feat(ui-init): init ui package --- packages/ui/README.md | 0 packages/ui/package.json | 35 +++++++++++++++++++++++++++++++++++ packages/ui/src/index.ts | 0 packages/ui/tsconfig.json | 18 ++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 packages/ui/README.md create mode 100644 packages/ui/package.json create mode 100644 packages/ui/src/index.ts create mode 100644 packages/ui/tsconfig.json diff --git a/packages/ui/README.md b/packages/ui/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/ui/package.json b/packages/ui/package.json new file mode 100644 index 0000000000..014f1dcc81 --- /dev/null +++ b/packages/ui/package.json @@ -0,0 +1,35 @@ +{ + "name": "@galacean/engine-ui", + "version": "1.2.0-beta.2", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org" + }, + "license": "MIT", + "main": "dist/main.js", + "module": "dist/module.js", + "debug": "src/index.ts", + "browser": "dist/browser.js", + "types": "types/index.d.ts", + "scripts": { + "b:types": "tsc" + }, + "umd": { + "name": "Galacean.UI", + "globals": { + "@galacean/engine": "Galacean" + } + }, + "files": [ + "dist/**/*", + "libs/**/*", + "types/**/*" + ], + "devDependencies": { + "@galacean/engine-design": "workspace:*", + "@galacean/engine": "workspace:*" + }, + "peerDependencies": { + "@galacean/engine": "workspace:*" + } +} diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json new file mode 100644 index 0000000000..7e27f46e81 --- /dev/null +++ b/packages/ui/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "module": "esnext", + "target": "esnext", + "declaration": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, + "declarationDir": "types", + "emitDeclarationOnly": true, + "noImplicitOverride": true, + "sourceMap": true, + "incremental": false, + "skipLibCheck": true, + "stripInternal": true + }, + "include": ["src/**/*"] +} From c98748f5623db1e1402effefbce7096be339f0cc Mon Sep 17 00:00:00 2001 From: singlecoder Date: Wed, 24 Apr 2024 17:28:30 +0800 Subject: [PATCH 026/218] feat(ui-init): add basic class --- packages/ui/src/UICanvas.ts | 3 +++ packages/ui/src/UIRenderer.ts | 3 +++ packages/ui/src/enums/CanvasRenderMode.ts | 8 ++++++++ packages/ui/src/enums/ScreenMathMode.ts | 10 ++++++++++ 4 files changed, 24 insertions(+) create mode 100644 packages/ui/src/UICanvas.ts create mode 100644 packages/ui/src/UIRenderer.ts create mode 100644 packages/ui/src/enums/CanvasRenderMode.ts create mode 100644 packages/ui/src/enums/ScreenMathMode.ts diff --git a/packages/ui/src/UICanvas.ts b/packages/ui/src/UICanvas.ts new file mode 100644 index 0000000000..3e77e39809 --- /dev/null +++ b/packages/ui/src/UICanvas.ts @@ -0,0 +1,3 @@ +import { Component } from "@galacean/engine"; + +export class UICanvas extends Component {} diff --git a/packages/ui/src/UIRenderer.ts b/packages/ui/src/UIRenderer.ts new file mode 100644 index 0000000000..b5f5b35f32 --- /dev/null +++ b/packages/ui/src/UIRenderer.ts @@ -0,0 +1,3 @@ +import { Renderer } from "@galacean/engine"; + +export class UIRenderer extends Renderer {} diff --git a/packages/ui/src/enums/CanvasRenderMode.ts b/packages/ui/src/enums/CanvasRenderMode.ts new file mode 100644 index 0000000000..aef4121cae --- /dev/null +++ b/packages/ui/src/enums/CanvasRenderMode.ts @@ -0,0 +1,8 @@ +/** + * Render mode for ui canvas. + */ +export enum CanvasRenderMode { + ScreenSpaceOverlay, + ScreenSpaceCamera, + WorldSpace +} diff --git a/packages/ui/src/enums/ScreenMathMode.ts b/packages/ui/src/enums/ScreenMathMode.ts new file mode 100644 index 0000000000..e317cffc2e --- /dev/null +++ b/packages/ui/src/enums/ScreenMathMode.ts @@ -0,0 +1,10 @@ +/** + * + */ +export enum ResolutionAdaptationStrategy { + WidthAdaptation, + HeightAdaptation, + BothAdaptation, + ExpandAdaptation, + ShrinkAdaptation +} From 7649de469fd0bfa53ccf34a5ac8ae64585cb804d Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 25 Apr 2024 15:11:37 +0800 Subject: [PATCH 027/218] refactor(2d-render-pipeline): rename the rendering order function of the renderer --- packages/core/src/RenderPipeline/CullingResults.ts | 6 +++--- packages/core/src/RenderPipeline/RenderQueue.ts | 4 ++-- packages/core/src/shadow/CascadedShadowCasterPass.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/core/src/RenderPipeline/CullingResults.ts b/packages/core/src/RenderPipeline/CullingResults.ts index deaf2b1e1a..9d48b55afb 100644 --- a/packages/core/src/RenderPipeline/CullingResults.ts +++ b/packages/core/src/RenderPipeline/CullingResults.ts @@ -24,9 +24,9 @@ export class CullingResults { } sort(): void { - this.opaqueQueue.sort(RenderQueue._compareFromNearToFar); - this.alphaTestQueue.sort(RenderQueue._compareFromNearToFar); - this.transparentQueue.sort(RenderQueue._compareFromFarToNear); + this.opaqueQueue.sort(RenderQueue._compareForOpaque); + this.alphaTestQueue.sort(RenderQueue._compareForOpaque); + this.transparentQueue.sort(RenderQueue._compareForTransparent); } destroy(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 3771857a9b..4e5a07a119 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -16,7 +16,7 @@ export class RenderQueue { /** * @internal */ - static _compareFromNearToFar(a: RenderElement, b: RenderElement): number { + static _compareForOpaque(a: RenderElement, b: RenderElement): number { const dataA = a.data; const dataB = b.data; const componentA = dataA.component; @@ -41,7 +41,7 @@ export class RenderQueue { /** * @internal */ - static _compareFromFarToNear(a: RenderElement, b: RenderElement): number { + static _compareForTransparent(a: RenderElement, b: RenderElement): number { const dataA = a.data; const dataB = b.data; const componentA = dataA.component; diff --git a/packages/core/src/shadow/CascadedShadowCasterPass.ts b/packages/core/src/shadow/CascadedShadowCasterPass.ts index b8e6a492f1..54aa81c181 100644 --- a/packages/core/src/shadow/CascadedShadowCasterPass.ts +++ b/packages/core/src/shadow/CascadedShadowCasterPass.ts @@ -218,8 +218,8 @@ export class CascadedShadowCasterPass extends PipelinePass { } if (opaqueQueue.elements.length || alphaTestQueue.elements.length) { - opaqueQueue.sort(RenderQueue._compareFromNearToFar); - alphaTestQueue.sort(RenderQueue._compareFromNearToFar); + opaqueQueue.sort(RenderQueue._compareForOpaque); + alphaTestQueue.sort(RenderQueue._compareForOpaque); const { x, y } = viewports[j]; From 68657e8fb6ecca8298ca704e2f5df4556dbf3004 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 25 Apr 2024 18:05:35 +0800 Subject: [PATCH 028/218] refactor(2d-render-pipeline): fix test --- tests/src/core/SpriteMask.test.ts | 21 +- tests/src/core/SpriteRenderer.test.ts | 2072 +++++++++++++------------ 2 files changed, 1116 insertions(+), 977 deletions(-) diff --git a/tests/src/core/SpriteMask.test.ts b/tests/src/core/SpriteMask.test.ts index d135714dc2..be0af2a2bb 100644 --- a/tests/src/core/SpriteMask.test.ts +++ b/tests/src/core/SpriteMask.test.ts @@ -166,8 +166,6 @@ describe("SpriteMask", async () => { spriteMask.sprite = new Sprite(engine, new Texture2D(engine, 100, 200)); spriteMask.destroy(); expect(spriteMask.sprite).to.eq(null); - // @ts-ignore - expect(spriteMask._verticesData).to.eq(null); }); it("_render", () => { @@ -178,7 +176,16 @@ describe("SpriteMask", async () => { // @ts-ignore spriteMask._render(context); // @ts-ignore - let { positions, uvs } = spriteMask._verticesData; + const { _chunk: chunk } = spriteMask; + const vertices = chunk._meshBuffer._vertices; + const positions: Array = []; + const uvs: Array = []; + let index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } expect(positions[0]).to.deep.eq(new Vector3(0, 0, 0)); expect(positions[1]).to.deep.eq(new Vector3(0, 0, 0)); expect(positions[2]).to.deep.eq(new Vector3(0, 0, 0)); @@ -197,6 +204,14 @@ describe("SpriteMask", async () => { spriteMask.sprite = sprite; // @ts-ignore spriteMask._render(context); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } // @ts-ignore expect(positions[0]).to.deep.eq(new Vector3(-0.5, -1, 0)); expect(positions[1]).to.deep.eq(new Vector3(0.5, -1, 0)); diff --git a/tests/src/core/SpriteRenderer.test.ts b/tests/src/core/SpriteRenderer.test.ts index f3a85f8467..d52ccf467a 100644 --- a/tests/src/core/SpriteRenderer.test.ts +++ b/tests/src/core/SpriteRenderer.test.ts @@ -184,48 +184,73 @@ describe("SpriteRenderer", async () => { spriteRenderer.width = 4; spriteRenderer.height = 5; // @ts-ignore - const renderData = spriteRenderer._verticesData; + const { _chunk: chunk } = spriteRenderer; + const vertices = chunk._meshBuffer._vertices; + const positions: Array = []; + const uvs: Array = []; + let index = chunk._vEntry.start; sprite.pivot = new Vector2(0.5, 0.5); // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(-2, -2.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(2, -2.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(-2, 2.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(2, 2.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 0))).to.eq(true); + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(-2, -2.5, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(2, -2.5, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(-2, 2.5, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(2, 2.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(1, 0))).to.eq(true); sprite.pivot = new Vector2(1, 1); // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(-4, -5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0, -5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(-4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(-4, -5, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0, -5, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(-4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(1, 0))).to.eq(true); sprite.pivot = new Vector2(0, 0); // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(4, 5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(4, 5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(1, 0))).to.eq(true); }); it("draw Sliced Sprite", () => { @@ -236,7 +261,11 @@ describe("SpriteRenderer", async () => { spriteRenderer.sprite = sprite; spriteRenderer.drawMode = SpriteDrawMode.Sliced; // @ts-ignore - const renderData = spriteRenderer._verticesData; + const { _chunk: chunk } = spriteRenderer; + const vertices = chunk._meshBuffer._vertices; + const positions: Array = []; + const uvs: Array = []; + let index = chunk._vEntry.start; sprite.pivot = new Vector2(0, 0); sprite.border = new Vector4(0.3, 0.3, 0.3, 0.3); spriteRenderer.width = 0.5; @@ -245,38 +274,43 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.25, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(0.25, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0.25, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(0.25, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(0.5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(0.5, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(0.5, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(0.5, 0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0))).to.eq(true); + for (let i = 0; i < 16; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(0.25, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(0.25, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(0.5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(0.5, 0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0))).to.eq(true); spriteRenderer.width = 15; spriteRenderer.height = 15; @@ -284,38 +318,46 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 14.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0, 15, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.6, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(0.6, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.6, 14.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(0.6, 15, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(14.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(14.4, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(14.4, 14.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(14.4, 15, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(15, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(15, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(15, 14.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(15, 15, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 16; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 14.1, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0, 15, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.6, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(0.6, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.6, 14.1, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(0.6, 15, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(14.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(14.4, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(14.4, 14.1, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(14.4, 15, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(15, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(15, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(15, 14.1, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(15, 15, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0))).to.eq(true); }); it("draw Tiled Sprite", () => { @@ -326,7 +368,11 @@ describe("SpriteRenderer", async () => { spriteRenderer.sprite = sprite; spriteRenderer.drawMode = SpriteDrawMode.Tiled; // @ts-ignore - const renderData = spriteRenderer._verticesData; + const { _chunk: chunk } = spriteRenderer; + const vertices = chunk._meshBuffer._vertices; + const positions: Array = []; + const uvs: Array = []; + let index = chunk._vEntry.start; spriteRenderer.width = 5; spriteRenderer.height = 5; sprite.pivot = new Vector2(0, 0); @@ -336,172 +382,185 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(1, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(1, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(4, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(5, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(1, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(1, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(4, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(5, 0.8999999999999999, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(5, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[16], new Vector3(0, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[17], new Vector3(1, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[18], new Vector3(0, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[19], new Vector3(1, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[20], new Vector3(4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[21], new Vector3(5, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[22], new Vector3(4, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[23], new Vector3(5, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[24], new Vector3(0, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[25], new Vector3(1, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[26], new Vector3(0, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[27], new Vector3(1, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[28], new Vector3(4, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[29], new Vector3(5, 3.3000000000000003, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[30], new Vector3(4, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[31], new Vector3(5, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[32], new Vector3(0, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[33], new Vector3(1, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[34], new Vector3(0, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[35], new Vector3(1, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[36], new Vector3(4, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[37], new Vector3(5, 4.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[38], new Vector3(4, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[39], new Vector3(5, 5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.5, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.5, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[16], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[17], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[18], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[19], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[20], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[21], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[22], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[23], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[24], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[25], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[26], new Vector2(0, 0.43333333333333335))).to.eq(true); - expect(Vector2.equals(renderData.uvs[27], new Vector2(0.5, 0.43333333333333335))).to.eq(true); - expect(Vector2.equals(renderData.uvs[28], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[29], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[30], new Vector2(0.5, 0.43333333333333335))).to.eq(true); - expect(Vector2.equals(renderData.uvs[31], new Vector2(1, 0.43333333333333335))).to.eq(true); - expect(Vector2.equals(renderData.uvs[32], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[33], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[34], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[35], new Vector2(0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[36], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[37], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[38], new Vector2(0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[39], new Vector2(1, 0))).to.eq(true); + for (let i = 0; i < 40; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(1, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(1, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(4, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(5, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(1, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(1, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(4, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(5, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(5, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[16], new Vector3(0, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[17], new Vector3(1, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[18], new Vector3(0, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[19], new Vector3(1, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[20], new Vector3(4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[21], new Vector3(5, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[22], new Vector3(4, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[23], new Vector3(5, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[24], new Vector3(0, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[25], new Vector3(1, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[26], new Vector3(0, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[27], new Vector3(1, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[28], new Vector3(4, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[29], new Vector3(5, 3.3000000000000003, 0))).to.eq(true); + expect(Vector3.equals(positions[30], new Vector3(4, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[31], new Vector3(5, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[32], new Vector3(0, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[33], new Vector3(1, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[34], new Vector3(0, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[35], new Vector3(1, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[36], new Vector3(4, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[37], new Vector3(5, 4.1, 0))).to.eq(true); + expect(Vector3.equals(positions[38], new Vector3(4, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[39], new Vector3(5, 5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.5, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.5, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[16], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[17], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[18], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[19], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[20], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[21], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[22], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[23], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[24], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[25], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[26], new Vector2(0, 0.43333333333333335))).to.eq(true); + expect(Vector2.equals(uvs[27], new Vector2(0.5, 0.43333333333333335))).to.eq(true); + expect(Vector2.equals(uvs[28], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[29], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[30], new Vector2(0.5, 0.43333333333333335))).to.eq(true); + expect(Vector2.equals(uvs[31], new Vector2(1, 0.43333333333333335))).to.eq(true); + expect(Vector2.equals(uvs[32], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[33], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[34], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[35], new Vector2(0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[36], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[37], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[38], new Vector2(0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[39], new Vector2(1, 0))).to.eq(true); spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(1, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(1, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(4, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(5, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(1, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(1, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(4, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(5, 0.8333333333333331, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(4, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(5, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[16], new Vector3(0, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[17], new Vector3(1, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[18], new Vector3(0, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[19], new Vector3(1, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[20], new Vector3(4, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[21], new Vector3(5, 2.011111111111111, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[22], new Vector3(4, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[23], new Vector3(5, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[24], new Vector3(0, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[25], new Vector3(1, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[26], new Vector3(0, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[27], new Vector3(1, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[28], new Vector3(4, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[29], new Vector3(5, 3.1222222222222222, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[30], new Vector3(4, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[31], new Vector3(5, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[32], new Vector3(0, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[33], new Vector3(1, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[34], new Vector3(0, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[35], new Vector3(1, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[36], new Vector3(4, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[37], new Vector3(5, 4.166666666666667, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[38], new Vector3(4, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[39], new Vector3(5, 5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.5, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.5, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[16], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[17], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[18], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[19], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[20], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[21], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[22], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[23], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[24], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[25], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[26], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[27], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[28], new Vector2(0.5, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[29], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[30], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[31], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[32], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[33], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[34], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[35], new Vector2(0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[36], new Vector2(0.5, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[37], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[38], new Vector2(0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[39], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 40; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(1, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(1, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(4, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(5, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(1, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(1, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(4, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(5, 0.8333333333333331, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(4, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(5, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[16], new Vector3(0, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[17], new Vector3(1, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[18], new Vector3(0, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[19], new Vector3(1, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[20], new Vector3(4, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[21], new Vector3(5, 2.011111111111111, 0))).to.eq(true); + expect(Vector3.equals(positions[22], new Vector3(4, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[23], new Vector3(5, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[24], new Vector3(0, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[25], new Vector3(1, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[26], new Vector3(0, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[27], new Vector3(1, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[28], new Vector3(4, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[29], new Vector3(5, 3.1222222222222222, 0))).to.eq(true); + expect(Vector3.equals(positions[30], new Vector3(4, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[31], new Vector3(5, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[32], new Vector3(0, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[33], new Vector3(1, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[34], new Vector3(0, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[35], new Vector3(1, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[36], new Vector3(4, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[37], new Vector3(5, 4.166666666666667, 0))).to.eq(true); + expect(Vector3.equals(positions[38], new Vector3(4, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[39], new Vector3(5, 5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.5, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.5, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[16], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[17], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[18], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[19], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[20], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[21], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[22], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[23], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[24], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[25], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[26], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[27], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[28], new Vector2(0.5, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[29], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[30], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[31], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[32], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[33], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[34], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[35], new Vector2(0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[36], new Vector2(0.5, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[37], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[38], new Vector2(0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[39], new Vector2(1, 0))).to.eq(true); sprite.border = new Vector4(0.3, 0.5, 0.3, 0.5); spriteRenderer.tileMode = SpriteTileMode.Continuous; @@ -509,236 +568,252 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.6, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.6, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.6, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(1.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.6, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(1.4, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(1.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(2.2, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(1.4, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(2.2, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(2.2, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(3.0000000000000004, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(2.2, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(3.0000000000000004, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[16], new Vector3(3.0000000000000004, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[17], new Vector3(3.8000000000000003, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[18], new Vector3(3.0000000000000004, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[19], new Vector3(3.8000000000000003, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[20], new Vector3(3.8000000000000003, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[21], new Vector3(4.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[22], new Vector3(3.8000000000000003, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[23], new Vector3(4.4, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[24], new Vector3(4.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[25], new Vector3(5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[26], new Vector3(4.4, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[27], new Vector3(5, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[28], new Vector3(0, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[29], new Vector3(0.6, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[30], new Vector3(0, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[31], new Vector3(0.6, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[32], new Vector3(0.6, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[33], new Vector3(1.4, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[34], new Vector3(0.6, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[35], new Vector3(1.4, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[36], new Vector3(1.4, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[37], new Vector3(2.2, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[38], new Vector3(1.4, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[39], new Vector3(2.2, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[40], new Vector3(2.2, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[41], new Vector3(3.0000000000000004, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[42], new Vector3(2.2, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[43], new Vector3(3.0000000000000004, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[44], new Vector3(3.0000000000000004, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[45], new Vector3(3.8000000000000003, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[46], new Vector3(3.0000000000000004, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[47], new Vector3(3.8000000000000003, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[48], new Vector3(3.8000000000000003, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[49], new Vector3(4.4, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[50], new Vector3(3.8000000000000003, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[51], new Vector3(4.4, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[52], new Vector3(4.4, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[53], new Vector3(5, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[54], new Vector3(4.4, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[55], new Vector3(5, 5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[16], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[17], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[18], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[19], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[20], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[21], new Vector2(0.5999999999999996, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[22], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[23], new Vector2(0.5999999999999996, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[24], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[25], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[26], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[27], new Vector2(1, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[28], new Vector2(0, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[29], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[30], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[31], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[32], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[33], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[34], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[35], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[36], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[37], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[38], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[39], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[40], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[41], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[42], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[43], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[44], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[45], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[46], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[47], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[48], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[49], new Vector2(0.5999999999999996, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[50], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[51], new Vector2(0.5999999999999996, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[52], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[53], new Vector2(1, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[54], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[55], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 56; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.6, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.6, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.6, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(1.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.6, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(1.4, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(1.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(2.2, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(1.4, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(2.2, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(2.2, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(3.0000000000000004, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(2.2, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(3.0000000000000004, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[16], new Vector3(3.0000000000000004, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[17], new Vector3(3.8000000000000003, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[18], new Vector3(3.0000000000000004, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[19], new Vector3(3.8000000000000003, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[20], new Vector3(3.8000000000000003, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[21], new Vector3(4.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[22], new Vector3(3.8000000000000003, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[23], new Vector3(4.4, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[24], new Vector3(4.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[25], new Vector3(5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[26], new Vector3(4.4, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[27], new Vector3(5, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[28], new Vector3(0, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[29], new Vector3(0.6, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[30], new Vector3(0, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[31], new Vector3(0.6, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[32], new Vector3(0.6, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[33], new Vector3(1.4, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[34], new Vector3(0.6, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[35], new Vector3(1.4, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[36], new Vector3(1.4, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[37], new Vector3(2.2, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[38], new Vector3(1.4, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[39], new Vector3(2.2, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[40], new Vector3(2.2, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[41], new Vector3(3.0000000000000004, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[42], new Vector3(2.2, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[43], new Vector3(3.0000000000000004, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[44], new Vector3(3.0000000000000004, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[45], new Vector3(3.8000000000000003, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[46], new Vector3(3.0000000000000004, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[47], new Vector3(3.8000000000000003, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[48], new Vector3(3.8000000000000003, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[49], new Vector3(4.4, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[50], new Vector3(3.8000000000000003, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[51], new Vector3(4.4, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[52], new Vector3(4.4, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[53], new Vector3(5, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[54], new Vector3(4.4, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[55], new Vector3(5, 5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[16], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[17], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[18], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[19], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[20], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[21], new Vector2(0.5999999999999996, 1))).to.eq(true); + expect(Vector2.equals(uvs[22], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[23], new Vector2(0.5999999999999996, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[24], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[25], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[26], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[27], new Vector2(1, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[28], new Vector2(0, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[29], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[30], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[31], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[32], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[33], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[34], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[35], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[36], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[37], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[38], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[39], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[40], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[41], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[42], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[43], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[44], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[45], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[46], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[47], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[48], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[49], new Vector2(0.5999999999999996, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[50], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[51], new Vector2(0.5999999999999996, 0))).to.eq(true); + expect(Vector2.equals(uvs[52], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[53], new Vector2(1, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[54], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[55], new Vector2(1, 0))).to.eq(true); spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.5769230769230769, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.5769230769230769, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.5769230769230769, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(1.3692307692307693, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.5769230769230769, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(1.3692307692307693, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(1.3692307692307693, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(2.1384615384615384, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(1.3692307692307693, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(2.1384615384615384, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(2.1384615384615384, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(2.907692307692308, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(2.1384615384615384, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(2.907692307692308, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[16], new Vector3(2.907692307692308, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[17], new Vector3(3.6769230769230767, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[18], new Vector3(2.907692307692308, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[19], new Vector3(3.6769230769230767, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[20], new Vector3(3.6769230769230767, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[21], new Vector3(4.423076923076923, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[22], new Vector3(3.6769230769230767, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[23], new Vector3(4.423076923076923, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[24], new Vector3(4.423076923076923, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[25], new Vector3(5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[26], new Vector3(4.423076923076923, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[27], new Vector3(5, 1.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[28], new Vector3(0, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[29], new Vector3(0.5769230769230769, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[30], new Vector3(0, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[31], new Vector3(0.5769230769230769, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[32], new Vector3(0.5769230769230769, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[33], new Vector3(1.3692307692307693, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[34], new Vector3(0.5769230769230769, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[35], new Vector3(1.3692307692307693, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[36], new Vector3(1.3692307692307693, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[37], new Vector3(2.1384615384615384, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[38], new Vector3(1.3692307692307693, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[39], new Vector3(2.1384615384615384, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[40], new Vector3(2.1384615384615384, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[41], new Vector3(2.907692307692308, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[42], new Vector3(2.1384615384615384, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[43], new Vector3(2.907692307692308, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[44], new Vector3(2.907692307692308, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[45], new Vector3(3.6769230769230767, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[46], new Vector3(2.907692307692308, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[47], new Vector3(3.6769230769230767, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[48], new Vector3(3.6769230769230767, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[49], new Vector3(4.423076923076923, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[50], new Vector3(3.6769230769230767, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[51], new Vector3(4.423076923076923, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[52], new Vector3(4.423076923076923, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[53], new Vector3(5, 3.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[54], new Vector3(4.423076923076923, 5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[55], new Vector3(5, 5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[16], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[17], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[18], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[19], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[20], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[21], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[22], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[23], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[24], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[25], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[26], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[27], new Vector2(1, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[28], new Vector2(0, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[29], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[30], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[31], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[32], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[33], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[34], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[35], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[36], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[37], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[38], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[39], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[40], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[41], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[42], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[43], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[44], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[45], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[46], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[47], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[48], new Vector2(0.3, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[49], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[50], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[51], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[52], new Vector2(0.7, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[53], new Vector2(1, 0.5))).to.eq(true); - expect(Vector2.equals(renderData.uvs[54], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[55], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 56; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.5769230769230769, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.5769230769230769, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.5769230769230769, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(1.3692307692307693, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.5769230769230769, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(1.3692307692307693, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(1.3692307692307693, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(2.1384615384615384, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(1.3692307692307693, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(2.1384615384615384, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(2.1384615384615384, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(2.907692307692308, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(2.1384615384615384, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(2.907692307692308, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[16], new Vector3(2.907692307692308, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[17], new Vector3(3.6769230769230767, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[18], new Vector3(2.907692307692308, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[19], new Vector3(3.6769230769230767, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[20], new Vector3(3.6769230769230767, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[21], new Vector3(4.423076923076923, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[22], new Vector3(3.6769230769230767, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[23], new Vector3(4.423076923076923, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[24], new Vector3(4.423076923076923, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[25], new Vector3(5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[26], new Vector3(4.423076923076923, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[27], new Vector3(5, 1.5, 0))).to.eq(true); + expect(Vector3.equals(positions[28], new Vector3(0, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[29], new Vector3(0.5769230769230769, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[30], new Vector3(0, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[31], new Vector3(0.5769230769230769, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[32], new Vector3(0.5769230769230769, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[33], new Vector3(1.3692307692307693, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[34], new Vector3(0.5769230769230769, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[35], new Vector3(1.3692307692307693, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[36], new Vector3(1.3692307692307693, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[37], new Vector3(2.1384615384615384, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[38], new Vector3(1.3692307692307693, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[39], new Vector3(2.1384615384615384, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[40], new Vector3(2.1384615384615384, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[41], new Vector3(2.907692307692308, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[42], new Vector3(2.1384615384615384, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[43], new Vector3(2.907692307692308, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[44], new Vector3(2.907692307692308, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[45], new Vector3(3.6769230769230767, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[46], new Vector3(2.907692307692308, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[47], new Vector3(3.6769230769230767, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[48], new Vector3(3.6769230769230767, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[49], new Vector3(4.423076923076923, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[50], new Vector3(3.6769230769230767, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[51], new Vector3(4.423076923076923, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[52], new Vector3(4.423076923076923, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[53], new Vector3(5, 3.5, 0))).to.eq(true); + expect(Vector3.equals(positions[54], new Vector3(4.423076923076923, 5, 0))).to.eq(true); + expect(Vector3.equals(positions[55], new Vector3(5, 5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[16], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[17], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[18], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[19], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[20], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[21], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[22], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[23], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[24], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[25], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[26], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[27], new Vector2(1, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[28], new Vector2(0, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[29], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[30], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[31], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[32], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[33], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[34], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[35], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[36], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[37], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[38], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[39], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[40], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[41], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[42], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[43], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[44], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[45], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[46], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[47], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[48], new Vector2(0.3, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[49], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[50], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[51], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[52], new Vector2(0.7, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[53], new Vector2(1, 0.5))).to.eq(true); + expect(Vector2.equals(uvs[54], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[55], new Vector2(1, 0))).to.eq(true); sprite.border = new Vector4(0.3, 0.3, 0.3, 0.3); spriteRenderer.width = 0.5; @@ -748,76 +823,92 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.25, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.25, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(0.5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(0.5, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(0.25, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(0.5, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(0.25, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(0.5, 0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 16; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(0.5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(0.25, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(0.25, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(0.5, 0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0))).to.eq(true); spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.25, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.25, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(0.5, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(0.5, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(0.25, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(0.25, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(0.5, 0.25, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(0.25, 0.5, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(0.5, 0.5, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 16; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(0.5, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(0.25, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(0.25, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(0.25, 0.5, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(0.5, 0.5, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0))).to.eq(true); spriteRenderer.width = 0.01; spriteRenderer.height = 0.01; @@ -826,76 +917,92 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.005, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.005, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(0.01, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(0.01, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0, 0.01, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(0.005, 0.01, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(0.01, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(0.005, 0.01, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(0.01, 0.01, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 16; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.005, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.005, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(0.01, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(0.01, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0, 0.01, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(0.005, 0.01, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(0.01, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(0.005, 0.01, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(0.01, 0.01, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0))).to.eq(true); spriteRenderer.tileMode = SpriteTileMode.Continuous; // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.005, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.005, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(0.01, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(0.01, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(0, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(0, 0.01, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(0.005, 0.01, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(0.005, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(0.01, 0.005, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(0.005, 0.01, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(0.01, 0.01, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 16; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.005, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.005, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(0.01, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(0.01, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(0, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(0, 0.01, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(0.005, 0.01, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(0.005, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(0.01, 0.005, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(0.005, 0.01, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(0.01, 0.01, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0))).to.eq(true); spriteRenderer.width = 100000; spriteRenderer.height = 100000; @@ -904,28 +1011,44 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(100000, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 100000, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(100000, 100000, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(100000, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 100000, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(100000, 100000, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(1, 0))).to.eq(true); spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(100000, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 100000, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(100000, 100000, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(100000, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 100000, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(100000, 100000, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(1, 0))).to.eq(true); spriteRenderer.width = 3; spriteRenderer.height = 4; @@ -934,364 +1057,348 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.6, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.6, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.6, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(1.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.6, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(1.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(1.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(2.2, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(1.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(2.2, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(2.2, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(2.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(2.2, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(2.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[16], new Vector3(2.4, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[17], new Vector3(3, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[18], new Vector3(2.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[19], new Vector3(3, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[20], new Vector3(0, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[21], new Vector3(0.6, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[22], new Vector3(0, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[23], new Vector3(0.6, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[24], new Vector3(0.6, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[25], new Vector3(1.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[26], new Vector3(0.6, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[27], new Vector3(1.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[28], new Vector3(1.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[29], new Vector3(2.2, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[30], new Vector3(1.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[31], new Vector3(2.2, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[32], new Vector3(2.2, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[33], new Vector3(2.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[34], new Vector3(2.2, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[35], new Vector3(2.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[36], new Vector3(2.4, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[37], new Vector3(3, 0.9, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[38], new Vector3(2.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[39], new Vector3(3, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[40], new Vector3(0, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[41], new Vector3(0.6, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[42], new Vector3(0, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[43], new Vector3(0.6, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[44], new Vector3(0.6, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[45], new Vector3(1.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[46], new Vector3(0.6, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[47], new Vector3(1.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[48], new Vector3(1.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[49], new Vector3(2.2, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[50], new Vector3(1.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[51], new Vector3(2.2, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[52], new Vector3(2.2, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[53], new Vector3(2.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[54], new Vector3(2.2, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[55], new Vector3(2.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[56], new Vector3(2.4, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[57], new Vector3(3, 2.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[58], new Vector3(2.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[59], new Vector3(3, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[60], new Vector3(0, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[61], new Vector3(0.6, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[62], new Vector3(0, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[63], new Vector3(0.6, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[64], new Vector3(0.6, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[65], new Vector3(1.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[66], new Vector3(0.6, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[67], new Vector3(1.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[68], new Vector3(1.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[69], new Vector3(2.2, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[70], new Vector3(1.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[71], new Vector3(2.2, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[72], new Vector3(2.2, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[73], new Vector3(2.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[74], new Vector3(2.2, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[75], new Vector3(2.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[76], new Vector3(2.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[77], new Vector3(3, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[78], new Vector3(2.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[79], new Vector3(3, 4, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(0.4, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(0.4, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[16], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[17], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[18], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[19], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[20], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[21], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[22], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[23], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[24], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[25], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[26], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[27], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[28], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[29], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[30], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[31], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[32], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[33], new Vector2(0.4, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[34], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[35], new Vector2(0.4, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[36], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[37], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[38], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[39], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[40], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[41], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[42], new Vector2(0, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[43], new Vector2(0.3, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[44], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[45], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[46], new Vector2(0.3, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[47], new Vector2(0.7, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[48], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[49], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[50], new Vector2(0.3, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[51], new Vector2(0.7, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[52], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[53], new Vector2(0.4, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[54], new Vector2(0.3, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[55], new Vector2(0.4, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[56], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[57], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[58], new Vector2(0.7, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[59], new Vector2(1, 0.3666666666666667))).to.eq(true); - expect(Vector2.equals(renderData.uvs[60], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[61], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[62], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[63], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[64], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[65], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[66], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[67], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[68], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[69], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[70], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[71], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[72], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[73], new Vector2(0.4, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[74], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[75], new Vector2(0.4, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[76], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[77], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[78], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[79], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 80; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.6, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.6, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.6, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(1.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.6, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(1.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(1.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(2.2, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(1.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(2.2, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(2.2, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(2.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(2.2, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(2.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[16], new Vector3(2.4, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[17], new Vector3(3, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[18], new Vector3(2.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[19], new Vector3(3, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[20], new Vector3(0, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[21], new Vector3(0.6, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[22], new Vector3(0, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[23], new Vector3(0.6, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[24], new Vector3(0.6, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[25], new Vector3(1.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[26], new Vector3(0.6, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[27], new Vector3(1.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[28], new Vector3(1.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[29], new Vector3(2.2, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[30], new Vector3(1.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[31], new Vector3(2.2, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[32], new Vector3(2.2, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[33], new Vector3(2.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[34], new Vector3(2.2, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[35], new Vector3(2.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[36], new Vector3(2.4, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[37], new Vector3(3, 0.9, 0))).to.eq(true); + expect(Vector3.equals(positions[38], new Vector3(2.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[39], new Vector3(3, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[40], new Vector3(0, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[41], new Vector3(0.6, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[42], new Vector3(0, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[43], new Vector3(0.6, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[44], new Vector3(0.6, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[45], new Vector3(1.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[46], new Vector3(0.6, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[47], new Vector3(1.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[48], new Vector3(1.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[49], new Vector3(2.2, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[50], new Vector3(1.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[51], new Vector3(2.2, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[52], new Vector3(2.2, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[53], new Vector3(2.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[54], new Vector3(2.2, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[55], new Vector3(2.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[56], new Vector3(2.4, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[57], new Vector3(3, 2.1, 0))).to.eq(true); + expect(Vector3.equals(positions[58], new Vector3(2.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[59], new Vector3(3, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[60], new Vector3(0, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[61], new Vector3(0.6, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[62], new Vector3(0, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[63], new Vector3(0.6, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[64], new Vector3(0.6, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[65], new Vector3(1.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[66], new Vector3(0.6, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[67], new Vector3(1.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[68], new Vector3(1.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[69], new Vector3(2.2, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[70], new Vector3(1.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[71], new Vector3(2.2, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[72], new Vector3(2.2, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[73], new Vector3(2.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[74], new Vector3(2.2, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[75], new Vector3(2.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[76], new Vector3(2.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[77], new Vector3(3, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[78], new Vector3(2.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[79], new Vector3(3, 4, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(0.4, 1))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(0.4, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[16], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[17], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[18], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[19], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[20], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[21], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[22], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[23], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[24], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[25], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[26], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[27], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[28], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[29], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[30], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[31], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[32], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[33], new Vector2(0.4, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[34], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[35], new Vector2(0.4, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[36], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[37], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[38], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[39], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[40], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[41], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[42], new Vector2(0, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[43], new Vector2(0.3, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[44], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[45], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[46], new Vector2(0.3, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[47], new Vector2(0.7, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[48], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[49], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[50], new Vector2(0.3, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[51], new Vector2(0.7, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[52], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[53], new Vector2(0.4, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[54], new Vector2(0.3, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[55], new Vector2(0.4, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[56], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[57], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[58], new Vector2(0.7, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[59], new Vector2(1, 0.3666666666666667))).to.eq(true); + expect(Vector2.equals(uvs[60], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[61], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[62], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[63], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[64], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[65], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[66], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[67], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[68], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[69], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[70], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[71], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[72], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[73], new Vector2(0.4, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[74], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[75], new Vector2(0.4, 0))).to.eq(true); + expect(Vector2.equals(uvs[76], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[77], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[78], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[79], new Vector2(1, 0))).to.eq(true); spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - expect(Vector3.equals(renderData.positions[0], new Vector3(0, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[1], new Vector3(0.6428571428571428, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[2], new Vector3(0, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[3], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[4], new Vector3(0.6428571428571428, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[5], new Vector3(1.4571428571428573, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[6], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[7], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[8], new Vector3(1.4571428571428573, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[9], new Vector3(2.357142857142857, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[10], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[11], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[12], new Vector3(2.357142857142857, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[13], new Vector3(3, 0, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[14], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[15], new Vector3(3, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[16], new Vector3(0, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[17], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[18], new Vector3(0, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[19], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[20], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[21], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[22], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[23], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[24], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[25], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[26], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[27], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[28], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[29], new Vector3(3, 0.857142857142857, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[30], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[31], new Vector3(3, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[32], new Vector3(0, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[33], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[34], new Vector3(0, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[35], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[36], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[37], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[38], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[39], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[40], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[41], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[42], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[43], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[44], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[45], new Vector3(3, 2.0428571428571427, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[46], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[47], new Vector3(3, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[48], new Vector3(0, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[49], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[50], new Vector3(0, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[51], new Vector3(0.6428571428571428, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[52], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[53], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[54], new Vector3(0.6428571428571428, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[55], new Vector3(1.4571428571428573, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[56], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq( - true - ); - expect(Vector3.equals(renderData.positions[57], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[58], new Vector3(1.4571428571428573, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[59], new Vector3(2.357142857142857, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[60], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[61], new Vector3(3, 3.1428571428571432, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[62], new Vector3(2.357142857142857, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[63], new Vector3(3, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[64], new Vector3(0.6, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[65], new Vector3(1.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[66], new Vector3(0.6, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[67], new Vector3(1.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[68], new Vector3(1.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[69], new Vector3(2.2, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[70], new Vector3(1.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[71], new Vector3(2.2, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[72], new Vector3(2.2, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[73], new Vector3(2.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[74], new Vector3(2.2, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[75], new Vector3(2.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[76], new Vector3(2.4, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[77], new Vector3(3, 3.1, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[78], new Vector3(2.4, 4, 0))).to.eq(true); - expect(Vector3.equals(renderData.positions[79], new Vector3(3, 4, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[0], new Vector2(0, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[1], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[2], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[3], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[4], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[5], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[6], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[7], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[8], new Vector2(0.3, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[9], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[10], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[11], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[12], new Vector2(0.7, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[13], new Vector2(1, 1))).to.eq(true); - expect(Vector2.equals(renderData.uvs[14], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[15], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[16], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[17], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[18], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[19], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[20], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[21], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[22], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[23], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[24], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[25], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[26], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[27], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[28], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[29], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[30], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[31], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[32], new Vector2(0, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[33], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[34], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[35], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[36], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[37], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[38], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[39], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[40], new Vector2(0.3, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[41], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[42], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[43], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[44], new Vector2(0.7, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[45], new Vector2(1, 0.7))).to.eq(true); - expect(Vector2.equals(renderData.uvs[46], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[47], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[48], new Vector2(0, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[49], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[50], new Vector2(0, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[51], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[52], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[53], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[54], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[55], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[56], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[57], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[58], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[59], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[60], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[61], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[62], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[63], new Vector2(1, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[64], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[65], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[66], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[67], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[68], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[69], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[70], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[71], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[72], new Vector2(0.3, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[73], new Vector2(0.4, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[74], new Vector2(0.3, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[75], new Vector2(0.4, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[76], new Vector2(0.7, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[77], new Vector2(1, 0.3))).to.eq(true); - expect(Vector2.equals(renderData.uvs[78], new Vector2(0.7, 0))).to.eq(true); - expect(Vector2.equals(renderData.uvs[79], new Vector2(1, 0))).to.eq(true); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 80; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } + expect(Vector3.equals(positions[0], new Vector3(0, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[1], new Vector3(0.6428571428571428, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[2], new Vector3(0, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[3], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[4], new Vector3(0.6428571428571428, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[5], new Vector3(1.4571428571428573, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[6], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[7], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[8], new Vector3(1.4571428571428573, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[9], new Vector3(2.357142857142857, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[10], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[11], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[12], new Vector3(2.357142857142857, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[13], new Vector3(3, 0, 0))).to.eq(true); + expect(Vector3.equals(positions[14], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[15], new Vector3(3, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[16], new Vector3(0, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[17], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[18], new Vector3(0, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[19], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[20], new Vector3(0.6428571428571428, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[21], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[22], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[23], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[24], new Vector3(1.4571428571428573, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[25], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[26], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[27], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[28], new Vector3(2.357142857142857, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[29], new Vector3(3, 0.857142857142857, 0))).to.eq(true); + expect(Vector3.equals(positions[30], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[31], new Vector3(3, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[32], new Vector3(0, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[33], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[34], new Vector3(0, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[35], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[36], new Vector3(0.6428571428571428, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[37], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[38], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[39], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[40], new Vector3(1.4571428571428573, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[41], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[42], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[43], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[44], new Vector3(2.357142857142857, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[45], new Vector3(3, 2.0428571428571427, 0))).to.eq(true); + expect(Vector3.equals(positions[46], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[47], new Vector3(3, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[48], new Vector3(0, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[49], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[50], new Vector3(0, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[51], new Vector3(0.6428571428571428, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[52], new Vector3(0.6428571428571428, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[53], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[54], new Vector3(0.6428571428571428, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[55], new Vector3(1.4571428571428573, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[56], new Vector3(1.4571428571428573, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[57], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[58], new Vector3(1.4571428571428573, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[59], new Vector3(2.357142857142857, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[60], new Vector3(2.357142857142857, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[61], new Vector3(3, 3.1428571428571432, 0))).to.eq(true); + expect(Vector3.equals(positions[62], new Vector3(2.357142857142857, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[63], new Vector3(3, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[64], new Vector3(0.6, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[65], new Vector3(1.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[66], new Vector3(0.6, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[67], new Vector3(1.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[68], new Vector3(1.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[69], new Vector3(2.2, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[70], new Vector3(1.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[71], new Vector3(2.2, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[72], new Vector3(2.2, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[73], new Vector3(2.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[74], new Vector3(2.2, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[75], new Vector3(2.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[76], new Vector3(2.4, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[77], new Vector3(3, 3.1, 0))).to.eq(true); + expect(Vector3.equals(positions[78], new Vector3(2.4, 4, 0))).to.eq(true); + expect(Vector3.equals(positions[79], new Vector3(3, 4, 0))).to.eq(true); + expect(Vector2.equals(uvs[0], new Vector2(0, 1))).to.eq(true); + expect(Vector2.equals(uvs[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[2], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[3], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[4], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[5], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[6], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[7], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[8], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(uvs[9], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[10], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[11], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[12], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(uvs[13], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(uvs[14], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[15], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[16], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[17], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[18], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[19], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[20], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[21], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[22], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[23], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[24], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[25], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[26], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[27], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[28], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[29], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[30], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[31], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[32], new Vector2(0, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[33], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[34], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[35], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[36], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[37], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[38], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[39], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[40], new Vector2(0.3, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[41], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[42], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[43], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[44], new Vector2(0.7, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[45], new Vector2(1, 0.7))).to.eq(true); + expect(Vector2.equals(uvs[46], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[47], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[48], new Vector2(0, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[49], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[50], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(uvs[51], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[52], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[53], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[54], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[55], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[56], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[57], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[58], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[59], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[60], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[61], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[62], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[63], new Vector2(1, 0))).to.eq(true); + expect(Vector2.equals(uvs[64], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[65], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[66], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[67], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[68], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[69], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[70], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[71], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[72], new Vector2(0.3, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[73], new Vector2(0.4, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[74], new Vector2(0.3, 0))).to.eq(true); + expect(Vector2.equals(uvs[75], new Vector2(0.4, 0))).to.eq(true); + expect(Vector2.equals(uvs[76], new Vector2(0.7, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[77], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(uvs[78], new Vector2(0.7, 0))).to.eq(true); + expect(Vector2.equals(uvs[79], new Vector2(1, 0))).to.eq(true); }); it("get set maskLayer", () => { @@ -1435,18 +1542,27 @@ describe("SpriteRenderer", async () => { // @ts-ignore expect(spriteRenderer._assembler).to.eq(null); // @ts-ignore - expect(spriteRenderer._verticesData).to.eq(null); + expect(spriteRenderer._chunk).to.eq(null); }); it("_render", () => { const rootEntity = scene.getRootEntity(); const spriteRenderer = rootEntity.addComponent(SpriteRenderer); const texture2d = new Texture2D(engine, 100, 200); - const context = { camera: { _renderPipeline: { pushRenderData: () => {} } } }; + const context = { camera: { engine: engine, _renderPipeline: { pushRenderData: () => {} } } }; // @ts-ignore spriteRenderer._render(context); // @ts-ignore - let { positions, uvs } = spriteRenderer._verticesData; + const { _chunk: chunk } = spriteRenderer; + const vertices = chunk._meshBuffer._vertices; + const positions: Array = []; + const uvs: Array = []; + let index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } expect(positions[0]).to.deep.eq(new Vector3(0, 0, 0)); expect(positions[1]).to.deep.eq(new Vector3(0, 0, 0)); expect(positions[2]).to.deep.eq(new Vector3(0, 0, 0)); @@ -1465,6 +1581,14 @@ describe("SpriteRenderer", async () => { spriteRenderer.sprite = sprite; // @ts-ignore spriteRenderer._render(context); + positions.length = 0; + uvs.length = 0; + index = chunk._vEntry.start; + for (let i = 0; i < 4; ++i) { + positions.push(new Vector3(vertices[index], vertices[index + 1], vertices[index + 2])); + uvs.push(new Vector2(vertices[index + 3], vertices[index + 4])); + index += 9; + } // @ts-ignore expect(positions[0]).to.deep.eq(new Vector3(-0.5, -1, 0)); expect(positions[1]).to.deep.eq(new Vector3(0.5, -1, 0)); From c95c0c2a448489e3f126240c3b23bd126abf4af1 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 26 Apr 2024 11:23:34 +0800 Subject: [PATCH 029/218] refactor(2d-render-pipeline): fix test error --- packages/core/src/2d/text/TextRenderer.ts | 10 ++++++++++ packages/core/src/2d/text/TextUtils.ts | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index d6f43a14d9..e68f1dd670 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -267,6 +267,16 @@ export class TextRenderer extends Renderer { this._maskLayer = value; } + /** + * The sub font. + */ + get subFont(): SubFont { + if (!this._subFont) { + this._resetSubFont(); + } + return this._subFont; + } + /** * The bounding volume of the TextRenderer. */ diff --git a/packages/core/src/2d/text/TextUtils.ts b/packages/core/src/2d/text/TextUtils.ts index 214bddb517..e71287be3d 100644 --- a/packages/core/src/2d/text/TextUtils.ts +++ b/packages/core/src/2d/text/TextUtils.ts @@ -97,7 +97,7 @@ export class TextUtils { } static measureTextWithWrap(renderer: TextRenderer): TextMetrics { - const subFont = renderer._subFont; + const { subFont } = renderer; const fontString = subFont.nativeFontString; const fontSizeInfo = TextUtils.measureFont(fontString); const subTexts = renderer.text.split(/(?:\r\n|\r|\n)/); @@ -271,7 +271,7 @@ export class TextUtils { } static measureTextWithoutWrap(renderer: TextRenderer): TextMetrics { - const { _subFont: subFont } = renderer; + const { subFont } = renderer; const fontString = subFont.nativeFontString; const fontSizeInfo = TextUtils.measureFont(fontString); const subTexts = renderer.text.split(/(?:\r\n|\r|\n)/); From 10fc066c6c82c3ef496768af42c1f9205c49e051 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 26 Apr 2024 15:16:27 +0800 Subject: [PATCH 030/218] refactor(2d-render-pipeline): fix chunk error --- packages/core/src/2d/text/TextRenderer.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index e68f1dd670..e4ce7b8c61 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -329,8 +329,10 @@ export class TextRenderer extends Renderer { const pool = TextRenderer._charRenderDataPool; const charRenderDatas = this._charRenderDatas; for (let i = 0, n = charRenderDatas.length; i < n; ++i) { - this.engine._batcherManager._batcher2D.freeChunk(charRenderDatas[i].chunk); - pool.free(charRenderDatas[i]); + const charRenderData = charRenderDatas[i]; + this.engine._batcherManager._batcher2D.freeChunk(charRenderData.chunk); + charRenderData.chunk = null; + pool.free(charRenderData); } charRenderDatas.length = 0; @@ -630,8 +632,10 @@ export class TextRenderer extends Renderer { const lastRenderDataCount = charRenderDatas.length; if (lastRenderDataCount > renderDataCount) { for (let i = renderDataCount; i < lastRenderDataCount; ++i) { - this.engine._batcherManager._batcher2D.freeChunk(charRenderDatas[i].chunk); - charRenderDataPool.free(charRenderDatas[i]); + const charRenderData = charRenderDatas[i]; + this.engine._batcherManager._batcher2D.freeChunk(charRenderData.chunk); + charRenderData.chunk = null; + charRenderDataPool.free(charRenderData); } charRenderDatas.length = renderDataCount; } From c9ac2a5f5ebc798f45b2d4371f05fcf28e7f7882 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Sun, 28 Apr 2024 15:06:23 +0800 Subject: [PATCH 031/218] refactor(2d-render-pipeline): opt code --- .../core/src/RenderPipeline/batcher/Batcher2D.ts | 14 +++++--------- .../core/src/RenderPipeline/batcher/MeshBuffer.ts | 12 +++++++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 6a6f1fc072..92b3874cf7 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -20,13 +20,15 @@ export class Batcher2D { /** @internal */ _meshBuffers: MeshBuffer[] = []; /** @internal */ + _maxVertexCount: number; + /** @internal */ _preContext: RenderContext = null; /** @internal */ _preRenderData: SpriteRenderData = null; constructor(engine: Engine, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT) { this._engine = engine; - this._createMeshBuffer(0, maxVertexCount); + this._maxVertexCount = maxVertexCount; } /** @@ -88,7 +90,7 @@ export class Batcher2D { } } - const meshBuffer = this._createMeshBuffer(len); + const meshBuffer = this._createMeshBuffer(len, this._maxVertexCount); chunk = meshBuffer.allocateChunk(vertexCount); if (chunk) { chunk._mbId = len; @@ -103,13 +105,7 @@ export class Batcher2D { } protected _createMeshBuffer(index: number, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT): MeshBuffer { - const { _meshBuffers } = this; - if (_meshBuffers[index]) { - return _meshBuffers[index]; - } - - const meshBuffer = (_meshBuffers[index] = new MeshBuffer(this._engine, maxVertexCount)); - return meshBuffer; + return (this._meshBuffers[index] ||= new MeshBuffer(this._engine, maxVertexCount)); } private _canBatch(preRenderData: SpriteRenderData, curRenderData: SpriteRenderData): boolean { diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index 5fce7eed3c..ab3a9aceac 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -64,9 +64,15 @@ export class MeshBuffer { /** @internal */ _indices: Uint16Array; - /** @internal */ - _vLen: number = 0; // _vertices 需要上传的数据长度 - /** @internal */ + /** + * @internal + * The length of _vertices needed to be uploaded. + * */ + _vLen: number = 0; + /** + * @internal + * The length of _indices needed to be uploaded. + * */ _iLen: number = 0; // _indices 需要上传的数据长度 /** @internal */ From 5dc393d2070c7b9d9d2dd042b98ff030cfaa6957 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Sun, 28 Apr 2024 15:08:47 +0800 Subject: [PATCH 032/218] refactor(2d-render-pipeline): opt code --- packages/core/src/RenderPipeline/batcher/Batcher2D.ts | 2 +- packages/core/src/RenderPipeline/batcher/MeshBuffer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 92b3874cf7..07fd9b1c62 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,6 +1,6 @@ import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; import { Engine } from "../../Engine"; -import { ShaderProperty, ShaderTagKey } from "../../shader"; +import { ShaderTagKey } from "../../shader"; import { RenderContext } from "../RenderContext"; import { SpriteRenderData } from "../SpriteRenderData"; import { MBChunk, MeshBuffer } from "./MeshBuffer"; diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index ab3a9aceac..b3ca3baac3 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -73,7 +73,7 @@ export class MeshBuffer { * @internal * The length of _indices needed to be uploaded. * */ - _iLen: number = 0; // _indices 需要上传的数据长度 + _iLen: number = 0; /** @internal */ _vFreeEntries: Entry[] = []; From d667d99b5e7ad4b5a1e84e04bce00153f07e04ae Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 29 Apr 2024 11:45:38 +0800 Subject: [PATCH 033/218] refactor(2d-render-pipeline): opt code --- packages/core/src/Engine.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index 9d0b49b317..f2ebdbb64e 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -518,7 +518,8 @@ export class Engine extends EventDispatcher { _render(scenes: ReadonlyArray): void { // Update `Renderer` logic and shader data const deltaTime = this.time.deltaTime; - for (let i = 0, n = scenes.length; i < n; i++) { + const sceneCount = scenes.length; + for (let i = 0; i < sceneCount; i++) { const scene = scenes[i]; if (!scene.isActive || scene.destroyed) continue; scene._componentsManager.callRendererOnUpdate(deltaTime); @@ -526,7 +527,7 @@ export class Engine extends EventDispatcher { } // Fire script `onBeginRender` and `onEndRender` - for (let i = 0, n = scenes.length; i < n; i++) { + for (let i = 0; i < sceneCount; i++) { const scene = scenes[i]; if (!scene.isActive || scene.destroyed) continue; const cameras = scene._componentsManager._activeCameras; From caa0a38f57bcfd7278606064816c97d62ae7a191 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 29 Apr 2024 17:31:18 +0800 Subject: [PATCH 034/218] refactor(2d-render-pipeline): fix 2d sort error --- .../src/RenderPipeline/BasicRenderPipeline.ts | 1 + .../src/RenderPipeline/batcher/Batcher2D.ts | 82 ++++++++++++++++--- .../RenderPipeline/batcher/BatcherManager.ts | 4 + 3 files changed, 76 insertions(+), 11 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 6213c4b211..bf75cbc6e1 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -85,6 +85,7 @@ export class BasicRenderPipeline { context.applyVirtualCamera(camera._virtualCamera, depthPassEnabled); this._prepareRender(context); + batcherManager.sortAndHandleRenderData(); batcherManager.flush(); batcherManager.uploadBuffer(); cullingResults.sort(); diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 07fd9b1c62..83839cfaa1 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,10 +1,15 @@ import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; import { Engine } from "../../Engine"; -import { ShaderTagKey } from "../../shader"; +import { RenderQueueType, ShaderTagKey } from "../../shader"; import { RenderContext } from "../RenderContext"; import { SpriteRenderData } from "../SpriteRenderData"; import { MBChunk, MeshBuffer } from "./MeshBuffer"; +interface TempRenderInfo { + context: RenderContext; + data: SpriteRenderData; +} + /** * @internal */ @@ -12,6 +17,42 @@ export class Batcher2D { /** The maximum number of vertex. */ static MAX_VERTEX_COUNT: number = 4096; + /** + * @internal + */ + static _sort(a: TempRenderInfo, b: TempRenderInfo): number { + const dataA = a.data; + const dataB = b.data; + const renderQueueTypeA = dataA.material.renderState.renderQueueType; + const renderQueueTypeB = dataB.material.renderState.renderQueueType; + const renderQueueTypeOrder = renderQueueTypeA - renderQueueTypeB; + if (renderQueueTypeOrder !== 0) { + return renderQueueTypeOrder; + } + + const componentA = dataA.component; + const componentB = dataB.component; + const priorityOrder = componentA.priority - componentB.priority; + if (priorityOrder !== 0) { + return priorityOrder; + } + + // make suer from the same renderer. + if (componentA.instanceId === componentB.instanceId) { + return dataA.material._priority - dataB.material._priority; + } else { + const distanceDiff = + renderQueueTypeA == RenderQueueType.Transparent + ? componentB._distanceForSort - componentA._distanceForSort + : componentA._distanceForSort - componentB._distanceForSort; + if (distanceDiff === 0) { + return componentA.instanceId - componentB.instanceId; + } else { + return distanceDiff; + } + } + } + protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); /** @internal */ @@ -25,6 +66,8 @@ export class Batcher2D { _preContext: RenderContext = null; /** @internal */ _preRenderData: SpriteRenderData = null; + /** @internal */ + _tempRenderInfos: Array = []; constructor(engine: Engine, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT) { this._engine = engine; @@ -44,16 +87,18 @@ export class Batcher2D { } commitRenderData(context: RenderContext, data: SpriteRenderData): void { - const { _preRenderData: preRenderData } = this; - if (preRenderData) { - if (this._canBatch(preRenderData, data)) { - this._udpateRenderData(context, preRenderData, data, true); - } else { - this.flush(); - this._udpateRenderData(context, preRenderData, data, false); - } - } else { - this._udpateRenderData(context, preRenderData, data, false); + this._tempRenderInfos.push({ + context, + data + }); + } + + sortAndHandleRenderData(): void { + const { _tempRenderInfos } = this; + _tempRenderInfos.sort(Batcher2D._sort); + for (let i = 0, l = _tempRenderInfos.length; i < l; ++i) { + const info = _tempRenderInfos[i]; + this._handleRenderData(info.context, info.data); } } @@ -75,6 +120,7 @@ export class Batcher2D { for (let i = 0, l = meshBuffers.length; i < l; ++i) { meshBuffers[i].clear(); } + this._tempRenderInfos.length = 0; } allocateChunk(vertexCount: number): MBChunk | null { @@ -142,6 +188,20 @@ export class Batcher2D { return left.maskLayer === right.maskLayer; } + private _handleRenderData(context: RenderContext, data: SpriteRenderData): void { + const { _preRenderData: preRenderData } = this; + if (preRenderData) { + if (this._canBatch(preRenderData, data)) { + this._udpateRenderData(context, preRenderData, data, true); + } else { + this.flush(); + this._udpateRenderData(context, preRenderData, data, false); + } + } else { + this._udpateRenderData(context, preRenderData, data, false); + } + } + private _udpateRenderData( context: RenderContext, preRenderData: SpriteRenderData, diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts index d4e755b16e..72a2f25b8e 100644 --- a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -30,6 +30,10 @@ export class BatcherManager { } } + sortAndHandleRenderData(): void { + this._batcher2D.sortAndHandleRenderData(); + } + flush(): void { this._batcher2D.flush(); } From 8f77a72197017b69a696a92b677976128419e9a0 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 30 Apr 2024 11:46:25 +0800 Subject: [PATCH 035/218] refactor(2d-render-pipeline): change 2d batch structure --- .../src/RenderPipeline/BasicRenderPipeline.ts | 4 +- .../core/src/RenderPipeline/CullingResults.ts | 8 ++ .../core/src/RenderPipeline/RenderQueue.ts | 34 +++++- .../src/RenderPipeline/batcher/Batcher2D.ts | 115 ++++-------------- .../RenderPipeline/batcher/BatcherManager.ts | 20 +-- 5 files changed, 69 insertions(+), 112 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index bf75cbc6e1..7c449d7305 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -85,10 +85,8 @@ export class BasicRenderPipeline { context.applyVirtualCamera(camera._virtualCamera, depthPassEnabled); this._prepareRender(context); - batcherManager.sortAndHandleRenderData(); - batcherManager.flush(); - batcherManager.uploadBuffer(); cullingResults.sort(); + cullingResults.update2DBatch(batcherManager._batcher2D); if (depthPassEnabled) { depthOnlyPass.onConfig(camera); diff --git a/packages/core/src/RenderPipeline/CullingResults.ts b/packages/core/src/RenderPipeline/CullingResults.ts index 9d48b55afb..9dca611b4e 100644 --- a/packages/core/src/RenderPipeline/CullingResults.ts +++ b/packages/core/src/RenderPipeline/CullingResults.ts @@ -1,6 +1,8 @@ import { Engine } from "../Engine"; import { RenderQueueType } from "../shader"; import { RenderQueue } from "./RenderQueue"; +import { Batcher2D } from "./batcher/Batcher2D"; +import { BatcherManager } from "./batcher/BatcherManager"; /** * @internal @@ -29,6 +31,12 @@ export class CullingResults { this.transparentQueue.sort(RenderQueue._compareForTransparent); } + update2DBatch(batcher: Batcher2D): void { + this.opaqueQueue.update2DBatch(batcher); + this.alphaTestQueue.update2DBatch(batcher); + this.transparentQueue.update2DBatch(batcher); + } + destroy(): void { this.opaqueQueue.destroy(); this.transparentQueue.destroy(); diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 4e5a07a119..2ed013cf8c 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -5,6 +5,7 @@ import { RenderQueueType, Shader, ShaderProperty } from "../shader"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; import { RenderContext } from "./RenderContext"; import { RenderElement } from "./RenderElement"; +import { Batcher2D } from "./batcher/Batcher2D"; import { RenderDataUsage } from "./enums/RenderDataUsage"; /** @@ -64,6 +65,7 @@ export class RenderQueue { } readonly elements: RenderElement[] = []; + readonly tempElements: RenderElement[] = []; private readonly _renderQueueType: RenderQueueType; @@ -75,7 +77,36 @@ export class RenderQueue { * Push a render element. */ pushRenderElement(element: RenderElement): void { - this.elements.push(element); + this.tempElements.push(element); + } + + update2DBatch(batcher: Batcher2D): void { + const { tempElements } = this; + if (tempElements.length === 0) { + return; + } + + const { elements } = this; + for (let i = 0, l = tempElements.length; i < l; ++i) { + const element = tempElements[i]; + if (element.data.usage === RenderDataUsage.Mesh) { + if (batcher._preElement) { + elements.push(batcher._preElement); + batcher._preElement = null; + } + elements.push(element); + } else { + const newElement = batcher.commitRenderElement(element); + if (newElement) { + elements.push(newElement); + } + } + } + if (batcher._preElement) { + elements.push(batcher._preElement); + batcher._preElement = null; + } + batcher.uploadBuffer(); } render(camera: Camera, pipelineStageTagValue: string): void { @@ -201,6 +232,7 @@ export class RenderQueue { */ clear(): void { this.elements.length = 0; + this.tempElements.length = 0; } /** diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 83839cfaa1..64a59dc942 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,15 +1,10 @@ import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; import { Engine } from "../../Engine"; -import { RenderQueueType, ShaderTagKey } from "../../shader"; -import { RenderContext } from "../RenderContext"; +import { ShaderTagKey } from "../../shader"; +import { RenderElement } from "../RenderElement"; import { SpriteRenderData } from "../SpriteRenderData"; import { MBChunk, MeshBuffer } from "./MeshBuffer"; -interface TempRenderInfo { - context: RenderContext; - data: SpriteRenderData; -} - /** * @internal */ @@ -17,42 +12,6 @@ export class Batcher2D { /** The maximum number of vertex. */ static MAX_VERTEX_COUNT: number = 4096; - /** - * @internal - */ - static _sort(a: TempRenderInfo, b: TempRenderInfo): number { - const dataA = a.data; - const dataB = b.data; - const renderQueueTypeA = dataA.material.renderState.renderQueueType; - const renderQueueTypeB = dataB.material.renderState.renderQueueType; - const renderQueueTypeOrder = renderQueueTypeA - renderQueueTypeB; - if (renderQueueTypeOrder !== 0) { - return renderQueueTypeOrder; - } - - const componentA = dataA.component; - const componentB = dataB.component; - const priorityOrder = componentA.priority - componentB.priority; - if (priorityOrder !== 0) { - return priorityOrder; - } - - // make suer from the same renderer. - if (componentA.instanceId === componentB.instanceId) { - return dataA.material._priority - dataB.material._priority; - } else { - const distanceDiff = - renderQueueTypeA == RenderQueueType.Transparent - ? componentB._distanceForSort - componentA._distanceForSort - : componentA._distanceForSort - componentB._distanceForSort; - if (distanceDiff === 0) { - return componentA.instanceId - componentB.instanceId; - } else { - return distanceDiff; - } - } - } - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); /** @internal */ @@ -63,11 +22,7 @@ export class Batcher2D { /** @internal */ _maxVertexCount: number; /** @internal */ - _preContext: RenderContext = null; - /** @internal */ - _preRenderData: SpriteRenderData = null; - /** @internal */ - _tempRenderInfos: Array = []; + _preElement: RenderElement = null; constructor(engine: Engine, maxVertexCount: number = Batcher2D.MAX_VERTEX_COUNT) { this._engine = engine; @@ -86,25 +41,21 @@ export class Batcher2D { this._meshBuffers = null; } - commitRenderData(context: RenderContext, data: SpriteRenderData): void { - this._tempRenderInfos.push({ - context, - data - }); - } - - sortAndHandleRenderData(): void { - const { _tempRenderInfos } = this; - _tempRenderInfos.sort(Batcher2D._sort); - for (let i = 0, l = _tempRenderInfos.length; i < l; ++i) { - const info = _tempRenderInfos[i]; - this._handleRenderData(info.context, info.data); + commitRenderElement(element: RenderElement): RenderElement | null { + const { _preElement: preElement } = this; + let batchElement = null; + if (preElement) { + if (this._canBatch(preElement, element)) { + this._udpateRenderData(preElement, element, true); + } else { + batchElement = this._preElement; + this._udpateRenderData(preElement, element, false); + } + } else { + this._udpateRenderData(preElement, element, false); } - } - flush(): void { - const { _preRenderData: preRenderData } = this; - preRenderData && this._preContext.camera._renderPipeline.pushRenderData(this._preContext, preRenderData); + return batchElement; } uploadBuffer(): void { @@ -120,7 +71,6 @@ export class Batcher2D { for (let i = 0, l = meshBuffers.length; i < l; ++i) { meshBuffers[i].clear(); } - this._tempRenderInfos.length = 0; } allocateChunk(vertexCount: number): MBChunk | null { @@ -154,7 +104,9 @@ export class Batcher2D { return (this._meshBuffers[index] ||= new MeshBuffer(this._engine, maxVertexCount)); } - private _canBatch(preRenderData: SpriteRenderData, curRenderData: SpriteRenderData): boolean { + private _canBatch(preElement: RenderElement, cureElement: RenderElement): boolean { + const preRenderData = preElement.data; + const curRenderData = cureElement.data; if (preRenderData.chunk._meshBuffer !== curRenderData.chunk._meshBuffer) { return false; } @@ -188,26 +140,9 @@ export class Batcher2D { return left.maskLayer === right.maskLayer; } - private _handleRenderData(context: RenderContext, data: SpriteRenderData): void { - const { _preRenderData: preRenderData } = this; - if (preRenderData) { - if (this._canBatch(preRenderData, data)) { - this._udpateRenderData(context, preRenderData, data, true); - } else { - this.flush(); - this._udpateRenderData(context, preRenderData, data, false); - } - } else { - this._udpateRenderData(context, preRenderData, data, false); - } - } - - private _udpateRenderData( - context: RenderContext, - preRenderData: SpriteRenderData, - curRenderData: SpriteRenderData, - canBatch: boolean - ): void { + private _udpateRenderData(preElement: RenderElement, curElement: RenderElement, canBatch: boolean): void { + const preRenderData = preElement ? preElement.data : null; + const curRenderData = curElement.data; const { chunk } = curRenderData; const { _meshBuffer: meshBuffer, _indices: tempIndices, _vEntry: vEntry } = chunk; const { _indices: indices } = meshBuffer; @@ -229,13 +164,11 @@ export class Batcher2D { meshBuffer._iLen += len; meshBuffer._vLen = Math.max(meshBuffer._vLen, vEntry.start + vEntry.len); if (!canBatch) { - this._preContext = context; - this._preRenderData = curRenderData; + this._preElement = curElement; } } private _reset(): void { - this._preContext = null; - this._preRenderData = null; + this._preElement = null; } } diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts index 72a2f25b8e..5950cfbe7c 100644 --- a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -1,7 +1,6 @@ import { Engine } from "../../Engine"; import { RenderContext } from "../RenderContext"; import { RenderData } from "../RenderData"; -import { SpriteRenderData } from "../SpriteRenderData"; import { RenderDataUsage } from "../enums/RenderDataUsage"; import { Batcher2D } from "./Batcher2D"; @@ -30,18 +29,6 @@ export class BatcherManager { } } - sortAndHandleRenderData(): void { - this._batcher2D.sortAndHandleRenderData(); - } - - flush(): void { - this._batcher2D.flush(); - } - - uploadBuffer(): void { - this._batcher2D.uploadBuffer(); - } - clear() { this._batcher2D.clear(); } @@ -49,12 +36,11 @@ export class BatcherManager { private _handleRenderData(context: RenderContext, data: RenderData): void { switch (data.usage) { case RenderDataUsage.Mesh: - this._batcher2D.flush(); - context.camera._renderPipeline.pushRenderData(context, data); - break; case RenderDataUsage.Sprite: case RenderDataUsage.Text: - this._batcher2D.commitRenderData(context, data); + context.camera._renderPipeline.pushRenderData(context, data); + break; + default: break; } } From f08d47787c07bb16610be6fb6b22055ba086acce Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 30 Apr 2024 17:22:48 +0800 Subject: [PATCH 036/218] refactor(2d-render-pipeline): opt code --- packages/core/src/2d/text/TextRenderer.ts | 6 ++--- .../core/src/RenderPipeline/RenderQueue.ts | 12 +++++----- .../src/RenderPipeline/batcher/Batcher2D.ts | 7 +++--- .../RenderPipeline/batcher/BatcherManager.ts | 22 ++++++------------- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index e4ce7b8c61..122e4ed2aa 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -15,7 +15,6 @@ import { CharRenderData } from "./CharRenderData"; import { Font } from "./Font"; import { SubFont } from "./SubFont"; import { TextUtils } from "./TextUtils"; -import { SpriteRenderData } from "../../RenderPipeline/SpriteRenderData"; import { RenderDataUsage } from "../../RenderPipeline/enums/RenderDataUsage"; import { Pool } from "../../utils/Pool"; @@ -423,16 +422,15 @@ export class TextRenderer extends Renderer { const charRenderDatas = this._charRenderDatas; const charCount = charRenderDatas.length; - let spriteRenderDatas: Array = []; + const batcherManager = engine._batcherManager; for (let i = 0; i < charCount; ++i) { const charRenderData = charRenderDatas[i]; const renderData = spriteRenderDataPool.getFromPool(); const { chunk } = charRenderData; renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, charRenderData.texture, chunk); renderData.usage = RenderDataUsage.Text; - spriteRenderDatas.push(renderData); + batcherManager.commitRenderData(context, renderData); } - engine._batcherManager.commitRenderData(context, spriteRenderDatas); } private _updateStencilState(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 2ed013cf8c..54317e1936 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -82,12 +82,13 @@ export class RenderQueue { update2DBatch(batcher: Batcher2D): void { const { tempElements } = this; - if (tempElements.length === 0) { + const len = tempElements.length; + if (len === 0) { return; } const { elements } = this; - for (let i = 0, l = tempElements.length; i < l; ++i) { + for (let i = 0; i < len; ++i) { const element = tempElements[i]; if (element.data.usage === RenderDataUsage.Mesh) { if (batcher._preElement) { @@ -110,8 +111,9 @@ export class RenderQueue { } render(camera: Camera, pipelineStageTagValue: string): void { - const elements = this.elements; - if (elements.length === 0) { + const { elements } = this; + const len = elements.length; + if (len === 0) { return; } @@ -124,7 +126,7 @@ export class RenderQueue { const pipelineStageKey = RenderContext.pipelineStageKey; const renderQueueType = this._renderQueueType; - for (let i = 0, n = elements.length; i < n; i++) { + for (let i = 0; i < len; i++) { const element = elements[i]; const { data, shaderPasses } = element; diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 64a59dc942..950fdddfc8 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -39,6 +39,8 @@ export class Batcher2D { } _meshBuffers.length = 0; this._meshBuffers = null; + this._engine = null; + this._preElement = null; } commitRenderElement(element: RenderElement): RenderElement | null { @@ -75,10 +77,9 @@ export class Batcher2D { allocateChunk(vertexCount: number): MBChunk | null { const { _meshBuffers } = this; - let chunk: MBChunk = null; - let i = 0; const len = _meshBuffers.length; - for (; i < len; ++i) { + let chunk: MBChunk = null; + for (let i = 0; i < len; ++i) { chunk = _meshBuffers[i].allocateChunk(vertexCount); if (chunk) { chunk._mbId = i; diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts index 5950cfbe7c..d9e7cf1b7f 100644 --- a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -17,23 +17,11 @@ export class BatcherManager { destroy() { this._batcher2D.destroy(); + this._batcher2D = null; + this._engine = null; } - commitRenderData(context: RenderContext, data: RenderData | Array): void { - if (data instanceof Array) { - for (let i = 0, l = data.length; i < l; ++i) { - this._handleRenderData(context, data[i]); - } - } else { - this._handleRenderData(context, data); - } - } - - clear() { - this._batcher2D.clear(); - } - - private _handleRenderData(context: RenderContext, data: RenderData): void { + commitRenderData(context: RenderContext, data: RenderData): void { switch (data.usage) { case RenderDataUsage.Mesh: case RenderDataUsage.Sprite: @@ -44,4 +32,8 @@ export class BatcherManager { break; } } + + clear() { + this._batcher2D.clear(); + } } From 7f4a46000f8c59b1645950e745f422e7492e24db Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 6 May 2024 16:54:31 +0800 Subject: [PATCH 037/218] refactor(2d-render-pipeline): opt code --- .../src/2d/assembler/SimpleSpriteAssembler.ts | 10 +- .../src/2d/assembler/SlicedSpriteAssembler.ts | 10 +- .../src/2d/assembler/TiledSpriteAssembler.ts | 105 ++++++++++-------- packages/core/src/2d/text/TextRenderer.ts | 20 ++-- .../src/RenderPipeline/BasicRenderPipeline.ts | 6 +- .../src/RenderPipeline/SpriteMaskManager.ts | 6 +- .../src/RenderPipeline/batcher/Batcher2D.ts | 7 +- .../src/RenderPipeline/batcher/MeshBuffer.ts | 8 +- 8 files changed, 94 insertions(+), 78 deletions(-) diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index de850d8b24..ccb8067863 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -86,14 +86,14 @@ export class SimpleSpriteAssembler { static updateColor(renderer: SpriteRenderer): void { const { _chunk: chunk } = renderer; - const { color } = renderer; + const { r, g, b, a } = renderer.color; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start + 5; for (let i = 0; i < 4; ++i) { - vertices[index] = color.r; - vertices[index + 1] = color.g; - vertices[index + 2] = color.b; - vertices[index + 3] = color.a; + vertices[index] = r; + vertices[index + 1] = g; + vertices[index + 2] = b; + vertices[index + 3] = a; index += 9; } } diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts index a0a8b81bb8..170b3c81b1 100644 --- a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts @@ -139,14 +139,14 @@ export class SlicedSpriteAssembler { static updateColor(renderer: SpriteRenderer): void { const { _chunk: chunk } = renderer; - const { color } = renderer; + const { r, g, b, a } = renderer.color; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start + 5; for (let i = 0; i < 16; ++i) { - vertices[index] = color.r; - vertices[index + 1] = color.g; - vertices[index + 2] = color.b; - vertices[index + 3] = color.a; + vertices[index] = r; + vertices[index + 1] = g; + vertices[index + 2] = b; + vertices[index + 3] = a; index += 9; } } diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index d583087e48..5116916bf4 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -85,7 +85,6 @@ export class TiledSpriteAssembler { } this.resetData(renderer, vertexCount, indicesCount); - const { r: colorR, g: colorG, b: colorB, a: colorA } = renderer.color; const { _chunk: chunk } = renderer; const vertices = chunk._meshBuffer._vertices; const indices = chunk._indices; @@ -96,7 +95,6 @@ export class TiledSpriteAssembler { const doubleJ = 2 * j; for (let i = 0; i < rowLength; i++) { const uvL = uvRow.get(2 * i); - const uvB = uvColumn.get(doubleJ); const uvR = uvRow.get(2 * i + 1); const uvT = uvColumn.get(doubleJ + 1); if (isNaN(uvL) || isNaN(uvL) || isNaN(uvR) || isNaN(uvT)) { @@ -116,48 +114,28 @@ export class TiledSpriteAssembler { const t = posColumn.get(j + 1); // left and bottom - vertices[index++] = wE0 * l + wE4 * b + wE12; - vertices[index++] = wE1 * l + wE5 * b + wE13; - vertices[index++] = wE2 * l + wE6 * b + wE14; - vertices[index++] = uvL; - vertices[index++] = uvB; - vertices[index++] = colorR; - vertices[index++] = colorG; - vertices[index++] = colorB; - vertices[index++] = colorA; + vertices[index] = wE0 * l + wE4 * b + wE12; + vertices[index + 1] = wE1 * l + wE5 * b + wE13; + vertices[index + 2] = wE2 * l + wE6 * b + wE14; + index += 9; // right and bottom - vertices[index++] = wE0 * r + wE4 * b + wE12; - vertices[index++] = wE1 * r + wE5 * b + wE13; - vertices[index++] = wE2 * r + wE6 * b + wE14; - vertices[index++] = uvR; - vertices[index++] = uvB; - vertices[index++] = colorR; - vertices[index++] = colorG; - vertices[index++] = colorB; - vertices[index++] = colorA; + vertices[index] = wE0 * r + wE4 * b + wE12; + vertices[index + 1] = wE1 * r + wE5 * b + wE13; + vertices[index + 2] = wE2 * r + wE6 * b + wE14; + index += 9; // left and top - vertices[index++] = wE0 * l + wE4 * t + wE12; - vertices[index++] = wE1 * l + wE5 * t + wE13; - vertices[index++] = wE2 * l + wE6 * t + wE14; - vertices[index++] = uvL; - vertices[index++] = uvT; - vertices[index++] = colorR; - vertices[index++] = colorG; - vertices[index++] = colorB; - vertices[index++] = colorA; + vertices[index] = wE0 * l + wE4 * t + wE12; + vertices[index + 1] = wE1 * l + wE5 * t + wE13; + vertices[index + 2] = wE2 * l + wE6 * t + wE14; + index += 9; // right and top - vertices[index++] = wE0 * r + wE4 * t + wE12; - vertices[index++] = wE1 * r + wE5 * t + wE13; - vertices[index++] = wE2 * r + wE6 * t + wE14; - vertices[index++] = uvR; - vertices[index++] = uvT; - vertices[index++] = colorR; - vertices[index++] = colorG; - vertices[index++] = colorB; - vertices[index++] = colorA; + vertices[index] = wE0 * r + wE4 * t + wE12; + vertices[index + 1] = wE1 * r + wE5 * t + wE13; + vertices[index + 2] = wE2 * r + wE6 * t + wE14; + index += 9; } } @@ -167,18 +145,57 @@ export class TiledSpriteAssembler { renderer._bounds.transform(worldMatrix); } - static updateUVs(renderer: SpriteRenderer): void {} + static updateUVs(renderer: SpriteRenderer): void { + const { _posRow: posRow, _posColumn: posColumn, _uvRow: uvRow, _uvColumn: uvColumn } = this; + const rowLength = posRow.length - 1; + const columnLength = posColumn.length - 1; + const { _chunk: chunk } = renderer; + const vertices = chunk._meshBuffer._vertices; + let index = chunk._vEntry.start + 3; + for (let j = 0; j < columnLength; j++) { + const doubleJ = 2 * j; + for (let i = 0; i < rowLength; i++) { + const uvL = uvRow.get(2 * i); + const uvB = uvColumn.get(doubleJ); + const uvR = uvRow.get(2 * i + 1); + const uvT = uvColumn.get(doubleJ + 1); + if (isNaN(uvL) || isNaN(uvL) || isNaN(uvR) || isNaN(uvT)) { + continue; + } + + // left and bottom + vertices[index] = uvL; + vertices[index + 1] = uvB; + index += 9; + + // right and bottom + vertices[index] = uvR; + vertices[index + 1] = uvB; + index += 9; + + // left and top + vertices[index] = uvL; + vertices[index + 1] = uvT; + index += 9; + + // right and top + vertices[index] = uvR; + vertices[index + 1] = uvT; + index += 9; + } + } + } static updateColor(renderer: SpriteRenderer): void { const { _chunk: chunk } = renderer; - const { color } = renderer; + const { r, g, b, a } = renderer.color; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start + 5; for (let i = 0, l = chunk._vEntry.len / 9; i < l; ++i) { - vertices[index] = color.r; - vertices[index + 1] = color.g; - vertices[index + 2] = color.b; - vertices[index + 3] = color.a; + vertices[index] = r; + vertices[index + 1] = g; + vertices[index + 2] = b; + vertices[index + 3] = a; index += 9; } } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 122e4ed2aa..f3e629cc3f 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -25,10 +25,7 @@ export class TextRenderer extends Renderer { private static _charRenderDataPool: Pool = new Pool(CharRenderData, 50); private static _tempVec30: Vector3 = new Vector3(); private static _tempVec31: Vector3 = new Vector3(); - private static _worldPosition0: Vector3 = new Vector3(); - private static _worldPosition1: Vector3 = new Vector3(); - private static _worldPosition2: Vector3 = new Vector3(); - private static _worldPosition3: Vector3 = new Vector3(); + private static _worldPositions: Array = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; /** @internal */ @assignmentClone @@ -327,9 +324,10 @@ export class TextRenderer extends Renderer { // Clear render data. const pool = TextRenderer._charRenderDataPool; const charRenderDatas = this._charRenderDatas; + const batcher2D = this.engine._batcherManager._batcher2D; for (let i = 0, n = charRenderDatas.length; i < n; ++i) { const charRenderData = charRenderDatas[i]; - this.engine._batcherManager._batcher2D.freeChunk(charRenderData.chunk); + batcher2D.freeChunk(charRenderData.chunk); charRenderData.chunk = null; pool.free(charRenderData); } @@ -475,30 +473,32 @@ export class TextRenderer extends Renderer { const up = TextRenderer._tempVec31.set(e4, e5, e6); const right = TextRenderer._tempVec30.set(e0, e1, e2); + const worldPosition0 = TextRenderer._worldPositions[0]; + const worldPosition1 = TextRenderer._worldPositions[1]; + const worldPosition2 = TextRenderer._worldPositions[2]; + const worldPosition3 = TextRenderer._worldPositions[3]; + for (let i = 0, n = charRenderDatas.length; i < n; ++i) { const charRenderData = charRenderDatas[i]; const { localPositions } = charRenderData; const { x: topLeftX, y: topLeftY } = localPositions; // Top-Left - const worldPosition0 = TextRenderer._worldPosition0; worldPosition0.x = topLeftX * e0 + topLeftY * e4 + e12; worldPosition0.y = topLeftX * e1 + topLeftY * e5 + e13; worldPosition0.z = topLeftX * e2 + topLeftY * e6 + e14; // Right offset - const worldPosition1 = TextRenderer._worldPosition1; Vector3.scale(right, localPositions.z - topLeftX, worldPosition1); // Top-Right Vector3.add(worldPosition0, worldPosition1, worldPosition1); // Up offset - const worldPosition2 = TextRenderer._worldPosition2; Vector3.scale(up, localPositions.w - topLeftY, worldPosition2); // Bottom-Left - Vector3.add(worldPosition0, worldPosition2, TextRenderer._worldPosition3); + Vector3.add(worldPosition0, worldPosition2, worldPosition3); // Bottom-Right Vector3.add(worldPosition1, worldPosition2, worldPosition2); @@ -506,7 +506,7 @@ export class TextRenderer extends Renderer { const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start; for (let i = 0; i < 4; ++i) { - const position = TextRenderer[`_worldPosition${i}`]; + const position = TextRenderer._worldPositions[i]; vertices[index] = position.x; vertices[index + 1] = position.y; vertices[index + 2] = position.z; diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 7c449d7305..058c415956 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -71,8 +71,8 @@ export class BasicRenderPipeline { const sunlight = scene._lightManager._sunlight; const depthOnlyPass = this._depthOnlyPass; const depthPassEnabled = camera.depthTextureMode === DepthTextureMode.PrePass && depthOnlyPass._supportDepthTexture; - const batcherManager = camera.engine._batcherManager; - camera.engine._spriteMaskManager.clear(); + const batcherManager = engine._batcherManager; + engine._spriteMaskManager.clear(); if (scene.castShadows && sunlight && sunlight.shadowType !== ShadowType.None) { this._cascadedShadowCasterPass.onRender(context); @@ -80,7 +80,7 @@ export class BasicRenderPipeline { cullingResults.reset(); batcherManager.clear(); - camera.engine._spriteMaskManager.clear(); + engine._spriteMaskManager.clear(); context.applyVirtualCamera(camera._virtualCamera, depthPassEnabled); this._prepareRender(context); diff --git a/packages/core/src/RenderPipeline/SpriteMaskManager.ts b/packages/core/src/RenderPipeline/SpriteMaskManager.ts index be8410f9b7..5da005c413 100644 --- a/packages/core/src/RenderPipeline/SpriteMaskManager.ts +++ b/packages/core/src/RenderPipeline/SpriteMaskManager.ts @@ -60,7 +60,7 @@ export class SpriteMaskManager { const preMaskLayer = this._preMaskLayer; const curMaskLayer = renderer.maskLayer; if (preMaskLayer !== curMaskLayer) { - const { _allSpriteMasks: masks } = this; + const { _allSpriteMasks: masks, _batcher } = this; const commonLayer = preMaskLayer & curMaskLayer; const addLayer = curMaskLayer & ~preMaskLayer; const reduceLayer = preMaskLayer & ~curMaskLayer; @@ -76,13 +76,13 @@ export class SpriteMaskManager { if (influenceLayers & addLayer) { const maskRenderElement = mask._maskElement; - this._batcher.drawElement(maskRenderElement, camera, StencilOperation.IncrementSaturate); + _batcher.drawElement(maskRenderElement, camera, StencilOperation.IncrementSaturate); continue; } if (influenceLayers & reduceLayer) { const maskRenderElement = mask._maskElement; - this._batcher.drawElement(maskRenderElement, camera, StencilOperation.DecrementSaturate); + _batcher.drawElement(maskRenderElement, camera, StencilOperation.DecrementSaturate); } } } diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 950fdddfc8..27b84f2b3f 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -89,11 +89,8 @@ export class Batcher2D { const meshBuffer = this._createMeshBuffer(len, this._maxVertexCount); chunk = meshBuffer.allocateChunk(vertexCount); - if (chunk) { - chunk._mbId = len; - return chunk; - } - return null; + chunk._mbId = len; + return chunk; } freeChunk(chunk: MBChunk): void { diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index b3ca3baac3..fcaca56f34 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -203,26 +203,28 @@ export class MeshBuffer { const { _entryPool: pool } = this; let preEntry = entry; + let notMerge = true; for (let i = 0; i < entryLen; ++i) { const curEntry = entries[i]; const { start, len } = preEntry; const preEnd = start + len; const curEnd = curEntry.start + curEntry.len; if (preEnd < curEntry.start) { - entries.splice(i, 0, preEntry); + notMerge && entries.splice(i, 0, preEntry); return; } else if (preEnd === curEntry.start) { curEntry.start = preEntry.start; curEntry.len += preEntry.len; pool.free(preEntry); preEntry = curEntry; + notMerge = false; } else if (start === curEnd) { curEntry.len += preEntry.len; pool.free(preEntry); preEntry = curEntry; + notMerge = false; } else if (start > curEnd) { - entries.splice(i + 1, 0, preEntry); - preEntry = curEntry; + i + 1 === entryLen && entries.push(preEntry); } } } From cfe01a57c730ba10b275f6859f4018f8ea3a884f Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 6 May 2024 17:04:29 +0800 Subject: [PATCH 038/218] refactor(2d-render-pipeline): opt code --- packages/core/src/2d/sprite/SpriteRenderer.ts | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 6eff822bc5..1918911c15 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -85,7 +85,7 @@ export class SpriteRenderer extends Renderer { break; } this._assembler.resetData(this); - this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.RenderData; + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; } } @@ -100,7 +100,7 @@ export class SpriteRenderer extends Renderer { if (this._tileMode !== value) { this._tileMode = value; if (this.drawMode === SpriteDrawMode.Tiled) { - this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.RenderData; + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; } } } @@ -117,7 +117,7 @@ export class SpriteRenderer extends Renderer { value = MathUtil.clamp(value, 0, 1); this._tiledAdaptiveThreshold = value; if (this.drawMode === SpriteDrawMode.Tiled) { - this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.RenderData; + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; } } } @@ -418,7 +418,7 @@ export class SpriteRenderer extends Renderer { if (this._drawMode === SpriteDrawMode.Sliced) { this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume; } else if (drawMode === SpriteDrawMode.Tiled) { - this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.RenderData; + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; } else { // When the width and height of `SpriteRenderer` are `undefined`, // the `size` of `Sprite` will affect the position of `SpriteRenderer`. @@ -428,11 +428,11 @@ export class SpriteRenderer extends Renderer { } break; case SpriteModifyFlags.border: - this._drawMode === SpriteDrawMode.Sliced && (this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.RenderData); + this._drawMode === SpriteDrawMode.Sliced && (this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData); break; case SpriteModifyFlags.region: case SpriteModifyFlags.atlasRegionOffset: - this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.RenderData; + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; break; case SpriteModifyFlags.atlasRegion: this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.UV; @@ -453,12 +453,12 @@ export class SpriteRenderer extends Renderer { enum SpriteRendererUpdateFlags { /** UV. */ UV = 0x2, - /** WorldVolume and UV . */ - RenderData = 0x3, + /** Color. */ + Color = 0x4, + /** Vertex data. */ + VertexData = 0x7, /** Automatic Size. */ - AutomaticSize = 0x4, + AutomaticSize = 0x8, /** All. */ - All = 0x7, - /** Color. */ - Color = 0x8 + All = 0xff } From 83cbf4a3964fdf0c1eae225f1a8f437c2ce07222 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 6 May 2024 17:19:57 +0800 Subject: [PATCH 039/218] refactor(2d-render-pipeline): fix sprite draw mode tiled error --- packages/core/src/2d/sprite/SpriteRenderer.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index 1918911c15..ff77587e83 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -181,7 +181,11 @@ export class SpriteRenderer extends Renderer { set width(value: number) { if (this._customWidth !== value) { this._customWidth = value; - this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume; + if (this._drawMode === SpriteDrawMode.Tiled) { + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; + } else { + this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume; + } } } @@ -204,7 +208,11 @@ export class SpriteRenderer extends Renderer { set height(value: number) { if (this._customHeight !== value) { this._customHeight = value; - this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume; + if (this._drawMode === SpriteDrawMode.Tiled) { + this._dirtyUpdateFlag |= SpriteRendererUpdateFlags.VertexData; + } else { + this._dirtyUpdateFlag |= RendererUpdateFlags.WorldVolume; + } } } From c353ee39174a81b0cc764f764c526341bb7b07cd Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 6 May 2024 17:28:41 +0800 Subject: [PATCH 040/218] refactor(2d-render-pipeline): rename CharRenderData to CharRenderInfo --- .../{CharRenderData.ts => CharRenderInfo.ts} | 4 +- packages/core/src/2d/text/TextRenderer.ts | 68 +++++++++---------- 2 files changed, 36 insertions(+), 36 deletions(-) rename packages/core/src/2d/text/{CharRenderData.ts => CharRenderInfo.ts} (85%) diff --git a/packages/core/src/2d/text/CharRenderData.ts b/packages/core/src/2d/text/CharRenderInfo.ts similarity index 85% rename from packages/core/src/2d/text/CharRenderData.ts rename to packages/core/src/2d/text/CharRenderInfo.ts index e1cf99da4e..fa605fcb4c 100644 --- a/packages/core/src/2d/text/CharRenderData.ts +++ b/packages/core/src/2d/text/CharRenderInfo.ts @@ -7,7 +7,7 @@ import { IPoolElement } from "../../utils/Pool"; /** * @internal */ -export class CharRenderData implements IPoolElement { +export class CharRenderInfo implements IPoolElement { static triangles: number[] = [0, 2, 1, 2, 0, 3]; texture: Texture2D; @@ -18,7 +18,7 @@ export class CharRenderData implements IPoolElement { init(engine: Engine) { if (!this.chunk) { this.chunk = engine._batcherManager._batcher2D.allocateChunk(4); - this.chunk._indices = CharRenderData.triangles; + this.chunk._indices = CharRenderInfo.triangles; } } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index f3e629cc3f..7835687a83 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -11,7 +11,7 @@ import { SpriteMaskInteraction } from "../enums/SpriteMaskInteraction"; import { SpriteMaskLayer } from "../enums/SpriteMaskLayer"; import { TextHorizontalAlignment, TextVerticalAlignment } from "../enums/TextAlignment"; import { OverflowMode } from "../enums/TextOverflow"; -import { CharRenderData } from "./CharRenderData"; +import { CharRenderInfo } from "./CharRenderInfo"; import { Font } from "./Font"; import { SubFont } from "./SubFont"; import { TextUtils } from "./TextUtils"; @@ -22,7 +22,7 @@ import { Pool } from "../../utils/Pool"; * Renders a text for 2D graphics. */ export class TextRenderer extends Renderer { - private static _charRenderDataPool: Pool = new Pool(CharRenderData, 50); + private static _charRenderInfoPool: Pool = new Pool(CharRenderInfo, 50); private static _tempVec30: Vector3 = new Vector3(); private static _tempVec31: Vector3 = new Vector3(); private static _worldPositions: Array = [new Vector3(), new Vector3(), new Vector3(), new Vector3()]; @@ -32,7 +32,7 @@ export class TextRenderer extends Renderer { _subFont: SubFont = null; /** @internal */ @ignoreClone - _charRenderDatas: CharRenderData[] = []; + _charRenderInfos: CharRenderInfo[] = []; @ignoreClone _dirtyFlag: number = DirtyFlag.Font; @@ -322,16 +322,16 @@ export class TextRenderer extends Renderer { super._onDestroy(); // Clear render data. - const pool = TextRenderer._charRenderDataPool; - const charRenderDatas = this._charRenderDatas; + const pool = TextRenderer._charRenderInfoPool; + const charRenderInfos = this._charRenderInfos; const batcher2D = this.engine._batcherManager._batcher2D; - for (let i = 0, n = charRenderDatas.length; i < n; ++i) { - const charRenderData = charRenderDatas[i]; - batcher2D.freeChunk(charRenderData.chunk); - charRenderData.chunk = null; - pool.free(charRenderData); + for (let i = 0, n = charRenderInfos.length; i < n; ++i) { + const charRenderInfo = charRenderInfos[i]; + batcher2D.freeChunk(charRenderInfo.chunk); + charRenderInfo.chunk = null; + pool.free(charRenderInfo); } - charRenderDatas.length = 0; + charRenderInfos.length = 0; this._subFont && (this._subFont = null); } @@ -417,15 +417,15 @@ export class TextRenderer extends Renderer { const { engine } = context.camera; const spriteRenderDataPool = engine._spriteRenderDataPool; const material = this.getMaterial(); - const charRenderDatas = this._charRenderDatas; - const charCount = charRenderDatas.length; + const charRenderInfos = this._charRenderInfos; + const charCount = charRenderInfos.length; const batcherManager = engine._batcherManager; for (let i = 0; i < charCount; ++i) { - const charRenderData = charRenderDatas[i]; + const charRenderInfo = charRenderInfos[i]; const renderData = spriteRenderDataPool.getFromPool(); - const { chunk } = charRenderData; - renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, charRenderData.texture, chunk); + const { chunk } = charRenderInfo; + renderData.set(this, material, chunk._meshBuffer._mesh._primitive, chunk._subMesh, charRenderInfo.texture, chunk); renderData.usage = RenderDataUsage.Text; batcherManager.commitRenderData(context, renderData); } @@ -463,7 +463,7 @@ export class TextRenderer extends Renderer { private _updatePosition(): void { const { transform } = this.entity; const e = transform.worldMatrix.elements; - const charRenderDatas = this._charRenderDatas; + const charRenderInfos = this._charRenderInfos; // prettier-ignore const e0 = e[0], e1 = e[1], e2 = e[2], @@ -478,9 +478,9 @@ export class TextRenderer extends Renderer { const worldPosition2 = TextRenderer._worldPositions[2]; const worldPosition3 = TextRenderer._worldPositions[3]; - for (let i = 0, n = charRenderDatas.length; i < n; ++i) { - const charRenderData = charRenderDatas[i]; - const { localPositions } = charRenderData; + for (let i = 0, n = charRenderInfos.length; i < n; ++i) { + const charRenderInfo = charRenderInfos[i]; + const { localPositions } = charRenderInfo; const { x: topLeftX, y: topLeftY } = localPositions; // Top-Left @@ -502,7 +502,7 @@ export class TextRenderer extends Renderer { // Bottom-Right Vector3.add(worldPosition1, worldPosition2, worldPosition2); - const { chunk } = charRenderData; + const { chunk } = charRenderInfo; const vertices = chunk._meshBuffer._vertices; let index = chunk._vEntry.start; for (let i = 0; i < 4; ++i) { @@ -517,12 +517,12 @@ export class TextRenderer extends Renderer { private _updateLocalData(): void { const { min, max } = this._localBounds; - const { color, _charRenderDatas: charRenderDatas, _subFont: charFont } = this; + const { color, _charRenderInfos: charRenderInfos, _subFont: charFont } = this; const textMetrics = this.enableWrapping ? TextUtils.measureTextWithWrap(this) : TextUtils.measureTextWithoutWrap(this); const { height, lines, lineWidths, lineHeight, lineMaxSizes } = textMetrics; - const charRenderDataPool = TextRenderer._charRenderDataPool; + const charRenderInfoPool = TextRenderer._charRenderInfoPool; const linesLen = lines.length; let renderDataCount = 0; @@ -580,10 +580,10 @@ export class TextRenderer extends Renderer { const charInfo = charFont._getCharInfo(char); if (charInfo.h > 0) { firstRow < 0 && (firstRow = j); - const charRenderData = (charRenderDatas[renderDataCount++] ||= charRenderDataPool.alloc()); - charRenderData.init(this.engine); - const { chunk, localPositions } = charRenderData; - charRenderData.texture = charFont._getTextureByIndex(charInfo.index); + const charRenderInfo = (charRenderInfos[renderDataCount++] ||= charRenderInfoPool.alloc()); + charRenderInfo.init(this.engine); + const { chunk, localPositions } = charRenderInfo; + charRenderInfo.texture = charFont._getTextureByIndex(charInfo.index); const vertices = chunk._meshBuffer._vertices; const { uvs } = charInfo; const { r, g, b, a } = color; @@ -627,19 +627,19 @@ export class TextRenderer extends Renderer { } // Revert excess render data to pool. - const lastRenderDataCount = charRenderDatas.length; + const lastRenderDataCount = charRenderInfos.length; if (lastRenderDataCount > renderDataCount) { for (let i = renderDataCount; i < lastRenderDataCount; ++i) { - const charRenderData = charRenderDatas[i]; - this.engine._batcherManager._batcher2D.freeChunk(charRenderData.chunk); - charRenderData.chunk = null; - charRenderDataPool.free(charRenderData); + const charRenderInfo = charRenderInfos[i]; + this.engine._batcherManager._batcher2D.freeChunk(charRenderInfo.chunk); + charRenderInfo.chunk = null; + charRenderInfoPool.free(charRenderInfo); } - charRenderDatas.length = renderDataCount; + charRenderInfos.length = renderDataCount; } charFont._getLastIndex() > 0 && - charRenderDatas.sort((a, b) => { + charRenderInfos.sort((a, b) => { return a.texture.instanceId - b.texture.instanceId; }); } From fbf6ed14bcc3ec667014cd90e7628efd99f0fbe3 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Mon, 6 May 2024 18:48:30 +0800 Subject: [PATCH 041/218] refactor(2d-render-pipeline): opt code --- .../src/RenderPipeline/BasicRenderPipeline.ts | 2 +- .../core/src/RenderPipeline/CullingResults.ts | 8 +-- .../core/src/RenderPipeline/RenderQueue.ts | 30 +-------- .../src/RenderPipeline/batcher/Batcher2D.ts | 65 ++++++++++++++----- .../batcher/SpriteMaskBatcher.ts | 2 +- 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 058c415956..a8966f6ab7 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -86,7 +86,7 @@ export class BasicRenderPipeline { this._prepareRender(context); cullingResults.sort(); - cullingResults.update2DBatch(batcherManager._batcher2D); + cullingResults.batch(batcherManager._batcher2D); if (depthPassEnabled) { depthOnlyPass.onConfig(camera); diff --git a/packages/core/src/RenderPipeline/CullingResults.ts b/packages/core/src/RenderPipeline/CullingResults.ts index 9dca611b4e..fa372634cf 100644 --- a/packages/core/src/RenderPipeline/CullingResults.ts +++ b/packages/core/src/RenderPipeline/CullingResults.ts @@ -31,10 +31,10 @@ export class CullingResults { this.transparentQueue.sort(RenderQueue._compareForTransparent); } - update2DBatch(batcher: Batcher2D): void { - this.opaqueQueue.update2DBatch(batcher); - this.alphaTestQueue.update2DBatch(batcher); - this.transparentQueue.update2DBatch(batcher); + batch(batcher: Batcher2D): void { + this.opaqueQueue.batch(batcher); + this.alphaTestQueue.batch(batcher); + this.transparentQueue.batch(batcher); } destroy(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 54317e1936..71691a49b4 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -80,34 +80,8 @@ export class RenderQueue { this.tempElements.push(element); } - update2DBatch(batcher: Batcher2D): void { - const { tempElements } = this; - const len = tempElements.length; - if (len === 0) { - return; - } - - const { elements } = this; - for (let i = 0; i < len; ++i) { - const element = tempElements[i]; - if (element.data.usage === RenderDataUsage.Mesh) { - if (batcher._preElement) { - elements.push(batcher._preElement); - batcher._preElement = null; - } - elements.push(element); - } else { - const newElement = batcher.commitRenderElement(element); - if (newElement) { - elements.push(newElement); - } - } - } - if (batcher._preElement) { - elements.push(batcher._preElement); - batcher._preElement = null; - } - batcher.uploadBuffer(); + batch(batcher: Batcher2D): void { + batcher.batch(this.tempElements, this.elements); } render(camera: Camera, pipelineStageTagValue: string): void { diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 27b84f2b3f..162a0cb17e 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -3,6 +3,7 @@ import { Engine } from "../../Engine"; import { ShaderTagKey } from "../../shader"; import { RenderElement } from "../RenderElement"; import { SpriteRenderData } from "../SpriteRenderData"; +import { RenderDataUsage } from "../enums/RenderDataUsage"; import { MBChunk, MeshBuffer } from "./MeshBuffer"; /** @@ -43,28 +44,32 @@ export class Batcher2D { this._preElement = null; } - commitRenderElement(element: RenderElement): RenderElement | null { - const { _preElement: preElement } = this; - let batchElement = null; - if (preElement) { - if (this._canBatch(preElement, element)) { - this._udpateRenderData(preElement, element, true); + batch(srcElements, dstElements): void { + const len = srcElements.length; + if (len === 0) { + return; + } + + for (let i = 0; i < len; ++i) { + const element = srcElements[i]; + if (element.data.usage === RenderDataUsage.Mesh) { + if (this._preElement) { + dstElements.push(this._preElement); + this._preElement = null; + } + dstElements.push(element); } else { - batchElement = this._preElement; - this._udpateRenderData(preElement, element, false); + const newElement = this._commitRenderElement(element); + if (newElement) { + dstElements.push(newElement); + } } - } else { - this._udpateRenderData(preElement, element, false); } - - return batchElement; - } - - uploadBuffer(): void { - const { _meshBuffers: meshBuffers } = this; - for (let i = 0, l = meshBuffers.length; i < l; ++i) { - meshBuffers[i].uploadBuffer(); + if (this._preElement) { + dstElements.push(this._preElement); + this._preElement = null; } + this._uploadBuffer(); } clear() { @@ -102,6 +107,30 @@ export class Batcher2D { return (this._meshBuffers[index] ||= new MeshBuffer(this._engine, maxVertexCount)); } + protected _uploadBuffer(): void { + const { _meshBuffers: meshBuffers } = this; + for (let i = 0, l = meshBuffers.length; i < l; ++i) { + meshBuffers[i].uploadBuffer(); + } + } + + private _commitRenderElement(element: RenderElement): RenderElement | null { + const { _preElement: preElement } = this; + let batchElement = null; + if (preElement) { + if (this._canBatch(preElement, element)) { + this._udpateRenderData(preElement, element, true); + } else { + batchElement = this._preElement; + this._udpateRenderData(preElement, element, false); + } + } else { + this._udpateRenderData(preElement, element, false); + } + + return batchElement; + } + private _canBatch(preElement: RenderElement, cureElement: RenderElement): boolean { const preRenderData = preElement.data; const curRenderData = cureElement.data; diff --git a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts index bfe7fe4d49..0bc6e4282b 100644 --- a/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts +++ b/packages/core/src/RenderPipeline/batcher/SpriteMaskBatcher.ts @@ -44,7 +44,7 @@ export class SpriteMaskBatcher extends Batcher2D { stencilOps.push(this._preOp); } - this.uploadBuffer(); + this._uploadBuffer(); this.drawBatches(camera); } From 997f29fa92dbad08a5303b6a6c7f795ac74739e6 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 7 May 2024 10:56:50 +0800 Subject: [PATCH 042/218] refactor(2d-render-pipeline): fix render queue sort error --- packages/core/src/RenderPipeline/RenderQueue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 71691a49b4..50248aca2e 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -220,6 +220,6 @@ export class RenderQueue { * Sort the elements. */ sort(compareFunc: Function): void { - Utils._quickSort(this.elements, 0, this.elements.length, compareFunc); + Utils._quickSort(this.tempElements, 0, this.elements.length, compareFunc); } } From 68f8993674377790e40b54e7eaeef48710857e05 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 7 May 2024 10:59:57 +0800 Subject: [PATCH 043/218] refactor(2d-render-pipeline): fix render queue sort error --- packages/core/src/RenderPipeline/RenderQueue.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 50248aca2e..b35d813c23 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -220,6 +220,6 @@ export class RenderQueue { * Sort the elements. */ sort(compareFunc: Function): void { - Utils._quickSort(this.tempElements, 0, this.elements.length, compareFunc); + Utils._quickSort(this.tempElements, 0, this.tempElements.length, compareFunc); } } From 96e96219f3bd3fb59a5609cacb72066f709d1d84 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 7 May 2024 11:28:37 +0800 Subject: [PATCH 044/218] refactor(2d-render-pipeline): opt code --- .../src/RenderPipeline/BasicRenderPipeline.ts | 2 +- .../core/src/RenderPipeline/CullingResults.ts | 10 ++++------ .../core/src/RenderPipeline/RenderQueue.ts | 20 +++++++++---------- .../RenderPipeline/batcher/BatcherManager.ts | 5 +++++ 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index a8966f6ab7..aafc836dcb 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -86,7 +86,7 @@ export class BasicRenderPipeline { this._prepareRender(context); cullingResults.sort(); - cullingResults.batch(batcherManager._batcher2D); + cullingResults.batch(batcherManager); if (depthPassEnabled) { depthOnlyPass.onConfig(camera); diff --git a/packages/core/src/RenderPipeline/CullingResults.ts b/packages/core/src/RenderPipeline/CullingResults.ts index fa372634cf..bbf3e92159 100644 --- a/packages/core/src/RenderPipeline/CullingResults.ts +++ b/packages/core/src/RenderPipeline/CullingResults.ts @@ -1,7 +1,5 @@ -import { Engine } from "../Engine"; import { RenderQueueType } from "../shader"; import { RenderQueue } from "./RenderQueue"; -import { Batcher2D } from "./batcher/Batcher2D"; import { BatcherManager } from "./batcher/BatcherManager"; /** @@ -31,10 +29,10 @@ export class CullingResults { this.transparentQueue.sort(RenderQueue._compareForTransparent); } - batch(batcher: Batcher2D): void { - this.opaqueQueue.batch(batcher); - this.alphaTestQueue.batch(batcher); - this.transparentQueue.batch(batcher); + batch(batcherManager: BatcherManager): void { + this.opaqueQueue.batch(batcherManager); + this.alphaTestQueue.batch(batcherManager); + this.transparentQueue.batch(batcherManager); } destroy(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index b35d813c23..5836e16a75 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -5,7 +5,7 @@ import { RenderQueueType, Shader, ShaderProperty } from "../shader"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; import { RenderContext } from "./RenderContext"; import { RenderElement } from "./RenderElement"; -import { Batcher2D } from "./batcher/Batcher2D"; +import { BatcherManager } from "./batcher/BatcherManager"; import { RenderDataUsage } from "./enums/RenderDataUsage"; /** @@ -64,8 +64,8 @@ export class RenderQueue { } } + readonly batchedElements: RenderElement[] = []; readonly elements: RenderElement[] = []; - readonly tempElements: RenderElement[] = []; private readonly _renderQueueType: RenderQueueType; @@ -77,16 +77,16 @@ export class RenderQueue { * Push a render element. */ pushRenderElement(element: RenderElement): void { - this.tempElements.push(element); + this.elements.push(element); } - batch(batcher: Batcher2D): void { - batcher.batch(this.tempElements, this.elements); + batch(batcherManager: BatcherManager): void { + batcherManager.batch(this.elements, this.batchedElements); } render(camera: Camera, pipelineStageTagValue: string): void { - const { elements } = this; - const len = elements.length; + const { batchedElements } = this; + const len = batchedElements.length; if (len === 0) { return; } @@ -101,7 +101,7 @@ export class RenderQueue { const renderQueueType = this._renderQueueType; for (let i = 0; i < len; i++) { - const element = elements[i]; + const element = batchedElements[i]; const { data, shaderPasses } = element; const { usage } = data; @@ -207,8 +207,8 @@ export class RenderQueue { * Clear collection. */ clear(): void { + this.batchedElements.length = 0; this.elements.length = 0; - this.tempElements.length = 0; } /** @@ -220,6 +220,6 @@ export class RenderQueue { * Sort the elements. */ sort(compareFunc: Function): void { - Utils._quickSort(this.tempElements, 0, this.tempElements.length, compareFunc); + Utils._quickSort(this.elements, 0, this.elements.length, compareFunc); } } diff --git a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts index d9e7cf1b7f..28fcdf6471 100644 --- a/packages/core/src/RenderPipeline/batcher/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/batcher/BatcherManager.ts @@ -1,6 +1,7 @@ import { Engine } from "../../Engine"; import { RenderContext } from "../RenderContext"; import { RenderData } from "../RenderData"; +import { RenderElement } from "../RenderElement"; import { RenderDataUsage } from "../enums/RenderDataUsage"; import { Batcher2D } from "./Batcher2D"; @@ -33,6 +34,10 @@ export class BatcherManager { } } + batch(elements: Array, batchedElements: Array): void { + this._batcher2D.batch(elements, batchedElements); + } + clear() { this._batcher2D.clear(); } From f9e67eca020fbb6c3f136154a9d0279824df3236 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 7 May 2024 15:43:33 +0800 Subject: [PATCH 045/218] refactor(2d-render-pipeline): opt performance for render queue sort --- .../core/src/RenderPipeline/RenderData.ts | 14 ++++++++ .../core/src/RenderPipeline/RenderQueue.ts | 34 ++++++------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/core/src/RenderPipeline/RenderData.ts b/packages/core/src/RenderPipeline/RenderData.ts index a9e0847c10..e0b6969efc 100644 --- a/packages/core/src/RenderPipeline/RenderData.ts +++ b/packages/core/src/RenderPipeline/RenderData.ts @@ -12,12 +12,26 @@ export class RenderData implements IPoolElement { subPrimitive: SubMesh; usage: RenderDataUsage = RenderDataUsage.Mesh; + /** @internal */ + _priority: number; + /** @internal */ + _materialPriority: number; + /** @internal */ + _componentInstanceId: number; + /** @internal */ + _distanceForSort: number; + set(component: Renderer, material: Material, primitive: Primitive, subPrimitive: SubMesh): void { this.component = component; this.material = material; this.primitive = primitive; this.subPrimitive = subPrimitive; + + this._priority = component.priority; + this._materialPriority = material._priority; + this._componentInstanceId = component.instanceId; + this._distanceForSort = component._distanceForSort; } dispose(): void { diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 5836e16a75..03d6e83a4d 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -20,22 +20,15 @@ export class RenderQueue { static _compareForOpaque(a: RenderElement, b: RenderElement): number { const dataA = a.data; const dataB = b.data; - const componentA = dataA.component; - const componentB = dataB.component; - const priorityOrder = componentA.priority - componentB.priority; + const priorityOrder = dataA._priority - dataB._priority; if (priorityOrder !== 0) { return priorityOrder; } - // make suer from the same renderer. - if (componentA.instanceId === componentB.instanceId) { - return dataA.material._priority - dataB.material._priority; + // make sure from the same renderer. + if (dataA._componentInstanceId === dataB._componentInstanceId) { + return dataA._materialPriority - dataB._materialPriority; } else { - const distanceDiff = componentA._distanceForSort - componentB._distanceForSort; - if (distanceDiff === 0) { - return componentA.instanceId - componentB.instanceId; - } else { - return distanceDiff; - } + return dataA._distanceForSort - dataB._distanceForSort || dataA._componentInstanceId - dataB._componentInstanceId; } } @@ -45,22 +38,15 @@ export class RenderQueue { static _compareForTransparent(a: RenderElement, b: RenderElement): number { const dataA = a.data; const dataB = b.data; - const componentA = dataA.component; - const componentB = dataB.component; - const priorityOrder = componentA.priority - componentB.priority; + const priorityOrder = dataA._priority - dataB._priority; if (priorityOrder !== 0) { return priorityOrder; } - // make suer from the same renderer. - if (componentA.instanceId === componentB.instanceId) { - return dataA.material._priority - dataB.material._priority; + // make sure from the same renderer. + if (dataA._componentInstanceId === dataB._componentInstanceId) { + return dataA._materialPriority - dataB._materialPriority; } else { - const distanceDiff = componentB._distanceForSort - componentA._distanceForSort; - if (distanceDiff === 0) { - return componentA.instanceId - componentB.instanceId; - } else { - return distanceDiff; - } + return dataB._distanceForSort - dataA._distanceForSort || dataA._componentInstanceId - dataB._componentInstanceId; } } From 48bcccf9e09850f584469fed97424cea8d2e23df Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 7 May 2024 16:15:02 +0800 Subject: [PATCH 046/218] refactor(2d-render-pipeline): opt performance for render queue sort --- packages/core/src/RenderPipeline/RenderQueue.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index 03d6e83a4d..18bdca2c5e 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -25,10 +25,11 @@ export class RenderQueue { return priorityOrder; } // make sure from the same renderer. - if (dataA._componentInstanceId === dataB._componentInstanceId) { + const instanceIdDiff = dataA._componentInstanceId - dataB._componentInstanceId; + if (instanceIdDiff === 0) { return dataA._materialPriority - dataB._materialPriority; } else { - return dataA._distanceForSort - dataB._distanceForSort || dataA._componentInstanceId - dataB._componentInstanceId; + return dataA._distanceForSort - dataB._distanceForSort || instanceIdDiff; } } @@ -43,10 +44,11 @@ export class RenderQueue { return priorityOrder; } // make sure from the same renderer. - if (dataA._componentInstanceId === dataB._componentInstanceId) { + const instanceIdDiff = dataA._componentInstanceId - dataB._componentInstanceId; + if (instanceIdDiff === 0) { return dataA._materialPriority - dataB._materialPriority; } else { - return dataB._distanceForSort - dataA._distanceForSort || dataA._componentInstanceId - dataB._componentInstanceId; + return dataB._distanceForSort - dataA._distanceForSort || instanceIdDiff; } } From c65299ac5d71b84f311d720ddd24e82303567c0d Mon Sep 17 00:00:00 2001 From: singlecoder Date: Tue, 7 May 2024 17:22:54 +0800 Subject: [PATCH 047/218] refactor(2d-render-pipeline): opt performance for 2d --- packages/core/src/2d/sprite/SpriteMask.ts | 15 ++++++++++++++- packages/core/src/2d/sprite/SpriteRenderer.ts | 8 ++++---- packages/core/src/2d/text/TextRenderer.ts | 8 ++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 33204094a4..59e74ca195 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -1,4 +1,4 @@ -import { BoundingBox } from "@galacean/engine-math"; +import { BoundingBox, Matrix } from "@galacean/engine-math"; import { Entity } from "../../Entity"; import { RenderContext } from "../../RenderPipeline/RenderContext"; import { RenderElement } from "../../RenderPipeline/RenderElement"; @@ -183,6 +183,19 @@ export class SpriteMask extends Renderer { target.sprite = this._sprite; } + /** + * @internal + */ + override _updateShaderData(context: RenderContext, onlyMVP: boolean): void { + if (this.getMaterial() === this.engine._spriteDefaultMaterial || onlyMVP) { + // @ts-ignore + this._updateMVPShaderData(context, Matrix._identity); + } else { + // @ts-ignore + this._updateTransformShaderData(context, Matrix._identity); + } + } + /** * @internal */ diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index ff77587e83..fd351d7dd7 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -294,13 +294,13 @@ export class SpriteRenderer extends Renderer { * @internal */ override _updateShaderData(context: RenderContext, onlyMVP: boolean): void { - if (onlyMVP) { + if (this.getMaterial() === this.engine._spriteDefaultMaterial || onlyMVP) { // @ts-ignore this._updateMVPShaderData(context, Matrix._identity); - return; + } else { + // @ts-ignore + this._updateTransformShaderData(context, Matrix._identity); } - // @ts-ignore - this._updateTransformShaderData(context, Matrix._identity); } /** diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 7835687a83..f3b51e680f 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -370,13 +370,13 @@ export class TextRenderer extends Renderer { * @internal */ override _updateShaderData(context: RenderContext, onlyMVP: boolean): void { - if (onlyMVP) { + if (this.getMaterial() === this.engine._spriteDefaultMaterial || onlyMVP) { // @ts-ignore this._updateMVPShaderData(context, Matrix._identity); - return; + } else { + // @ts-ignore + this._updateTransformShaderData(context, Matrix._identity); } - // @ts-ignore - this._updateTransformShaderData(context, Matrix._identity); } /** From 0acf868b2c7f2d4ae0e69fb52fbbb80f4646597d Mon Sep 17 00:00:00 2001 From: singlecoder Date: Wed, 8 May 2024 15:05:52 +0800 Subject: [PATCH 048/218] refactor(2d-render-pipeline): opt code --- packages/core/src/RenderPipeline/batcher/MeshBuffer.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts index fcaca56f34..557cb1bf12 100644 --- a/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts +++ b/packages/core/src/RenderPipeline/batcher/MeshBuffer.ts @@ -78,8 +78,6 @@ export class MeshBuffer { /** @internal */ _vFreeEntries: Entry[] = []; /** @internal */ - _iFreeEntries: Entry[] = []; - /** @internal */ _entryPool: Pool = new Pool(Entry, 10); /** @internal */ _chunkPool: Pool = new Pool(MBChunk, 10); @@ -117,7 +115,6 @@ export class MeshBuffer { this._vertices = new Float32Array(vertexLen); this._indices = new Uint16Array(indiceLen); this._vFreeEntries.push(new Entry(0, vertexLen)); - this._iFreeEntries.push(new Entry(0, indiceLen)); } destroy(): void { From 5871137697268d65a424f0fd48511965d934d972 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 9 May 2024 18:03:05 +0800 Subject: [PATCH 049/218] refactor(2d-render-pipeline): opt code --- packages/core/src/RenderPipeline/batcher/Batcher2D.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 162a0cb17e..57d3808bb3 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -161,10 +161,7 @@ export class Batcher2D { if (leftMaskInteraction !== right.maskInteraction) { return false; } - if (leftMaskInteraction === SpriteMaskInteraction.None) { - return true; - } - return left.maskLayer === right.maskLayer; + return leftMaskInteraction === SpriteMaskInteraction.None || left.maskLayer === right.maskLayer; } private _udpateRenderData(preElement: RenderElement, curElement: RenderElement, canBatch: boolean): void { From 999e3481ac1f3edba0b9d64d6e199a68c73e9af1 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Thu, 9 May 2024 19:01:43 +0800 Subject: [PATCH 050/218] refactor(2d-render-pipeline): opt code --- .../src/RenderPipeline/batcher/Batcher2D.ts | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts index 57d3808bb3..de4474de27 100644 --- a/packages/core/src/RenderPipeline/batcher/Batcher2D.ts +++ b/packages/core/src/RenderPipeline/batcher/Batcher2D.ts @@ -1,4 +1,4 @@ -import { SpriteMaskInteraction, SpriteRenderer } from "../../2d"; +import { SpriteMaskInteraction, SpriteRenderer, TextRenderer } from "../../2d"; import { Engine } from "../../Engine"; import { ShaderTagKey } from "../../shader"; import { RenderElement } from "../RenderElement"; @@ -138,30 +138,20 @@ export class Batcher2D { return false; } - const preRender = preRenderData.component; - const curRender = curRenderData.component; + const preRender = preRenderData.component; + const curRender = curRenderData.component; // Compare mask. - if (!this._checkBatchWithMask(preRender, curRender)) { + const preMaskInteraction = preRender.maskInteraction; + if ( + preMaskInteraction !== curRender.maskInteraction || + (preMaskInteraction !== SpriteMaskInteraction.None && preRender.maskLayer !== curRender.maskLayer) + ) { return false; } - // Compare texture. - if (preRenderData.texture !== curRenderData.texture) { - return false; - } - - // Compare material. - return preRenderData.material === curRenderData.material; - } - - private _checkBatchWithMask(left: SpriteRenderer, right: SpriteRenderer): boolean { - const leftMaskInteraction = left.maskInteraction; - - if (leftMaskInteraction !== right.maskInteraction) { - return false; - } - return leftMaskInteraction === SpriteMaskInteraction.None || left.maskLayer === right.maskLayer; + // Compare texture and material. + return preRenderData.texture === curRenderData.texture && preRenderData.material === curRenderData.material; } private _udpateRenderData(preElement: RenderElement, curElement: RenderElement, canBatch: boolean): void { @@ -187,9 +177,7 @@ export class Batcher2D { } meshBuffer._iLen += len; meshBuffer._vLen = Math.max(meshBuffer._vLen, vEntry.start + vEntry.len); - if (!canBatch) { - this._preElement = curElement; - } + !canBatch && (this._preElement = curElement); } private _reset(): void { From 8fae435aef151ad6321e4861b3c9c189ba9fa212 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 10 May 2024 14:18:52 +0800 Subject: [PATCH 051/218] feat(ui): rename resolution adaptation strategy --- .../enums/{ScreenMathMode.ts => ResolutionAdaptationStrategy.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/ui/src/enums/{ScreenMathMode.ts => ResolutionAdaptationStrategy.ts} (100%) diff --git a/packages/ui/src/enums/ScreenMathMode.ts b/packages/ui/src/enums/ResolutionAdaptationStrategy.ts similarity index 100% rename from packages/ui/src/enums/ScreenMathMode.ts rename to packages/ui/src/enums/ResolutionAdaptationStrategy.ts From 332ff645a24bdaec2c393603a7900b12c6e1b145 Mon Sep 17 00:00:00 2001 From: singlecoder Date: Fri, 10 May 2024 17:32:41 +0800 Subject: [PATCH 052/218] feat(ui): add ui canvas and ui renderer --- packages/core/src/ComponentsManager.ts | 15 ++++++++ packages/core/src/ui/UICanvas.ts | 8 +++++ packages/core/src/ui/UIRenderer.ts | 33 +++++++++++++++++ .../src/ui}/enums/CanvasRenderMode.ts | 0 .../ui}/enums/ResolutionAdaptationStrategy.ts | 2 +- packages/core/src/ui/index.ts | 5 +++ packages/ui/README.md | 0 packages/ui/package.json | 35 ------------------- packages/ui/src/UICanvas.ts | 3 -- packages/ui/src/UIRenderer.ts | 3 -- packages/ui/src/index.ts | 0 packages/ui/tsconfig.json | 18 ---------- 12 files changed, 62 insertions(+), 60 deletions(-) create mode 100644 packages/core/src/ui/UICanvas.ts create mode 100644 packages/core/src/ui/UIRenderer.ts rename packages/{ui/src => core/src/ui}/enums/CanvasRenderMode.ts (100%) rename packages/{ui/src => core/src/ui}/enums/ResolutionAdaptationStrategy.ts (80%) create mode 100644 packages/core/src/ui/index.ts delete mode 100644 packages/ui/README.md delete mode 100644 packages/ui/package.json delete mode 100644 packages/ui/src/UICanvas.ts delete mode 100644 packages/ui/src/UIRenderer.ts delete mode 100644 packages/ui/src/index.ts delete mode 100644 packages/ui/tsconfig.json diff --git a/packages/core/src/ComponentsManager.ts b/packages/core/src/ComponentsManager.ts index 09b0096c21..2e5e78365e 100644 --- a/packages/core/src/ComponentsManager.ts +++ b/packages/core/src/ComponentsManager.ts @@ -4,6 +4,7 @@ import { DisorderedArray } from "./DisorderedArray"; import { Renderer } from "./Renderer"; import { Script } from "./Script"; import { Animator } from "./animation"; +import { UICanvas } from "./ui"; /** * The manager of the components. @@ -15,6 +16,8 @@ export class ComponentsManager { _activeCameras: DisorderedArray = new DisorderedArray(); /** @internal */ _renderers: DisorderedArray = new DisorderedArray(); + /** @internal */ + _uiCanvases: DisorderedArray = new DisorderedArray(); // Script private _onStartScripts: DisorderedArray