import { EffectAsset, Material, Sprite, Vec4 } from 'cc'; /** * 圆角 Sprite 材质工具。 * * 基于 rounded-sprite.effect 的 SDF alpha 裁剪实现,直接作用于 Sprite 的自定义材质。 * 每个 Sprite 都会获得独立 Material,避免 roundedParams / uvRect 互相覆盖。 */ let cachedTemplate: Material | null = null; let cachedEffectRef: EffectAsset | null = null; const getOrCreateTemplate = (effectAsset: EffectAsset): Material => { if (cachedTemplate && cachedEffectRef === effectAsset) { return cachedTemplate; } const template = new Material(); template.initialize({ effectAsset, defines: { USE_TEXTURE: true }, }); cachedTemplate = template; cachedEffectRef = effectAsset; return template; }; const extractUvRect = (sprite: Sprite): Vec4 => { const spriteFrame = sprite.spriteFrame; if (!spriteFrame) { return new Vec4(0, 0, 1, 1); } const uv = spriteFrame.uv; if (!uv || uv.length < 8) { return new Vec4(0, 0, 1, 1); } const u0 = uv[0]; const v0 = uv[1]; const u1 = uv[2]; const v1 = uv[3]; const u2 = uv[4]; const v2 = uv[5]; const u3 = uv[6]; const v3 = uv[7]; const minU = Math.min(u0, u1, u2, u3); const maxU = Math.max(u0, u1, u2, u3); const minV = Math.min(v0, v1, v2, v3); const maxV = Math.max(v0, v1, v2, v3); const rangeU = maxU - minU; const rangeV = maxV - minV; if (rangeU <= 0 || rangeV <= 0) { return new Vec4(0, 0, 1, 1); } return new Vec4(minU, minV, rangeU, rangeV); }; export const applyRoundedCorner = ( sprite: Sprite, effectAsset: EffectAsset, width: number, height: number, cornerRadius = 0.1, grayscale = false, ): void => { if (!sprite || !sprite.isValid) { console.warn('[roundedMaterial] Invalid sprite, skipping'); return; } if (!effectAsset) { console.warn('[roundedMaterial] EffectAsset is null, skipping'); return; } const template = getOrCreateTemplate(effectAsset); const materialInstance = new Material(); const defines: Record = { USE_TEXTURE: true }; if (grayscale) { defines.IS_GRAY = true; } materialInstance.initialize({ effectAsset, defines, }); const params = new Vec4(cornerRadius, 0, width, height); materialInstance.setProperty('roundedParams', params); materialInstance.setProperty('uvRect', extractUvRect(sprite)); sprite.customMaterial = materialInstance; };