From 1ae57df4a8381ee44a5942b8677b25804ed491c8 Mon Sep 17 00:00:00 2001 From: johanzhu Date: Tue, 19 Nov 2024 17:34:20 +0800 Subject: [PATCH 1/4] feat: support pma --- example/main.ts | 1 + src/SpineAnimationRenderer.ts | 6 ++++++ src/SpineGenerator.ts | 29 ++++++++++++++++------------- src/util/BlendMode.ts | 6 +++--- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/example/main.ts b/example/main.ts index d72a1f5..3870b12 100644 --- a/example/main.ts +++ b/example/main.ts @@ -182,6 +182,7 @@ async function loadSpine(root: Entity, engine: Engine, resource) { spineEntity.transform.setPosition(-25 + Math.random() * 50, -250, 0); const spineAnimation = spineEntity.addComponent(SpineAnimationRenderer); if (scene === 'physic') { + spineAnimation.premultipliedAlpha = true; spineEntity.transform.setScale(0.5, 0.5, 0.5); } spineAnimation.resource = spineResource; diff --git a/src/SpineAnimationRenderer.ts b/src/SpineAnimationRenderer.ts index 47757f0..2e854ce 100644 --- a/src/SpineAnimationRenderer.ts +++ b/src/SpineAnimationRenderer.ts @@ -60,6 +60,12 @@ export class SpineAnimationRenderer extends Renderer { */ @assignmentClone zSpacing = 0.01; + + /** + * Whether to premultiplied alpha for texture. + */ + @assignmentClone + premultipliedAlpha = false; /** * Default state for spine animation. diff --git a/src/SpineGenerator.ts b/src/SpineGenerator.ts index bf37ddf..4f09f08 100644 --- a/src/SpineGenerator.ts +++ b/src/SpineGenerator.ts @@ -80,6 +80,7 @@ export class SpineGenerator { _vertexCount, _subPrimitives, zSpacing, + premultipliedAlpha, } = renderer; let { tempVerts, @@ -171,15 +172,17 @@ export class SpineGenerator { let skeleton = slot.bone.skeleton; let skeletonColor = skeleton.color; let slotColor = slot.color; - let alpha = skeletonColor.a * slotColor.a * attachmentColor.a; - let color = SpineGenerator.tempColor; + let finalColor = SpineGenerator.tempColor; let dark = SpineGenerator.tempDark; - color.set( - skeletonColor.r * slotColor.r * attachmentColor.r, - skeletonColor.g * slotColor.g * attachmentColor.g, - skeletonColor.b * slotColor.b * attachmentColor.b, - alpha, - ); + finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r; + finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g; + finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b; + finalColor.a = skeletonColor.a * slotColor.a * attachmentColor.a; + if (premultipliedAlpha) { + finalColor.r *= finalColor.a; + finalColor.g *= finalColor.a; + finalColor.b *= finalColor.a; + } if (isClipping) { _clipper.clipTriangles( @@ -187,7 +190,7 @@ export class SpineGenerator { triangles, triangles.length, uvs, - color, + finalColor, dark, false, ); @@ -197,7 +200,7 @@ export class SpineGenerator { finalIndicesLength = finalIndices.length; } else { let verts = tempVerts; - const { r, g, b, a } = color; + const { r, g, b, a } = finalColor; for ( let v = 2, u = 0, n = numFloats; v < n; @@ -345,7 +348,7 @@ export class SpineGenerator { const key = `${subTexture.instanceId}_${blendMode}`; let material = SpineAnimationRenderer._materialCache.get(key); if (!material) { - material = this._createMaterialForTexture(subTexture, engine, blendMode); + material = this._createMaterialForTexture(subTexture, engine, blendMode, premultipliedAlpha); SpineAnimationRenderer._materialCache.set(key, material); } renderer.setMaterial(i, material); @@ -369,10 +372,10 @@ export class SpineGenerator { this._separateSlotTextureMap.set(slotName, texture); } - private _createMaterialForTexture(texture: Texture2D, engine: Engine, blendMode: BlendMode): Material { + private _createMaterialForTexture(texture: Texture2D, engine: Engine, blendMode: BlendMode, premultipliedAlpha: boolean): Material { const material = SpineAnimationRenderer._getDefaultMaterial(engine); material.shaderData.setTexture("material_SpineTexture", texture); - setBlendMode(material, blendMode); + setBlendMode(material, blendMode, premultipliedAlpha); return material; } diff --git a/src/util/BlendMode.ts b/src/util/BlendMode.ts index ca359cf..784c191 100644 --- a/src/util/BlendMode.ts +++ b/src/util/BlendMode.ts @@ -5,11 +5,11 @@ import { BlendFactor, BlendOperation, Material } from "@galacean/engine"; const { SourceAlpha, One, DestinationColor, Zero, OneMinusSourceColor, OneMinusSourceAlpha } = BlendFactor; const { Add } = BlendOperation; -export function setBlendMode(material: Material, blendMode: BlendMode) { +export function setBlendMode(material: Material, blendMode: BlendMode, premultipliedAlpha: boolean) { const target = material.renderState.blendState.targetBlendState; switch (blendMode) { case BlendMode.Additive: - target.sourceColorBlendFactor = SourceAlpha; + target.sourceColorBlendFactor = premultipliedAlpha ? One : SourceAlpha; target.destinationColorBlendFactor = One; target.sourceAlphaBlendFactor = One; target.destinationAlphaBlendFactor = One; @@ -30,7 +30,7 @@ export function setBlendMode(material: Material, blendMode: BlendMode) { target.colorBlendOperation = target.alphaBlendOperation = Add; break; default: // Normal blend default - target.sourceColorBlendFactor = SourceAlpha; + target.sourceColorBlendFactor = premultipliedAlpha ? One : SourceAlpha; target.destinationColorBlendFactor = OneMinusSourceAlpha; target.sourceAlphaBlendFactor = One; target.destinationAlphaBlendFactor = OneMinusSourceAlpha; From 11d8e607a73ed0d4023859df9efb28dbec9fbe6a Mon Sep 17 00:00:00 2001 From: johanzhu Date: Wed, 27 Nov 2024 10:23:52 +0800 Subject: [PATCH 2/4] feat: fix alpha cache --- src/SpineGenerator.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/SpineGenerator.ts b/src/SpineGenerator.ts index 4f09f08..5fe3e28 100644 --- a/src/SpineGenerator.ts +++ b/src/SpineGenerator.ts @@ -177,11 +177,12 @@ export class SpineGenerator { finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r; finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g; finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b; - finalColor.a = skeletonColor.a * slotColor.a * attachmentColor.a; + const finalAlpha = skeletonColor.a * slotColor.a * attachmentColor.a; + finalColor.a = finalAlpha; if (premultipliedAlpha) { - finalColor.r *= finalColor.a; - finalColor.g *= finalColor.a; - finalColor.b *= finalColor.a; + finalColor.r *= finalAlpha; + finalColor.g *= finalAlpha; + finalColor.b *= finalAlpha; } if (isClipping) { From df88ffa4490f8e0be97cd2e942a45f12e41da436 Mon Sep 17 00:00:00 2001 From: johanzhu Date: Tue, 3 Dec 2024 15:44:37 +0800 Subject: [PATCH 3/4] feat: fix pma note --- src/SpineAnimationRenderer.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SpineAnimationRenderer.ts b/src/SpineAnimationRenderer.ts index 2e854ce..328ddd7 100644 --- a/src/SpineAnimationRenderer.ts +++ b/src/SpineAnimationRenderer.ts @@ -62,7 +62,9 @@ export class SpineAnimationRenderer extends Renderer { zSpacing = 0.01; /** - * Whether to premultiplied alpha for texture. + * Whether to use premultiplied alpha mode for rendering. + * When enabled, vertex color values are multiplied by the alpha channel. + * @remarks If this option is enabled, the Spine editor must export textures with "Premultiply Alpha" checked. */ @assignmentClone premultipliedAlpha = false; From 008512d15bed9756cd59bdff9966d4a62746ba8d Mon Sep 17 00:00:00 2001 From: johanzhu Date: Tue, 3 Dec 2024 16:00:29 +0800 Subject: [PATCH 4/4] feat: opt code --- src/SpineAnimationRenderer.ts | 31 +++++++++++----------- src/SpineGenerator.ts | 49 +++++++++++++++++------------------ 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/SpineAnimationRenderer.ts b/src/SpineAnimationRenderer.ts index 328ddd7..6df99c8 100644 --- a/src/SpineAnimationRenderer.ts +++ b/src/SpineAnimationRenderer.ts @@ -1,25 +1,25 @@ -import { Skeleton, AnimationState, Physics, TrackEntry, AnimationStateData } from "@esotericsoftware/spine-core"; -import { SpineGenerator } from "./SpineGenerator"; +import { AnimationState, AnimationStateData, Physics, Skeleton, TrackEntry } from "@esotericsoftware/spine-core"; import { + assignmentClone, + BoundingBox, Buffer, - Renderer, + BufferBindFlag, + BufferUsage, + deepClone, + Engine, Entity, ignoreClone, + IndexBufferBinding, + IndexFormat, Material, - Engine, - BoundingBox, Primitive, + Renderer, SubPrimitive, - deepClone, + VertexBufferBinding, VertexElement, VertexElementFormat, - BufferBindFlag, - BufferUsage, - VertexBufferBinding, - IndexBufferBinding, - IndexFormat, - assignmentClone, } from "@galacean/engine"; +import { SpineGenerator } from "./SpineGenerator"; import { SpineMaterial } from "./SpineMaterial"; import { SpineResource } from "./loader/SpineResource"; import { getBlendMode } from "./util/BlendMode"; @@ -64,11 +64,12 @@ export class SpineAnimationRenderer extends Renderer { /** * Whether to use premultiplied alpha mode for rendering. * When enabled, vertex color values are multiplied by the alpha channel. - * @remarks If this option is enabled, the Spine editor must export textures with "Premultiply Alpha" checked. + * @remarks + If this option is enabled, the Spine editor must export textures with "Premultiply Alpha" checked. */ @assignmentClone premultipliedAlpha = false; - + /** * Default state for spine animation. * Contains the default animation name to be played, whether this animation should loop, the default skin name. @@ -463,5 +464,5 @@ export class SpineAnimationDefaultConfig { * The name of the default skin @defaultValue `default` */ public skinName: string = "default" - ) {} + ) { } } diff --git a/src/SpineGenerator.ts b/src/SpineGenerator.ts index 5fe3e28..a894655 100644 --- a/src/SpineGenerator.ts +++ b/src/SpineGenerator.ts @@ -1,30 +1,27 @@ import { - Texture2D, - SubPrimitive, - Vector3, - Material, - Engine, - BoundingBox, -} from "@galacean/engine"; -import { - Skeleton, - SkeletonClipping, - RegionAttachment, - MeshAttachment, - ClippingAttachment, ArrayLike, - Color, BlendMode, - SkeletonData, - Skin, + ClippingAttachment, + Color, + MeshAttachment, NumberArrayLike, - Attachment, + RegionAttachment, + Skeleton, + SkeletonClipping } from "@esotericsoftware/spine-core"; +import { + BoundingBox, + Engine, + Material, + SubPrimitive, + Texture2D, + Vector3, +} from "@galacean/engine"; import { SpineAnimationRenderer } from "./SpineAnimationRenderer"; import { AdaptiveTexture } from "./loader/LoaderUtils"; -import { ReturnablePool } from "./util/ReturnablePool"; -import { ClearablePool } from "./util/ClearablePool"; import { setBlendMode } from "./util/BlendMode"; +import { ClearablePool } from "./util/ClearablePool"; +import { ReturnablePool } from "./util/ReturnablePool"; class SubRenderItem { subPrimitive: SubPrimitive; @@ -169,16 +166,17 @@ export class SpineGenerator { let finalIndices: ArrayLike; let finalIndicesLength: number; - let skeleton = slot.bone.skeleton; - let skeletonColor = skeleton.color; - let slotColor = slot.color; - let finalColor = SpineGenerator.tempColor; - let dark = SpineGenerator.tempDark; + const skeleton = slot.bone.skeleton; + const skeletonColor = skeleton.color; + const slotColor = slot.color; + const finalColor = SpineGenerator.tempColor; + const finalAlpha = skeletonColor.a * slotColor.a * attachmentColor.a; + finalColor.r = skeletonColor.r * slotColor.r * attachmentColor.r; finalColor.g = skeletonColor.g * slotColor.g * attachmentColor.g; finalColor.b = skeletonColor.b * slotColor.b * attachmentColor.b; - const finalAlpha = skeletonColor.a * slotColor.a * attachmentColor.a; finalColor.a = finalAlpha; + if (premultipliedAlpha) { finalColor.r *= finalAlpha; finalColor.g *= finalAlpha; @@ -186,6 +184,7 @@ export class SpineGenerator { } if (isClipping) { + const dark = SpineGenerator.tempDark; _clipper.clipTriangles( tempVerts, triangles,