From 640ae67045cf7a33c0cd7b147ddef7eaee8ca0de Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Fri, 5 Jan 2024 11:25:49 +0800 Subject: [PATCH 1/7] feat: sprite support rotate --- .../src/2d/assembler/SimpleSpriteAssembler.ts | 11 +-- packages/core/src/2d/sprite/Sprite.ts | 76 ++++++++++++++----- packages/loader/src/SpriteAtlasLoader.ts | 10 ++- 3 files changed, 67 insertions(+), 30 deletions(-) diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index e135e77d9a..427fe73b6f 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -52,18 +52,15 @@ export class SimpleSpriteAssembler { 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]); } - BoundingBox.transform(sprite._getBounds(), worldMatrix, renderer._bounds); } 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); + renderUVs[0].copyFrom(spriteUVs[0]); + renderUVs[1].copyFrom(spriteUVs[1]); + renderUVs[2].copyFrom(spriteUVs[2]); + renderUVs[3].copyFrom(spriteUVs[3]); } } diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index 9b2257227e..e722ea3d2f 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -20,6 +20,7 @@ export class Sprite extends ReferResource { private _positions: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; private _uvs: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; + private _boundUVs: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; private _bounds: BoundingBox = new BoundingBox(); private _texture: Texture2D = null; @@ -288,15 +289,24 @@ export class Sprite extends ReferResource { private _calDefaultSize(): void { if (this._texture) { const { _texture, _atlasRegion, _atlasRegionOffset, _region } = this; - const pixelsPerUnitReciprocal = 1.0 / Engine._pixelsPerUnit; + const ppuReciprocal = 1.0 / Engine._pixelsPerUnit; + const rotated = this._atlasRotated; + let regionWidth: number, regionHeight: number; + if (this._atlasRotated) { + this._automaticWidth = + ((_texture.width * _atlasRegion.height) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * + _region.width * + ppuReciprocal; + regionHeight = _texture.height * _atlasRegion.width; + } else { + regionWidth = _texture.width * _atlasRegion.width; + regionHeight = _texture.height * _atlasRegion.height; + } + this._automaticWidth = - ((_texture.width * _atlasRegion.width) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * - _region.width * - pixelsPerUnitReciprocal; + (regionWidth / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * _region.width * ppuReciprocal; this._automaticHeight = - ((_texture.height * _atlasRegion.height) / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * - _region.height * - pixelsPerUnitReciprocal; + (regionHeight / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * _region.height * ppuReciprocal; } else { this._automaticWidth = this._automaticHeight = 0; } @@ -346,20 +356,44 @@ export class Sprite extends ReferResource { const right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; const bottom = atlasRegionH + atlasRegionY - Math.max(regionY - offsetBottom, 0) * realHeight; const { x: borderLeft, y: borderBottom, z: borderRight, w: borderTop } = this._border; - // Left-Bottom - uv[0].set(left, bottom); - // Border ( Left-Bottom ) - uv[1].set( - (regionX - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX, - atlasRegionH + atlasRegionY - (regionY - offsetBottom + borderBottom * regionH) * realHeight - ); - // Border ( Right-Top ) - uv[2].set( - atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth, - (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY - ); - // Right-Top - uv[3].set(right, top); + if (this._atlasRotated) { + // Left-Bottom + uv[0].set(left, top); + // Right-Bottom + uv[1].set(left, bottom); + // Left-Top + uv[2].set(right, top); + // Right-Top + uv[3].set(right, bottom); + // uv[1].set( + // (regionX - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX, + // (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY + // ); + // uv[2].set( + // atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth, + // atlasRegionH + atlasRegionY - (regionY - offsetBottom + borderBottom * regionH) * realHeight + // ); + // uv[3].set(right, bottom); + } else { + // Left-Bottom + uv[0].set(left, bottom); + // Right-Bottom + uv[1].set(right, bottom); + // Left-Top + uv[2].set(left, top); + // Right-Top + uv[3].set(right, top); + // // Border ( Left-Bottom ) + // uv[1].set( + // (regionX - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX, + // atlasRegionH + atlasRegionY - (regionY - offsetBottom + borderBottom * regionH) * realHeight + // ); + // // Border ( Right-Top ) + // uv[2].set( + // atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth, + // (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY + // ); + } this._dirtyUpdateFlag &= ~SpriteUpdateFlags.uvs; } diff --git a/packages/loader/src/SpriteAtlasLoader.ts b/packages/loader/src/SpriteAtlasLoader.ts index 5a4406f5f9..5d38edadd9 100644 --- a/packages/loader/src/SpriteAtlasLoader.ts +++ b/packages/loader/src/SpriteAtlasLoader.ts @@ -94,14 +94,20 @@ class SpriteAtlasLoader extends Loader { config.name ); if (texture) { + const atlasRotated = config.atlasRotated ?? false; + // const atlasRotated = false; const invW = 1 / texture.width; const invH = 1 / texture.height; - sprite.atlasRegion.set(atlasRegion.x * invW, atlasRegion.y * invH, atlasRegion.w * invW, atlasRegion.h * invH); + if (atlasRotated) { + sprite.atlasRegion.set(atlasRegion.x * invW, atlasRegion.y * invH, atlasRegion.h * invW, atlasRegion.w * invH); + } else { + sprite.atlasRegion.set(atlasRegion.x * invW, atlasRegion.y * invH, atlasRegion.w * invW, atlasRegion.h * invH); + } if (atlasRegionOffset) { const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; sprite.atlasRegionOffset.set(offsetLeft * invW, offsetTop * invH, offsetRight * invW, offsetBottom * invH); } - config.atlasRotated && (sprite.atlasRotated = true); + sprite.atlasRotated = atlasRotated; } return sprite; } From 0abd06f62309014e36591f1ef9773d2ea0f6bde2 Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Sun, 7 Jan 2024 18:07:05 +0800 Subject: [PATCH 2/7] feat: sprite supported rotate --- .../src/2d/assembler/SimpleSpriteAssembler.ts | 6 +- .../src/2d/assembler/SlicedSpriteAssembler.ts | 31 ++-- .../src/2d/assembler/TiledSpriteAssembler.ts | 121 ++++++++------ packages/core/src/2d/sprite/Sprite.ts | 157 ++++++++++-------- packages/loader/src/SpriteAtlasLoader.ts | 10 +- 5 files changed, 183 insertions(+), 142 deletions(-) diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index 427fe73b6f..be4d90b380 100644 --- a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts @@ -59,8 +59,8 @@ export class SimpleSpriteAssembler { const spriteUVs = renderer.sprite._getUVs(); const renderUVs = renderer._verticesData.uvs; renderUVs[0].copyFrom(spriteUVs[0]); - renderUVs[1].copyFrom(spriteUVs[1]); - renderUVs[2].copyFrom(spriteUVs[2]); - renderUVs[3].copyFrom(spriteUVs[3]); + renderUVs[1].copyFrom(spriteUVs[3]); + renderUVs[2].copyFrom(spriteUVs[12]); + renderUVs[3].copyFrom(spriteUVs[15]); } } diff --git a/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts b/packages/core/src/2d/assembler/SlicedSpriteAssembler.ts index 19aebf5bcf..e8ae86b158 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 @@ -27,9 +26,8 @@ export class SlicedSpriteAssembler { static updatePositions(renderer: SpriteRenderer): void { const { width, height, sprite } = renderer; - const { positions, uvs } = renderer._verticesData; + const { positions } = renderer._verticesData; const { border } = sprite; - const spriteUVs = sprite._getUVs(); // Update local positions. const spritePositions = sprite._getPositions(); const { x: left, y: bottom } = spritePositions[0]; @@ -95,27 +93,24 @@ export class SlicedSpriteAssembler { wE[14] = pWE[14] - localTransX * wE[2] - localTransY * wE[6]; // ------------------------ - // 3 - 7 - 11 - 15 + // 12 -13 -14 - 15 // | | | | - // 2 - 6 - 10 - 14 + // 8 - 9 - 10 - 11 // | | | | - // 1 - 5 - 9 - 13 + // 4 - 5 - 6 - 7 // | | | | - // 0 - 4 - 8 - 12 + // 0 - 1 - 2 - 3 // ------------------------ - // Assemble position and uv. + // Assemble positions. for (let i = 0; i < 4; i++) { - const rowValue = row[i]; - const rowU = spriteUVs[i].x; + const columnValue = column[i]; for (let j = 0; j < 4; j++) { - const columnValue = column[j]; - const idx = i * 4 + j; - positions[idx].set( + const rowValue = row[j]; + positions[i * 4 + j].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); } } @@ -125,5 +120,11 @@ export class SlicedSpriteAssembler { renderer._bounds.transform(worldMatrix); } - static updateUVs(renderer: SpriteRenderer): void {} + static updateUVs(renderer: SpriteRenderer): void { + const spriteUVs = renderer.sprite._getUVs(); + const renderUVs = renderer._verticesData.uvs; + for (let i = 0; i < 16; i++) { + renderUVs[i].copyFrom(spriteUVs[i]); + } + } } diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index d6e31218ff..2cee63c051 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -1,13 +1,12 @@ 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 { Logger } from "../../base"; +import { StaticInterfaceImplement } from "../../base/StaticInterfaceImplement"; +import { SpriteTileMode } from "../enums/SpriteTileMode"; import { Sprite } from "../sprite"; import { SpriteRenderer } from "../sprite/SpriteRenderer"; import { IAssembler } from "./IAssembler"; -import { Logger } from "../../base"; -import { SimpleSpriteAssembler } from "./SimpleSpriteAssembler"; /** * @internal @@ -17,8 +16,8 @@ export class TiledSpriteAssembler { static _worldMatrix: Matrix = new Matrix(); static _posRow: DisorderedArray = new DisorderedArray(); static _posColumn: DisorderedArray = new DisorderedArray(); - static _uvRow: DisorderedArray = new DisorderedArray(); - static _uvColumn: DisorderedArray = new DisorderedArray(); + static _uvRowInfo: DisorderedArray = new DisorderedArray(); + static _uvColumnInfo: DisorderedArray = new DisorderedArray(); static resetData(renderer: SpriteRenderer): void { renderer._verticesData.triangles = []; @@ -28,15 +27,16 @@ export class TiledSpriteAssembler { 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; + const { _posRow: posRow, _posColumn: posColumn, _uvRowInfo: uvRowInfo, _uvColumnInfo: uvColumnInfo } = this; + posRow.length = posColumn.length = uvRowInfo.length = uvColumnInfo.length = 0; tileMode === SpriteTileMode.Adaptive - ? this._calculateAdaptiveDividing(sprite, width, height, threshold, posRow, posColumn, uvRow, uvColumn) - : this._calculateContinuousDividing(sprite, width, height, posRow, posColumn, uvRow, uvColumn); + ? this._calculateAdaptiveDividing(sprite, width, height, threshold, posRow, posColumn, uvRowInfo, uvColumnInfo) + : this._calculateContinuousDividing(sprite, width, height, posRow, posColumn, uvRowInfo, uvColumnInfo); // Update renderer's worldMatrix const { x: pivotX, y: pivotY } = renderer.sprite.pivot; const localTransX = renderer.width * pivotX; const localTransY = renderer.height * pivotY; + const spriteUVs = sprite._getUVs(); // Renderer's worldMatrix const { _worldMatrix: worldMatrix } = TiledSpriteAssembler; const { elements: wE } = worldMatrix; @@ -60,11 +60,11 @@ export class TiledSpriteAssembler { 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)) { + const rowForm = uvRowInfo.get(2 * i); + const rowTo = uvRowInfo.get(2 * i + 1); + const colFrom = uvColumnInfo.get(doubleJ); + const colTo = uvColumnInfo.get(doubleJ + 1); + if (isNaN(rowForm) || isNaN(rowTo) || isNaN(colFrom) || isNaN(colTo)) { continue; } triangles[trianglesOffset++] = count; @@ -78,8 +78,17 @@ export class TiledSpriteAssembler { 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)); + TiledSpriteAssembler._getCorners( + spriteUVs, + rowForm, + rowTo, + colFrom, + colTo, + (uvs[count] ||= new Vector2()), + (uvs[count + 1] ||= new Vector2()), + (uvs[count + 2] ||= new Vector2()), + (uvs[count + 3] ||= new Vector2()) + ); let pos = positions[count]; if (pos) { pos.set(wE0 * l + wE4 * b + wE12, wE1 * l + wE5 * b + wE13, wE2 * l + wE6 * b + wE14); @@ -89,7 +98,6 @@ export class TiledSpriteAssembler { count++; // 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); @@ -99,7 +107,6 @@ export class TiledSpriteAssembler { count++; // 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); @@ -109,7 +116,6 @@ export class TiledSpriteAssembler { count++; // 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); @@ -192,8 +198,8 @@ export class TiledSpriteAssembler { if ((rVertCount - 1) * (cVertCount - 1) * 4 > Basic2DBatcher.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); + uvRow.add(0), uvRow.add(3); + uvColumn.add(0), uvColumn.add(3); Logger.warn(`The number of vertices exceeds the upper limit(${Basic2DBatcher.MAX_VERTEX_COUNT}).`); return; } @@ -203,24 +209,23 @@ export class TiledSpriteAssembler { scale = width / fixedLR; posRow.add(expectWidth * left * scale), posRow.add(fixedL * scale); posRow.add(width - expectWidth * (1 - right) * scale); - uvRow.add(spriteUV0.x), uvRow.add(spriteUV1.x), uvRow.add(spriteUV2.x), uvRow.add(spriteUV3.x); + uvRow.add(0), uvRow.add(1), uvRow.add(2), uvRow.add(3); break; case TiledType.WithoutTiled: posRow.add(expectWidth * left), posRow.add(fixedL), posRow.add(width - fixedR); posRow.add(width - expectWidth * (1 - right)); - uvRow.add(spriteUV0.x), uvRow.add(spriteUV1.x), uvRow.add(NaN), uvRow.add(NaN); - uvRow.add(spriteUV2.x), uvRow.add(spriteUV3.x); + uvRow.add(0), uvRow.add(1), uvRow.add(NaN), uvRow.add(NaN), uvRow.add(2), uvRow.add(3); break; case TiledType.WithTiled: scale = width / (fixedLR + rRepeatCount * fixedCW); posRow.add(expectWidth * left * scale), posRow.add(fixedL * scale); - uvRow.add(spriteUV0.x), uvRow.add(spriteUV1.x), uvRow.add(spriteUV1.x); + uvRow.add(0), uvRow.add(1), uvRow.add(1); for (let i = 0, l = rRepeatCount - 1; i < l; i++) { posRow.add(fixedL + (i + 1) * fixedCW * scale); - uvRow.add(spriteUV2.x), uvRow.add(spriteUV1.x); + uvRow.add(2), uvRow.add(1); } posRow.add(width - fixedR * scale), posRow.add(width - expectWidth * (1 - right) * scale); - uvRow.add(spriteUV2.x), uvRow.add(spriteUV2.x), uvRow.add(spriteUV3.x); + uvRow.add(2), uvRow.add(2), uvRow.add(3); break; default: break; @@ -231,24 +236,23 @@ export class TiledSpriteAssembler { scale = height / fixedTB; posColumn.add(expectHeight * bottom * scale), posColumn.add(fixedB * scale); posColumn.add(height - expectHeight * (1 - top) * scale); - uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV1.y), uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV3.y); + uvColumn.add(0), uvColumn.add(1), uvColumn.add(2), uvColumn.add(3); break; case TiledType.WithoutTiled: posColumn.add(expectHeight * bottom), posColumn.add(fixedB), posColumn.add(height - fixedT); posColumn.add(height - expectHeight * (1 - top)); - uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV1.y), uvColumn.add(NaN), uvColumn.add(NaN); - uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV3.y); + uvColumn.add(0), uvColumn.add(1), uvColumn.add(NaN), uvColumn.add(NaN), uvColumn.add(2), uvColumn.add(3); break; case TiledType.WithTiled: scale = height / (fixedTB + cRepeatCount * fixedCH); posColumn.add(expectHeight * bottom * scale), posColumn.add(fixedB * scale); - uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV1.y), uvColumn.add(spriteUV1.y); + uvColumn.add(0), uvColumn.add(1), uvColumn.add(1); for (let i = 0, l = cRepeatCount - 1; i < l; i++) { posColumn.add(fixedB + (i + 1) * fixedCH * scale); - uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV1.y); + uvColumn.add(2), uvColumn.add(1); } posColumn.add(height - fixedT * scale), posColumn.add(height - expectHeight * (1 - top) * scale); - uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV3.y); + uvColumn.add(2), uvColumn.add(2), uvColumn.add(3); break; default: break; @@ -312,8 +316,8 @@ export class TiledSpriteAssembler { if ((rVertCount - 1) * (cVertCount - 1) * 4 > Basic2DBatcher.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); + uvRow.add(0), uvRow.add(3); + uvColumn.add(0), uvColumn.add(3); Logger.warn(`The number of vertices exceeds the upper limit(${Basic2DBatcher.MAX_VERTEX_COUNT}).`); return; } @@ -323,25 +327,25 @@ export class TiledSpriteAssembler { const scale = width / fixedLR; posRow.add(expectWidth * left * scale), posRow.add(fixedL * scale); posRow.add(width - expectWidth * (1 - right) * scale); - uvRow.add(spriteUV0.x), uvRow.add(spriteUV1.x), uvRow.add(spriteUV2.x), uvRow.add(spriteUV3.x); + uvRow.add(0), uvRow.add(1), uvRow.add(2), uvRow.add(3); break; case TiledType.WithoutTiled: posRow.add(expectWidth * left), posRow.add(fixedL), posRow.add(width - fixedR); posRow.add(width - expectWidth * (1 - right)); - uvRow.add(spriteUV0.x), uvRow.add(spriteUV1.x), uvRow.add(NaN), uvRow.add(NaN); - uvRow.add(spriteUV2.x), uvRow.add(spriteUV3.x); + uvRow.add(0), uvRow.add(1), uvRow.add(NaN), uvRow.add(NaN), uvRow.add(2), uvRow.add(3); break; case TiledType.WithTiled: posRow.add(expectWidth * left), posRow.add(fixedL); - uvRow.add(spriteUV0.x), uvRow.add(spriteUV1.x), uvRow.add(spriteUV1.x); + uvRow.add(0), uvRow.add(1), uvRow.add(1); const countInteger = rRepeatCount | 0; for (let i = 0; i < countInteger; i++) { posRow.add(fixedL + (i + 1) * fixedCW); - uvRow.add(spriteUV2.x), uvRow.add(spriteUV1.x); + uvRow.add(2), uvRow.add(1); } posRow.add(width - fixedR), posRow.add(width - expectWidth * (1 - right)); - uvRow.add((spriteUV2.x - spriteUV1.x) * (rRepeatCount - countInteger) + spriteUV1.x); - uvRow.add(spriteUV2.x), uvRow.add(spriteUV3.x); + // uvRow.add((spriteUV2.x - spriteUV1.x) * (rRepeatCount - countInteger) + spriteUV1.x); + uvRow.add(2); + uvRow.add(2), uvRow.add(3); break; default: break; @@ -352,30 +356,47 @@ export class TiledSpriteAssembler { const scale = height / fixedTB; posColumn.add(expectHeight * bottom * scale), posColumn.add(fixedB * scale); posColumn.add(height - expectHeight * (1 - top) * scale); - uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV1.y), uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV3.y); + uvColumn.add(0), uvColumn.add(1), uvColumn.add(2), uvColumn.add(3); break; case TiledType.WithoutTiled: posColumn.add(expectHeight * bottom), posColumn.add(fixedB), posColumn.add(height - fixedT); posColumn.add(height - expectHeight * (1 - top)); - uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV1.y), uvColumn.add(NaN), uvColumn.add(NaN); - uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV3.y); + uvColumn.add(0), uvColumn.add(1), uvColumn.add(NaN), uvColumn.add(NaN), uvColumn.add(2), uvColumn.add(3); break; case TiledType.WithTiled: posColumn.add(expectHeight * bottom), posColumn.add(fixedB); - uvColumn.add(spriteUV0.y), uvColumn.add(spriteUV1.y), uvColumn.add(spriteUV1.y); + uvColumn.add(0), uvColumn.add(1), uvColumn.add(1); const countInteger = cRepeatCount | 0; for (let i = 0; i < countInteger; i++) { posColumn.add(fixedB + (i + 1) * fixedCH); - uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV1.y); + uvColumn.add(2), uvColumn.add(1); } posColumn.add(height - fixedT), posColumn.add(height - expectHeight * (1 - top)); - uvColumn.add((spriteUV2.y - spriteUV1.y) * (cRepeatCount - countInteger) + spriteUV1.y); - uvColumn.add(spriteUV2.y), uvColumn.add(spriteUV3.y); + // uvColumn.add((spriteUV2.y - spriteUV1.y) * (cRepeatCount - countInteger) + spriteUV1.y); + uvColumn.add(2); + uvColumn.add(2), uvColumn.add(3); break; default: break; } } + + private static _getCorners( + uvs: Vector2[], + rowFrom: number, + rowTo: number, + colFrom: number, + colTo: number, + leftBottom: Vector2, + rightBottom: Vector2, + leftTop: Vector2, + rightTop: Vector2 + ): void { + leftBottom.copyFrom(uvs[rowFrom + colFrom * 4]); + rightBottom.copyFrom(uvs[rowTo + colFrom * 4]); + leftTop.copyFrom(uvs[rowFrom + colTo * 4]); + rightTop.copyFrom(uvs[rowTo + colTo * 4]); + } } enum TiledType { diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index e722ea3d2f..bdff7f740f 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -3,8 +3,8 @@ import { Engine } from "../../Engine"; import { UpdateFlagManager } from "../../UpdateFlagManager"; import { ReferResource } from "../../asset/ReferResource"; import { Texture2D } from "../../texture/Texture2D"; -import { SpriteModifyFlags } from "../enums/SpriteModifyFlags"; import { SpriteAtlas } from "../atlas/SpriteAtlas"; +import { SpriteModifyFlags } from "../enums/SpriteModifyFlags"; /** * 2D sprite. @@ -19,8 +19,24 @@ export class Sprite extends ReferResource { private _customHeight: number = undefined; private _positions: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; - private _uvs: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; - private _boundUVs: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; + private _uvs: Vector2[] = [ + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2(), + new Vector2() + ]; private _bounds: BoundingBox = new BoundingBox(); private _texture: Texture2D = null; @@ -177,7 +193,7 @@ export class Sprite extends ReferResource { * x y z w * | | | | * Left, bottom, right, top. - * @remarks only use in sliced mode. + * @remarks only use in sliced or tiled mode. */ get border(): Vector4 { return this._border; @@ -288,25 +304,14 @@ export class Sprite extends ReferResource { private _calDefaultSize(): void { if (this._texture) { - const { _texture, _atlasRegion, _atlasRegionOffset, _region } = this; + const { _texture, _atlasRegion, _atlasRegionOffset, _region, _atlasRotated } = this; const ppuReciprocal = 1.0 / Engine._pixelsPerUnit; - const rotated = this._atlasRotated; - let regionWidth: number, regionHeight: number; - if (this._atlasRotated) { - this._automaticWidth = - ((_texture.width * _atlasRegion.height) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * - _region.width * - ppuReciprocal; - regionHeight = _texture.height * _atlasRegion.width; - } else { - regionWidth = _texture.width * _atlasRegion.width; - regionHeight = _texture.height * _atlasRegion.height; - } - + const originWidth = _texture.width * (_atlasRotated ? _atlasRegion.height : _atlasRegion.width); + const originHeight = _texture.height * (_atlasRotated ? _atlasRegion.width : _atlasRegion.height); this._automaticWidth = - (regionWidth / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * _region.width * ppuReciprocal; + (originWidth / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * _region.width * ppuReciprocal; this._automaticHeight = - (regionHeight / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * _region.height * ppuReciprocal; + (originHeight / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * _region.height * ppuReciprocal; } else { this._automaticWidth = this._automaticHeight = 0; } @@ -342,57 +347,77 @@ export class Sprite extends ReferResource { } private _updateUVs(): void { - const { _uvs: uv, _atlasRegionOffset: atlasRegionOffset } = this; - const { x: regionX, y: regionY, width: regionW, height: regionH } = this._region; - const regionRight = 1 - regionX - regionW; - const regionBottom = 1 - regionY - regionH; + const { _uvs: uvs, _atlasRotated: atlasRotated } = this; + const { x: regionLeft, y: regionTop, width: regionW, height: regionH } = this._region; + const regionRight = 1 - regionLeft - regionW; + const regionBottom = 1 - regionTop - regionH; + const { x: atlasRegionX, y: atlasRegionY, width: atlasRegionW, height: atlasRegionH } = this._atlasRegion; - const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; + const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = this._atlasRegionOffset; const realWidth = atlasRegionW / (1 - offsetLeft - offsetRight); const realHeight = atlasRegionH / (1 - offsetTop - offsetBottom); - // Coordinates of the four boundaries. - const left = Math.max(regionX - offsetLeft, 0) * realWidth + atlasRegionX; - const top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; - const right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; - const bottom = atlasRegionH + atlasRegionY - Math.max(regionY - offsetBottom, 0) * realHeight; + const { x: borderLeft, y: borderBottom, z: borderRight, w: borderTop } = this._border; - if (this._atlasRotated) { - // Left-Bottom - uv[0].set(left, top); - // Right-Bottom - uv[1].set(left, bottom); - // Left-Top - uv[2].set(right, top); - // Right-Top - uv[3].set(right, bottom); - // uv[1].set( - // (regionX - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX, - // (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY - // ); - // uv[2].set( - // atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth, - // atlasRegionH + atlasRegionY - (regionY - offsetBottom + borderBottom * regionH) * realHeight - // ); - // uv[3].set(right, bottom); + + // Coordinates of the four boundaries. + let left: number, top: number, right: number, bottom: number; + let borderL: number, borderT: number, borderR: number, borderB: number; + if (atlasRotated) { + left = Math.max(regionBottom - offsetLeft, 0) * realWidth + atlasRegionX; + top = Math.max(regionLeft - offsetTop, 0) * realHeight + atlasRegionY; + right = atlasRegionW + atlasRegionX - Math.max(regionTop - offsetRight, 0) * realWidth; + bottom = atlasRegionH + atlasRegionY - Math.max(regionRight - offsetBottom, 0) * realHeight; + + borderL = (regionBottom - offsetLeft + borderBottom * regionH) * realWidth + atlasRegionX; + borderT = (regionLeft - offsetTop + borderLeft * regionW) * realHeight + atlasRegionY; + borderR = atlasRegionW + atlasRegionX - (regionTop - offsetRight + borderTop * regionH) * realWidth; + borderB = atlasRegionH + atlasRegionY - (regionRight - offsetBottom + borderRight * regionW) * realHeight; + } else { + left = Math.max(regionLeft - offsetLeft, 0) * realWidth + atlasRegionX; + top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; + right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; + bottom = atlasRegionH + atlasRegionY - Math.max(regionTop - offsetBottom, 0) * realHeight; + + borderL = (regionLeft - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX; + borderT = (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY; + borderR = atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth; + borderB = atlasRegionH + atlasRegionY - (regionTop - offsetBottom + borderBottom * regionH) * realHeight; + } + + if (atlasRotated) { + uvs[0].set(left, top); + uvs[1].set(left, borderT); + uvs[2].set(left, borderB); + uvs[3].set(left, bottom); + uvs[4].set(borderL, top); + uvs[5].set(borderL, borderT); + uvs[6].set(borderL, borderB); + uvs[7].set(borderL, bottom); + uvs[8].set(borderR, top); + uvs[9].set(borderR, borderT); + uvs[10].set(borderR, borderB); + uvs[11].set(borderR, bottom); + uvs[12].set(right, top); + uvs[13].set(right, borderT); + uvs[14].set(right, borderB); + uvs[15].set(right, bottom); } else { - // Left-Bottom - uv[0].set(left, bottom); - // Right-Bottom - uv[1].set(right, bottom); - // Left-Top - uv[2].set(left, top); - // Right-Top - uv[3].set(right, top); - // // Border ( Left-Bottom ) - // uv[1].set( - // (regionX - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX, - // atlasRegionH + atlasRegionY - (regionY - offsetBottom + borderBottom * regionH) * realHeight - // ); - // // Border ( Right-Top ) - // uv[2].set( - // atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth, - // (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY - // ); + uvs[0].set(left, bottom); + uvs[1].set(borderL, bottom); + uvs[2].set(borderR, bottom); + uvs[3].set(right, bottom); + uvs[4].set(left, borderB); + uvs[5].set(borderL, borderB); + uvs[6].set(borderR, borderB); + uvs[7].set(right, borderB); + uvs[8].set(left, borderT); + uvs[9].set(borderL, borderT); + uvs[10].set(borderR, borderT); + uvs[11].set(right, borderT); + uvs[12].set(left, top); + uvs[13].set(borderL, top); + uvs[14].set(borderR, top); + uvs[15].set(right, top); } this._dirtyUpdateFlag &= ~SpriteUpdateFlags.uvs; } diff --git a/packages/loader/src/SpriteAtlasLoader.ts b/packages/loader/src/SpriteAtlasLoader.ts index 5d38edadd9..be9e4828ce 100644 --- a/packages/loader/src/SpriteAtlasLoader.ts +++ b/packages/loader/src/SpriteAtlasLoader.ts @@ -94,20 +94,14 @@ class SpriteAtlasLoader extends Loader { config.name ); if (texture) { - const atlasRotated = config.atlasRotated ?? false; - // const atlasRotated = false; const invW = 1 / texture.width; const invH = 1 / texture.height; - if (atlasRotated) { - sprite.atlasRegion.set(atlasRegion.x * invW, atlasRegion.y * invH, atlasRegion.h * invW, atlasRegion.w * invH); - } else { - sprite.atlasRegion.set(atlasRegion.x * invW, atlasRegion.y * invH, atlasRegion.w * invW, atlasRegion.h * invH); - } + sprite.atlasRegion.set(atlasRegion.x * invW, atlasRegion.y * invH, atlasRegion.w * invW, atlasRegion.h * invH); if (atlasRegionOffset) { const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = atlasRegionOffset; sprite.atlasRegionOffset.set(offsetLeft * invW, offsetTop * invH, offsetRight * invW, offsetBottom * invH); } - sprite.atlasRotated = atlasRotated; + sprite.atlasRotated = config.atlasRotated ?? false; } return sprite; } From 37a51055043c02f497a563f55e7f30b67ac39713 Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Mon, 8 Jan 2024 11:35:50 +0800 Subject: [PATCH 3/7] feat: sprite support rotate --- packages/core/src/2d/assembler/TiledSpriteAssembler.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 2cee63c051..92634a2768 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -393,9 +393,12 @@ export class TiledSpriteAssembler { rightTop: Vector2 ): void { leftBottom.copyFrom(uvs[rowFrom + colFrom * 4]); - rightBottom.copyFrom(uvs[rowTo + colFrom * 4]); - leftTop.copyFrom(uvs[rowFrom + colTo * 4]); - rightTop.copyFrom(uvs[rowTo + colTo * 4]); + const rowToInteger = rowTo | 0; + const colToInteger = colTo | 0; + Vector2.lerp(uvs[Math.floor(rowTo) + colFrom * 4], uvs[Math.ceil(rowTo) + colFrom * 4], rowToInteger, rightBottom); + Vector2.lerp(uvs[rowFrom + Math.floor(colTo) * 4], uvs[rowFrom + Math.ceil(colTo) * 4], colToInteger, leftTop); + Vector2.add(rightBottom, leftTop, rightTop); + rightTop.subtract(leftBottom); } } From ed67ec2eab8d7b82a7b55c532561df48e3d230f7 Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Mon, 8 Jan 2024 22:30:06 +0800 Subject: [PATCH 4/7] feat: atlas support rotate --- .../src/2d/assembler/TiledSpriteAssembler.ts | 26 +++---- packages/core/src/2d/sprite/Sprite.ts | 76 +++++++++---------- 2 files changed, 47 insertions(+), 55 deletions(-) diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 92634a2768..2f81eda944 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -16,8 +16,8 @@ export class TiledSpriteAssembler { static _worldMatrix: Matrix = new Matrix(); static _posRow: DisorderedArray = new DisorderedArray(); static _posColumn: DisorderedArray = new DisorderedArray(); - static _uvRowInfo: DisorderedArray = new DisorderedArray(); - static _uvColumnInfo: DisorderedArray = new DisorderedArray(); + static _uvRow: DisorderedArray = new DisorderedArray(); + static _uvColumn: DisorderedArray = new DisorderedArray(); static resetData(renderer: SpriteRenderer): void { renderer._verticesData.triangles = []; @@ -27,11 +27,11 @@ export class TiledSpriteAssembler { const { width, height, sprite, tileMode, tiledAdaptiveThreshold: threshold } = renderer; const { positions, uvs, triangles } = renderer._verticesData; // Calculate row and column - const { _posRow: posRow, _posColumn: posColumn, _uvRowInfo: uvRowInfo, _uvColumnInfo: uvColumnInfo } = this; - posRow.length = posColumn.length = uvRowInfo.length = uvColumnInfo.length = 0; + const { _posRow: posRow, _posColumn: posColumn, _uvRow: uvRow, _uvColumn: uvColumn } = this; + posRow.length = posColumn.length = uvRow.length = uvColumn.length = 0; tileMode === SpriteTileMode.Adaptive - ? this._calculateAdaptiveDividing(sprite, width, height, threshold, posRow, posColumn, uvRowInfo, uvColumnInfo) - : this._calculateContinuousDividing(sprite, width, height, posRow, posColumn, uvRowInfo, uvColumnInfo); + ? this._calculateAdaptiveDividing(sprite, width, height, threshold, posRow, posColumn, uvRow, uvColumn) + : this._calculateContinuousDividing(sprite, width, height, posRow, posColumn, uvRow, uvColumn); // Update renderer's worldMatrix const { x: pivotX, y: pivotY } = renderer.sprite.pivot; const localTransX = renderer.width * pivotX; @@ -60,10 +60,10 @@ export class TiledSpriteAssembler { for (let j = 0; j < columnLength; j++) { const doubleJ = 2 * j; for (let i = 0; i < rowLength; i++) { - const rowForm = uvRowInfo.get(2 * i); - const rowTo = uvRowInfo.get(2 * i + 1); - const colFrom = uvColumnInfo.get(doubleJ); - const colTo = uvColumnInfo.get(doubleJ + 1); + const rowForm = uvRow.get(2 * i); + const rowTo = uvRow.get(2 * i + 1); + const colFrom = uvColumn.get(doubleJ); + const colTo = uvColumn.get(doubleJ + 1); if (isNaN(rowForm) || isNaN(rowTo) || isNaN(colFrom) || isNaN(colTo)) { continue; } @@ -343,8 +343,7 @@ export class TiledSpriteAssembler { uvRow.add(2), uvRow.add(1); } posRow.add(width - fixedR), posRow.add(width - expectWidth * (1 - right)); - // uvRow.add((spriteUV2.x - spriteUV1.x) * (rRepeatCount - countInteger) + spriteUV1.x); - uvRow.add(2); + uvRow.add(2 + rRepeatCount - countInteger); uvRow.add(2), uvRow.add(3); break; default: @@ -372,8 +371,7 @@ export class TiledSpriteAssembler { uvColumn.add(2), uvColumn.add(1); } posColumn.add(height - fixedT), posColumn.add(height - expectHeight * (1 - top)); - // uvColumn.add((spriteUV2.y - spriteUV1.y) * (cRepeatCount - countInteger) + spriteUV1.y); - uvColumn.add(2); + uvRow.add(2 + rRepeatCount - countInteger); uvColumn.add(2), uvColumn.add(3); break; default: diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index bdff7f740f..e04b99a871 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -347,76 +347,70 @@ export class Sprite extends ReferResource { } private _updateUVs(): void { - const { _uvs: uvs, _atlasRotated: atlasRotated } = this; + const { _uvs: uvs, _atlasRotated: atlasRotated, _border: border } = this; const { x: regionLeft, y: regionTop, width: regionW, height: regionH } = this._region; const regionRight = 1 - regionLeft - regionW; const regionBottom = 1 - regionTop - regionH; - const { x: atlasRegionX, y: atlasRegionY, width: atlasRegionW, height: atlasRegionH } = this._atlasRegion; const { x: offsetLeft, y: offsetTop, z: offsetRight, w: offsetBottom } = this._atlasRegionOffset; const realWidth = atlasRegionW / (1 - offsetLeft - offsetRight); const realHeight = atlasRegionH / (1 - offsetTop - offsetBottom); - - const { x: borderLeft, y: borderBottom, z: borderRight, w: borderTop } = this._border; - - // Coordinates of the four boundaries. + // Coordinates of the boundaries. let left: number, top: number, right: number, bottom: number; - let borderL: number, borderT: number, borderR: number, borderB: number; + let borderLeft: number, borderTop: number, borderRight: number, borderBottom: number; if (atlasRotated) { left = Math.max(regionBottom - offsetLeft, 0) * realWidth + atlasRegionX; top = Math.max(regionLeft - offsetTop, 0) * realHeight + atlasRegionY; right = atlasRegionW + atlasRegionX - Math.max(regionTop - offsetRight, 0) * realWidth; bottom = atlasRegionH + atlasRegionY - Math.max(regionRight - offsetBottom, 0) * realHeight; - - borderL = (regionBottom - offsetLeft + borderBottom * regionH) * realWidth + atlasRegionX; - borderT = (regionLeft - offsetTop + borderLeft * regionW) * realHeight + atlasRegionY; - borderR = atlasRegionW + atlasRegionX - (regionTop - offsetRight + borderTop * regionH) * realWidth; - borderB = atlasRegionH + atlasRegionY - (regionRight - offsetBottom + borderRight * regionW) * realHeight; + borderLeft = (regionBottom - offsetLeft + border.y * regionH) * realWidth + atlasRegionX; + borderTop = (regionLeft - offsetTop + border.x * regionW) * realHeight + atlasRegionY; + borderRight = atlasRegionW + atlasRegionX - (regionTop - offsetRight + border.w * regionH) * realWidth; + borderBottom = atlasRegionH + atlasRegionY - (regionRight - offsetBottom + border.z * regionW) * realHeight; } else { left = Math.max(regionLeft - offsetLeft, 0) * realWidth + atlasRegionX; top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; bottom = atlasRegionH + atlasRegionY - Math.max(regionTop - offsetBottom, 0) * realHeight; - - borderL = (regionLeft - offsetLeft + borderLeft * regionW) * realWidth + atlasRegionX; - borderT = (regionBottom - offsetTop + borderTop * regionH) * realHeight + atlasRegionY; - borderR = atlasRegionW + atlasRegionX - (regionRight - offsetRight + borderRight * regionW) * realWidth; - borderB = atlasRegionH + atlasRegionY - (regionTop - offsetBottom + borderBottom * regionH) * realHeight; + borderLeft = (regionLeft - offsetLeft + border.x * regionW) * realWidth + atlasRegionX; + borderTop = (regionBottom - offsetTop + border.w * regionH) * realHeight + atlasRegionY; + borderRight = atlasRegionW + atlasRegionX - (regionRight - offsetRight + border.z * regionW) * realWidth; + borderBottom = atlasRegionH + atlasRegionY - (regionTop - offsetBottom + border.y * regionH) * realHeight; } if (atlasRotated) { uvs[0].set(left, top); - uvs[1].set(left, borderT); - uvs[2].set(left, borderB); + uvs[1].set(left, borderTop); + uvs[2].set(left, borderBottom); uvs[3].set(left, bottom); - uvs[4].set(borderL, top); - uvs[5].set(borderL, borderT); - uvs[6].set(borderL, borderB); - uvs[7].set(borderL, bottom); - uvs[8].set(borderR, top); - uvs[9].set(borderR, borderT); - uvs[10].set(borderR, borderB); - uvs[11].set(borderR, bottom); + uvs[4].set(borderLeft, top); + uvs[5].set(borderLeft, borderTop); + uvs[6].set(borderLeft, borderBottom); + uvs[7].set(borderLeft, bottom); + uvs[8].set(borderRight, top); + uvs[9].set(borderRight, borderTop); + uvs[10].set(borderRight, borderBottom); + uvs[11].set(borderRight, bottom); uvs[12].set(right, top); - uvs[13].set(right, borderT); - uvs[14].set(right, borderB); + uvs[13].set(right, borderTop); + uvs[14].set(right, borderBottom); uvs[15].set(right, bottom); } else { uvs[0].set(left, bottom); - uvs[1].set(borderL, bottom); - uvs[2].set(borderR, bottom); + uvs[1].set(borderLeft, bottom); + uvs[2].set(borderRight, bottom); uvs[3].set(right, bottom); - uvs[4].set(left, borderB); - uvs[5].set(borderL, borderB); - uvs[6].set(borderR, borderB); - uvs[7].set(right, borderB); - uvs[8].set(left, borderT); - uvs[9].set(borderL, borderT); - uvs[10].set(borderR, borderT); - uvs[11].set(right, borderT); + uvs[4].set(left, borderBottom); + uvs[5].set(borderLeft, borderBottom); + uvs[6].set(borderRight, borderBottom); + uvs[7].set(right, borderBottom); + uvs[8].set(left, borderTop); + uvs[9].set(borderLeft, borderTop); + uvs[10].set(borderRight, borderTop); + uvs[11].set(right, borderTop); uvs[12].set(left, top); - uvs[13].set(borderL, top); - uvs[14].set(borderR, top); + uvs[13].set(borderLeft, top); + uvs[14].set(borderRight, top); uvs[15].set(right, top); } this._dirtyUpdateFlag &= ~SpriteUpdateFlags.uvs; From 48f824ca1194743d53214a9e2ee1fe61258f786e Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Mon, 8 Jan 2024 23:03:55 +0800 Subject: [PATCH 5/7] feat: atlas support rotate --- .../src/2d/assembler/TiledSpriteAssembler.ts | 8 +- tests/src/core/Sprite.test.ts | 61 ++++++++++-- tests/src/core/SpriteRenderer.test.ts | 98 ++++++++++--------- 3 files changed, 105 insertions(+), 62 deletions(-) diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 2f81eda944..587bf38957 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -151,7 +151,6 @@ export class TiledSpriteAssembler { const spritePositions = sprite._getPositions(); const { x: left, y: bottom } = spritePositions[0]; const { x: right, y: top } = spritePositions[3]; - const [spriteUV0, spriteUV1, spriteUV2, spriteUV3] = sprite._getUVs(); const { width: expectWidth, height: expectHeight } = sprite; const fixedL = expectWidth * border.x; const fixedR = expectWidth * border.z; @@ -272,7 +271,6 @@ export class TiledSpriteAssembler { const spritePositions = sprite._getPositions(); const { x: left, y: bottom } = spritePositions[0]; const { x: right, y: top } = spritePositions[3]; - const [spriteUV0, spriteUV1, spriteUV2, spriteUV3] = sprite._getUVs(); const { width: expectWidth, height: expectHeight } = sprite; const fixedL = expectWidth * border.x; const fixedR = expectWidth * border.z; @@ -343,8 +341,7 @@ export class TiledSpriteAssembler { uvRow.add(2), uvRow.add(1); } posRow.add(width - fixedR), posRow.add(width - expectWidth * (1 - right)); - uvRow.add(2 + rRepeatCount - countInteger); - uvRow.add(2), uvRow.add(3); + uvRow.add(2 + rRepeatCount - countInteger), uvRow.add(2), uvRow.add(3); break; default: break; @@ -371,8 +368,7 @@ export class TiledSpriteAssembler { uvColumn.add(2), uvColumn.add(1); } posColumn.add(height - fixedT), posColumn.add(height - expectHeight * (1 - top)); - uvRow.add(2 + rRepeatCount - countInteger); - uvColumn.add(2), uvColumn.add(3); + uvColumn.add(2 + rRepeatCount - countInteger), uvColumn.add(2), uvColumn.add(3); break; default: break; diff --git a/tests/src/core/Sprite.test.ts b/tests/src/core/Sprite.test.ts index 7ff97a10f9..ff1d83fff7 100644 --- a/tests/src/core/Sprite.test.ts +++ b/tests/src/core/Sprite.test.ts @@ -1,6 +1,6 @@ -import { Sprite, SpriteRenderer, Texture2D, SpriteMask } from "@galacean/engine-core"; -import { WebGLEngine } from "@galacean/engine-rhi-webgl"; +import { Sprite, SpriteMask, SpriteRenderer, Texture2D } from "@galacean/engine-core"; import { Rect, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; +import { WebGLEngine } from "@galacean/engine-rhi-webgl"; import { expect } from "chai"; describe("Sprite", async () => { @@ -146,24 +146,69 @@ describe("Sprite", async () => { let uvs = sprite._getUVs(); expect(uvs[0]).to.deep.eq(new Vector2(0, 1)); expect(uvs[1]).to.deep.eq(new Vector2(0, 1)); - expect(uvs[2]).to.deep.eq(new Vector2(1, 0)); - expect(uvs[3]).to.deep.eq(new Vector2(1, 0)); + expect(uvs[2]).to.deep.eq(new Vector2(1, 1)); + expect(uvs[3]).to.deep.eq(new Vector2(1, 1)); + + expect(uvs[4]).to.deep.eq(new Vector2(0, 1)); + expect(uvs[5]).to.deep.eq(new Vector2(0, 1)); + expect(uvs[6]).to.deep.eq(new Vector2(1, 1)); + expect(uvs[7]).to.deep.eq(new Vector2(1, 1)); + + expect(uvs[8]).to.deep.eq(new Vector2(0, 0)); + expect(uvs[9]).to.deep.eq(new Vector2(0, 0)); + expect(uvs[10]).to.deep.eq(new Vector2(1, 0)); + expect(uvs[11]).to.deep.eq(new Vector2(1, 0)); + + expect(uvs[12]).to.deep.eq(new Vector2(0, 0)); + expect(uvs[13]).to.deep.eq(new Vector2(0, 0)); + expect(uvs[14]).to.deep.eq(new Vector2(1, 0)); + expect(uvs[15]).to.deep.eq(new Vector2(1, 0)); sprite.region = new Rect(0, 0, 0.5, 0.5); // @ts-ignore uvs = sprite._getUVs(); expect(uvs[0]).to.deep.eq(new Vector2(0, 1)); expect(uvs[1]).to.deep.eq(new Vector2(0, 1)); - expect(uvs[2]).to.deep.eq(new Vector2(0.5, 0.5)); - expect(uvs[3]).to.deep.eq(new Vector2(0.5, 0.5)); + expect(uvs[2]).to.deep.eq(new Vector2(0.5, 1)); + expect(uvs[3]).to.deep.eq(new Vector2(0.5, 1)); + + expect(uvs[4]).to.deep.eq(new Vector2(0, 1)); + expect(uvs[5]).to.deep.eq(new Vector2(0, 1)); + expect(uvs[6]).to.deep.eq(new Vector2(0.5, 1)); + expect(uvs[7]).to.deep.eq(new Vector2(0.5, 1)); + + expect(uvs[8]).to.deep.eq(new Vector2(0, 0.5)); + expect(uvs[9]).to.deep.eq(new Vector2(0, 0.5)); + expect(uvs[10]).to.deep.eq(new Vector2(0.5, 0.5)); + expect(uvs[11]).to.deep.eq(new Vector2(0.5, 0.5)); + + expect(uvs[12]).to.deep.eq(new Vector2(0, 0.5)); + expect(uvs[13]).to.deep.eq(new Vector2(0, 0.5)); + expect(uvs[14]).to.deep.eq(new Vector2(0.5, 0.5)); + expect(uvs[15]).to.deep.eq(new Vector2(0.5, 0.5)); sprite.atlasRegion = new Rect(0, 0, 0.5, 0.5); // @ts-ignore uvs = sprite._getUVs(); expect(uvs[0]).to.deep.eq(new Vector2(0, 0.5)); expect(uvs[1]).to.deep.eq(new Vector2(0, 0.5)); - expect(uvs[2]).to.deep.eq(new Vector2(0.25, 0.25)); - expect(uvs[3]).to.deep.eq(new Vector2(0.25, 0.25)); + expect(uvs[2]).to.deep.eq(new Vector2(0.25, 0.5)); + expect(uvs[3]).to.deep.eq(new Vector2(0.25, 0.5)); + + expect(uvs[4]).to.deep.eq(new Vector2(0, 0.5)); + expect(uvs[5]).to.deep.eq(new Vector2(0, 0.5)); + expect(uvs[6]).to.deep.eq(new Vector2(0.25, 0.5)); + expect(uvs[7]).to.deep.eq(new Vector2(0.25, 0.5)); + + expect(uvs[8]).to.deep.eq(new Vector2(0, 0.25)); + expect(uvs[9]).to.deep.eq(new Vector2(0, 0.25)); + expect(uvs[10]).to.deep.eq(new Vector2(0.25, 0.25)); + expect(uvs[11]).to.deep.eq(new Vector2(0.25, 0.25)); + + expect(uvs[12]).to.deep.eq(new Vector2(0, 0.25)); + expect(uvs[13]).to.deep.eq(new Vector2(0, 0.25)); + expect(uvs[14]).to.deep.eq(new Vector2(0.25, 0.25)); + expect(uvs[15]).to.deep.eq(new Vector2(0.25, 0.25)); }); it("_getBounds", () => { diff --git a/tests/src/core/SpriteRenderer.test.ts b/tests/src/core/SpriteRenderer.test.ts index f3a85f8467..1c4cf7e6d8 100644 --- a/tests/src/core/SpriteRenderer.test.ts +++ b/tests/src/core/SpriteRenderer.test.ts @@ -243,39 +243,39 @@ describe("SpriteRenderer", async () => { spriteRenderer.height = 0.5; // @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, 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[1], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[2], new Vector3(0.25, 0, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[3], new Vector3(0.5, 0, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[4], new Vector3(0, 0.25, 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[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.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[11], new Vector3(0.5, 0.25, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[12], new Vector3(0, 0.5, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[13], new Vector3(0.25, 0.5, 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); + // @ts-ignore + spriteRenderer._assembler.updateUVs(spriteRenderer); 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[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(renderData.uvs[2], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(renderData.uvs[4], new Vector2(0, 0.7))).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[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.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[11], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(renderData.uvs[12], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(renderData.uvs[13], new Vector2(0.3, 0))).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); spriteRenderer.width = 15; @@ -285,36 +285,36 @@ describe("SpriteRenderer", async () => { // @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[1], new Vector3(0.6, 0, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[2], new Vector3(14.4, 0, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[3], new Vector3(15, 0, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[4], new Vector3(0, 0.8999999999999999, 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[6], new Vector3(14.4, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[7], new Vector3(15, 0.8999999999999999, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[8], new Vector3(0, 14.1, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[9], new Vector3(0.6, 14.1, 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[11], new Vector3(15, 14.1, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[12], new Vector3(0, 15, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[13], new Vector3(0.6, 15, 0))).to.eq(true); + expect(Vector3.equals(renderData.positions[14], new Vector3(14.4, 15, 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[1], new Vector2(0.3, 1))).to.eq(true); + expect(Vector2.equals(renderData.uvs[2], new Vector2(0.7, 1))).to.eq(true); + expect(Vector2.equals(renderData.uvs[3], new Vector2(1, 1))).to.eq(true); + expect(Vector2.equals(renderData.uvs[4], new Vector2(0, 0.7))).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[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.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[11], new Vector2(1, 0.3))).to.eq(true); + expect(Vector2.equals(renderData.uvs[12], new Vector2(0, 0))).to.eq(true); + expect(Vector2.equals(renderData.uvs[13], new Vector2(0.3, 0))).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); }); @@ -336,6 +336,7 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); + console.log('renderData.positions', renderData.positions); 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); @@ -416,6 +417,7 @@ describe("SpriteRenderer", async () => { 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); + return; spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore From 1d7fc34c3804b961e21673ffec12661c385564f2 Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Mon, 8 Jan 2024 23:20:30 +0800 Subject: [PATCH 6/7] feat: atlas support rotate --- packages/core/src/2d/assembler/TiledSpriteAssembler.ts | 8 ++++---- tests/src/core/SpriteRenderer.test.ts | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 587bf38957..57fba49a8b 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -341,7 +341,7 @@ export class TiledSpriteAssembler { uvRow.add(2), uvRow.add(1); } posRow.add(width - fixedR), posRow.add(width - expectWidth * (1 - right)); - uvRow.add(2 + rRepeatCount - countInteger), uvRow.add(2), uvRow.add(3); + uvRow.add(1 + rRepeatCount - countInteger), uvRow.add(2), uvRow.add(3); break; default: break; @@ -368,7 +368,7 @@ export class TiledSpriteAssembler { uvColumn.add(2), uvColumn.add(1); } posColumn.add(height - fixedT), posColumn.add(height - expectHeight * (1 - top)); - uvColumn.add(2 + rRepeatCount - countInteger), uvColumn.add(2), uvColumn.add(3); + uvColumn.add(1 + cRepeatCount - countInteger), uvColumn.add(2), uvColumn.add(3); break; default: break; @@ -387,8 +387,8 @@ export class TiledSpriteAssembler { rightTop: Vector2 ): void { leftBottom.copyFrom(uvs[rowFrom + colFrom * 4]); - const rowToInteger = rowTo | 0; - const colToInteger = colTo | 0; + const rowToInteger = rowTo % 1; + const colToInteger = colTo % 1; Vector2.lerp(uvs[Math.floor(rowTo) + colFrom * 4], uvs[Math.ceil(rowTo) + colFrom * 4], rowToInteger, rightBottom); Vector2.lerp(uvs[rowFrom + Math.floor(colTo) * 4], uvs[rowFrom + Math.ceil(colTo) * 4], colToInteger, leftTop); Vector2.add(rightBottom, leftTop, rightTop); diff --git a/tests/src/core/SpriteRenderer.test.ts b/tests/src/core/SpriteRenderer.test.ts index 1c4cf7e6d8..19e82771e1 100644 --- a/tests/src/core/SpriteRenderer.test.ts +++ b/tests/src/core/SpriteRenderer.test.ts @@ -336,7 +336,6 @@ describe("SpriteRenderer", async () => { spriteRenderer._assembler.updatePositions(spriteRenderer); // @ts-ignore spriteRenderer._assembler.updateUVs(spriteRenderer); - console.log('renderData.positions', renderData.positions); 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); @@ -417,7 +416,6 @@ describe("SpriteRenderer", async () => { 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); - return; spriteRenderer.tileMode = SpriteTileMode.Adaptive; // @ts-ignore From ac3d661fee4637cc607692e56eeda5feb54b6853 Mon Sep 17 00:00:00 2001 From: cptbtptpbcptdtptp Date: Tue, 9 Jan 2024 17:04:01 +0800 Subject: [PATCH 7/7] feat: atlas support rotate --- .../src/2d/assembler/TiledSpriteAssembler.ts | 108 +++++++----------- packages/core/src/2d/sprite/Sprite.ts | 79 ++++--------- 2 files changed, 63 insertions(+), 124 deletions(-) diff --git a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts index 57fba49a8b..9dde2e1349 100644 --- a/packages/core/src/2d/assembler/TiledSpriteAssembler.ts +++ b/packages/core/src/2d/assembler/TiledSpriteAssembler.ts @@ -36,7 +36,7 @@ export class TiledSpriteAssembler { const { x: pivotX, y: pivotY } = renderer.sprite.pivot; const localTransX = renderer.width * pivotX; const localTransY = renderer.height * pivotY; - const spriteUVs = sprite._getUVs(); + const spUVs = sprite._getUVs(); // Renderer's worldMatrix const { _worldMatrix: worldMatrix } = TiledSpriteAssembler; const { elements: wE } = worldMatrix; @@ -60,11 +60,11 @@ export class TiledSpriteAssembler { for (let j = 0; j < columnLength; j++) { const doubleJ = 2 * j; for (let i = 0; i < rowLength; i++) { - const rowForm = uvRow.get(2 * i); - const rowTo = uvRow.get(2 * i + 1); - const colFrom = uvColumn.get(doubleJ); - const colTo = uvColumn.get(doubleJ + 1); - if (isNaN(rowForm) || isNaN(rowTo) || isNaN(colFrom) || isNaN(colTo)) { + const rFrom = uvRow.get(2 * i); + const rTo = uvRow.get(2 * i + 1); + const cFrom = uvColumn.get(doubleJ); + const cTo = uvColumn.get(doubleJ + 1); + if (isNaN(rFrom) || isNaN(rTo) || isNaN(cFrom) || isNaN(cTo)) { continue; } triangles[trianglesOffset++] = count; @@ -73,56 +73,50 @@ export class TiledSpriteAssembler { triangles[trianglesOffset++] = count + 2; triangles[trianglesOffset++] = count + 1; triangles[trianglesOffset++] = count + 3; - const l = posRow.get(i); - const b = posColumn.get(j); - const r = posRow.get(i + 1); - const t = posColumn.get(j + 1); - TiledSpriteAssembler._getCorners( - spriteUVs, - rowForm, - rowTo, - colFrom, - colTo, - (uvs[count] ||= new Vector2()), - (uvs[count + 1] ||= new Vector2()), - (uvs[count + 2] ||= new Vector2()), - (uvs[count + 3] ||= new Vector2()) - ); - 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); - } + // left and bottom + const LBPos = (positions[count] ||= new Vector3()); + const LBUV = (uvs[count] ||= new Vector2()); count++; - // right and bottom - 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); - } + const RBPos = (positions[count] ||= new Vector3()); + const RBUV = (uvs[count] ||= new Vector2()); count++; - // left and top - 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); - } + const LTPos = (positions[count] ||= new Vector3()); + const LTUV = (uvs[count] ||= new Vector2()); count++; - // right and top - pos = positions[count]; - if (pos) { - pos.set(wE0 * r + wE4 * t + wE12, wE1 * r + wE5 * t + wE13, wE2 * r + wE6 * t + wE14); + const RTPos = (positions[count] ||= new Vector3()); + const RTUV = (uvs[count] ||= new Vector2()); + count++; + + // update position + const l = posRow.get(i); + const b = posColumn.get(j); + const r = posRow.get(i + 1); + const t = posColumn.get(j + 1); + LBPos.set(wE0 * l + wE4 * b + wE12, wE1 * l + wE5 * b + wE13, wE2 * l + wE6 * b + wE14); + RBPos.set(wE0 * r + wE4 * b + wE12, wE1 * r + wE5 * b + wE13, wE2 * r + wE6 * b + wE14); + LTPos.set(wE0 * l + wE4 * t + wE12, wE1 * l + wE5 * t + wE13, wE2 * l + wE6 * t + wE14); + RTPos.set(wE0 * r + wE4 * t + wE12, wE1 * r + wE5 * t + wE13, wE2 * r + wE6 * t + wE14); + + // update uv + LBUV.copyFrom(spUVs[rFrom + cFrom * 4]); + const rowToInteger = rTo % 1; + const colToInteger = cTo % 1; + if (rowToInteger) { + Vector2.lerp(spUVs[Math.floor(rTo) + cFrom * 4], spUVs[Math.ceil(rTo) + cFrom * 4], rowToInteger, RBUV); } else { - positions[count] = new Vector3(wE0 * r + wE4 * t + wE12, wE1 * r + wE5 * t + wE13, wE2 * r + wE6 * t + wE14); + RBUV.copyFrom(spUVs[rTo + cFrom * 4]); } - count++; + if (colToInteger) { + Vector2.lerp(spUVs[rFrom + Math.floor(cTo) * 4], spUVs[rFrom + Math.ceil(cTo) * 4], colToInteger, LTUV); + } else { + LTUV.copyFrom(spUVs[rFrom + cTo * 4]); + } + Vector2.add(RBUV, LTUV, RTUV); + RTUV.subtract(LBUV); } } @@ -374,26 +368,6 @@ export class TiledSpriteAssembler { break; } } - - private static _getCorners( - uvs: Vector2[], - rowFrom: number, - rowTo: number, - colFrom: number, - colTo: number, - leftBottom: Vector2, - rightBottom: Vector2, - leftTop: Vector2, - rightTop: Vector2 - ): void { - leftBottom.copyFrom(uvs[rowFrom + colFrom * 4]); - const rowToInteger = rowTo % 1; - const colToInteger = colTo % 1; - Vector2.lerp(uvs[Math.floor(rowTo) + colFrom * 4], uvs[Math.ceil(rowTo) + colFrom * 4], rowToInteger, rightBottom); - Vector2.lerp(uvs[rowFrom + Math.floor(colTo) * 4], uvs[rowFrom + Math.ceil(colTo) * 4], colToInteger, leftTop); - Vector2.add(rightBottom, leftTop, rightTop); - rightTop.subtract(leftBottom); - } } enum TiledType { diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index e04b99a871..5604e29adf 100644 --- a/packages/core/src/2d/sprite/Sprite.ts +++ b/packages/core/src/2d/sprite/Sprite.ts @@ -19,23 +19,12 @@ export class Sprite extends ReferResource { private _customHeight: number = undefined; private _positions: Vector2[] = [new Vector2(), new Vector2(), new Vector2(), new Vector2()]; + // prettier-ignore private _uvs: Vector2[] = [ - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2(), - new Vector2() + new Vector2(), new Vector2(), new Vector2(), new Vector2(), + new Vector2(), new Vector2(), new Vector2(), new Vector2(), + new Vector2(), new Vector2(), new Vector2(), new Vector2(), + new Vector2(), new Vector2(), new Vector2(), new Vector2(), ]; private _bounds: BoundingBox = new BoundingBox(); @@ -357,61 +346,37 @@ export class Sprite extends ReferResource { const realHeight = atlasRegionH / (1 - offsetTop - offsetBottom); // Coordinates of the boundaries. let left: number, top: number, right: number, bottom: number; - let borderLeft: number, borderTop: number, borderRight: number, borderBottom: number; + let bLeft: number, bTop: number, bRight: number, bBottom: number; if (atlasRotated) { left = Math.max(regionBottom - offsetLeft, 0) * realWidth + atlasRegionX; top = Math.max(regionLeft - offsetTop, 0) * realHeight + atlasRegionY; right = atlasRegionW + atlasRegionX - Math.max(regionTop - offsetRight, 0) * realWidth; bottom = atlasRegionH + atlasRegionY - Math.max(regionRight - offsetBottom, 0) * realHeight; - borderLeft = (regionBottom - offsetLeft + border.y * regionH) * realWidth + atlasRegionX; - borderTop = (regionLeft - offsetTop + border.x * regionW) * realHeight + atlasRegionY; - borderRight = atlasRegionW + atlasRegionX - (regionTop - offsetRight + border.w * regionH) * realWidth; - borderBottom = atlasRegionH + atlasRegionY - (regionRight - offsetBottom + border.z * regionW) * realHeight; + bLeft = (regionBottom - offsetLeft + border.y * regionH) * realWidth + atlasRegionX; + bTop = (regionLeft - offsetTop + border.x * regionW) * realHeight + atlasRegionY; + bRight = atlasRegionW + atlasRegionX - (regionTop - offsetRight + border.w * regionH) * realWidth; + bBottom = atlasRegionH + atlasRegionY - (regionRight - offsetBottom + border.z * regionW) * realHeight; } else { left = Math.max(regionLeft - offsetLeft, 0) * realWidth + atlasRegionX; top = Math.max(regionBottom - offsetTop, 0) * realHeight + atlasRegionY; right = atlasRegionW + atlasRegionX - Math.max(regionRight - offsetRight, 0) * realWidth; bottom = atlasRegionH + atlasRegionY - Math.max(regionTop - offsetBottom, 0) * realHeight; - borderLeft = (regionLeft - offsetLeft + border.x * regionW) * realWidth + atlasRegionX; - borderTop = (regionBottom - offsetTop + border.w * regionH) * realHeight + atlasRegionY; - borderRight = atlasRegionW + atlasRegionX - (regionRight - offsetRight + border.z * regionW) * realWidth; - borderBottom = atlasRegionH + atlasRegionY - (regionTop - offsetBottom + border.y * regionH) * realHeight; + bLeft = (regionLeft - offsetLeft + border.x * regionW) * realWidth + atlasRegionX; + bTop = (regionBottom - offsetTop + border.w * regionH) * realHeight + atlasRegionY; + bRight = atlasRegionW + atlasRegionX - (regionRight - offsetRight + border.z * regionW) * realWidth; + bBottom = atlasRegionH + atlasRegionY - (regionTop - offsetBottom + border.y * regionH) * realHeight; } if (atlasRotated) { - uvs[0].set(left, top); - uvs[1].set(left, borderTop); - uvs[2].set(left, borderBottom); - uvs[3].set(left, bottom); - uvs[4].set(borderLeft, top); - uvs[5].set(borderLeft, borderTop); - uvs[6].set(borderLeft, borderBottom); - uvs[7].set(borderLeft, bottom); - uvs[8].set(borderRight, top); - uvs[9].set(borderRight, borderTop); - uvs[10].set(borderRight, borderBottom); - uvs[11].set(borderRight, bottom); - uvs[12].set(right, top); - uvs[13].set(right, borderTop); - uvs[14].set(right, borderBottom); - uvs[15].set(right, bottom); + uvs[0].set(left, top), uvs[1].set(left, bTop), uvs[2].set(left, bBottom), uvs[3].set(left, bottom); + uvs[4].set(bLeft, top), uvs[5].set(bLeft, bTop), uvs[6].set(bLeft, bBottom), uvs[7].set(bLeft, bottom); + uvs[8].set(bRight, top), uvs[9].set(bRight, bTop), uvs[10].set(bRight, bBottom), uvs[11].set(bRight, bottom); + uvs[12].set(right, top), uvs[13].set(right, bTop), uvs[14].set(right, bBottom), uvs[15].set(right, bottom); } else { - uvs[0].set(left, bottom); - uvs[1].set(borderLeft, bottom); - uvs[2].set(borderRight, bottom); - uvs[3].set(right, bottom); - uvs[4].set(left, borderBottom); - uvs[5].set(borderLeft, borderBottom); - uvs[6].set(borderRight, borderBottom); - uvs[7].set(right, borderBottom); - uvs[8].set(left, borderTop); - uvs[9].set(borderLeft, borderTop); - uvs[10].set(borderRight, borderTop); - uvs[11].set(right, borderTop); - uvs[12].set(left, top); - uvs[13].set(borderLeft, top); - uvs[14].set(borderRight, top); - uvs[15].set(right, top); + uvs[0].set(left, bottom), uvs[1].set(bLeft, bottom), uvs[2].set(bRight, bottom), uvs[3].set(right, bottom); + uvs[4].set(left, bBottom), uvs[5].set(bLeft, bBottom), uvs[6].set(bRight, bBottom), uvs[7].set(right, bBottom); + uvs[8].set(left, bTop), uvs[9].set(bLeft, bTop), uvs[10].set(bRight, bTop), uvs[11].set(right, bTop); + uvs[12].set(left, top), uvs[13].set(bLeft, top), uvs[14].set(bRight, top), uvs[15].set(right, top); } this._dirtyUpdateFlag &= ~SpriteUpdateFlags.uvs; }