feat: 适配关卡内图片的圆角
This commit is contained in:
99
assets/scripts/utils/roundedMaterial.utils.ts
Normal file
99
assets/scripts/utils/roundedMaterial.utils.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
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<string, boolean> = { 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;
|
||||
};
|
||||
9
assets/scripts/utils/roundedMaterial.utils.ts.meta
Normal file
9
assets/scripts/utils/roundedMaterial.utils.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "216272d4-0b46-425b-be95-28e46f1417f4",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
Reference in New Issue
Block a user