Files
mp-xieyingeng/assets/resources/effects/rounded-sprite.effect
2026-05-03 22:28:22 +08:00

141 lines
3.5 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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;
}
}%