// 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 #if USE_LOCAL #include #endif #if SAMPLE_FROM_RT #include #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 #include 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; } }%