diff --git a/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts b/packages/core/src/2d/assembler/SimpleSpriteAssembler.ts index e135e77d9a..be4d90b380 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[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..9dde2e1349 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 @@ -37,6 +36,7 @@ export class TiledSpriteAssembler { const { x: pivotX, y: pivotY } = renderer.sprite.pivot; const localTransX = renderer.width * pivotX; const localTransY = renderer.height * pivotY; + 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 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 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,50 +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); // 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); - } + const LBPos = (positions[count] ||= new Vector3()); + const LBUV = (uvs[count] ||= new Vector2()); 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); - } 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 - 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); - } + const LTPos = (positions[count] ||= new Vector3()); + const LTUV = (uvs[count] ||= new Vector2()); 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); + 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); } } @@ -145,7 +145,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; @@ -192,8 +191,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 +202,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 +229,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; @@ -268,7 +265,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; @@ -312,8 +308,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 +319,23 @@ 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(1 + rRepeatCount - countInteger), uvRow.add(2), uvRow.add(3); break; default: break; @@ -352,25 +346,23 @@ 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(1 + cRepeatCount - countInteger), uvColumn.add(2), uvColumn.add(3); break; default: break; diff --git a/packages/core/src/2d/sprite/Sprite.ts b/packages/core/src/2d/sprite/Sprite.ts index 9b2257227e..5604e29adf 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,7 +19,13 @@ 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()]; + // 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(), + ]; private _bounds: BoundingBox = new BoundingBox(); private _texture: Texture2D = null; @@ -176,7 +182,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; @@ -287,16 +293,14 @@ export class Sprite extends ReferResource { private _calDefaultSize(): void { if (this._texture) { - const { _texture, _atlasRegion, _atlasRegionOffset, _region } = this; - const pixelsPerUnitReciprocal = 1.0 / Engine._pixelsPerUnit; + const { _texture, _atlasRegion, _atlasRegionOffset, _region, _atlasRotated } = this; + const ppuReciprocal = 1.0 / Engine._pixelsPerUnit; + const originWidth = _texture.width * (_atlasRotated ? _atlasRegion.height : _atlasRegion.width); + const originHeight = _texture.height * (_atlasRotated ? _atlasRegion.width : _atlasRegion.height); this._automaticWidth = - ((_texture.width * _atlasRegion.width) / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * - _region.width * - pixelsPerUnitReciprocal; + (originWidth / (1 - _atlasRegionOffset.x - _atlasRegionOffset.z)) * _region.width * ppuReciprocal; this._automaticHeight = - ((_texture.height * _atlasRegion.height) / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * - _region.height * - pixelsPerUnitReciprocal; + (originHeight / (1 - _atlasRegionOffset.y - _atlasRegionOffset.w)) * _region.height * ppuReciprocal; } else { this._automaticWidth = this._automaticHeight = 0; } @@ -332,34 +336,48 @@ 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, _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 } = 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; - // 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); + // Coordinates of the boundaries. + let left: number, top: number, right: number, bottom: 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; + 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; + 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, 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(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; } diff --git a/packages/loader/src/SpriteAtlasLoader.ts b/packages/loader/src/SpriteAtlasLoader.ts index 7359fbd25f..d7523ccfe1 100644 --- a/packages/loader/src/SpriteAtlasLoader.ts +++ b/packages/loader/src/SpriteAtlasLoader.ts @@ -101,7 +101,7 @@ class SpriteAtlasLoader extends Loader { 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 = config.atlasRotated ?? false; } isNaN(width) || (sprite.width = width); isNaN(height) || (sprite.height = height); 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..19e82771e1 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); });