feat: 适配关卡内图片的圆角

This commit is contained in:
richarjiang
2026-05-03 22:28:22 +08:00
parent 7249df8c22
commit c04bde38a3
13 changed files with 346 additions and 41 deletions

View File

@@ -0,0 +1,140 @@
// Rounded Corner Sprite Effect
// 用于实现圆角矩形裁剪效果,性能优于 Mask 方案
CCEffect %{
techniques:
- passes:
- vert: sprite-vs:vert
frag: sprite-fs:frag
depthStencilState:
depthTest: false
depthWrite: false
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendSrcAlpha: src_alpha
blendDstAlpha: one_minus_src_alpha
rasterizerState:
cullMode: none
properties:
alphaThreshold: { value: 0.5 }
# 圆角参数: x=圆角半径比例(0-0.5), y=预留, z=节点宽度, w=节点高度
roundedParams: { value: [0.08, 0.0, 347.0, 200.0] }
# UV 区域: x=minU, y=minV, z=rangeU, w=rangeV (用于裁剪后的 SpriteFrame 归一化)
uvRect: { value: [0.0, 0.0, 1.0, 1.0] }
}%
CCProgram sprite-vs %{
precision highp float;
#include <builtin/uniforms/cc-global>
#if USE_LOCAL
#include <builtin/uniforms/cc-local>
#endif
#if SAMPLE_FROM_RT
#include <common/common-define>
#endif
in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;
out vec4 color;
out vec2 uv0;
vec4 vert() {
vec4 pos = vec4(a_position, 1);
#if USE_LOCAL
pos = cc_matWorld * pos;
#endif
#if USE_PIXEL_ALIGNMENT
pos = cc_matView * pos;
pos.xyz = floor(pos.xyz);
pos = cc_matProj * pos;
#else
pos = cc_matViewProj * pos;
#endif
uv0 = a_texCoord;
#if SAMPLE_FROM_RT
CC_HANDLE_RT_SAMPLE_FLIP(uv0);
#endif
color = a_color;
return pos;
}
}%
CCProgram sprite-fs %{
precision highp float;
#include <builtin/internal/embedded-alpha>
#include <builtin/internal/alpha-test>
in vec4 color;
in vec2 uv0;
// roundedParams: x=圆角半径比例, y=预留, z=节点宽度, w=节点高度
// uvRect: x=minU, y=minV, z=rangeU, w=rangeV (裁剪后的 SpriteFrame UV 归一化)
uniform Custom {
vec4 roundedParams;
vec4 uvRect;
};
#if USE_TEXTURE
#pragma builtin(local)
layout(set = 2, binding = 12) uniform sampler2D cc_spriteTexture;
#endif
// 计算点到圆角矩形边界的有符号距离
float roundedBoxSDF(vec2 centerPos, vec2 halfSize, float radius) {
vec2 q = abs(centerPos) - halfSize + radius;
return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - radius;
}
vec4 frag() {
vec4 o = vec4(1, 1, 1, 1);
#if USE_TEXTURE
o *= CCSampleWithAlphaSeparated(cc_spriteTexture, uv0);
#endif
o *= color;
// 解析参数
float cornerRadius = roundedParams.x;
vec2 nodeSize = vec2(roundedParams.z, roundedParams.w);
// 将实际 UV 归一化到 0→1 范围(兼容裁剪后的 SpriteFrame
// uvRect: (minU, minV, rangeU, rangeV)
vec2 normalizedUV = (uv0 - uvRect.xy) / uvRect.zw;
// 将归一化 UV 转换为以中心为原点的坐标系
vec2 centerUV = normalizedUV - 0.5;
// 计算实际的圆角半径(基于短边)
float minSize = min(nodeSize.x, nodeSize.y);
float radius = cornerRadius * minSize;
// 将 UV 坐标转换为像素坐标
vec2 pixelPos = centerUV * nodeSize;
vec2 halfSize = nodeSize * 0.5;
// 计算 SDF 距离
float dist = roundedBoxSDF(pixelPos, halfSize, radius);
// 使用平滑的抗锯齿边缘
float smoothEdge = 1.0 - smoothstep(-1.0, 1.0, dist);
o.a *= smoothEdge;
// 灰度转换(与 Cocos 内置 sprite shader 一致的 luminance 权重)
#if USE_GRAY_SCALE
float gray = dot(o.rgb, vec3(0.2126, 0.7152, 0.0722));
o.rgb = vec3(gray);
#endif
ALPHA_TEST(o);
return o;
}
}%

View File

@@ -0,0 +1,11 @@
{
"ver": "1.7.1",
"importer": "effect",
"imported": true,
"uuid": "f0080a34-1786-4547-8d81-d89cc517b63e",
"files": [
".json"
],
"subMetas": {},
"userData": {}
}