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,9 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "5a2048d4-99ea-4f02-99b3-2ba9d1ec4fd5",
"files": [],
"subMetas": {},
"userData": {}
}

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": {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -2,7 +2,7 @@
"ver": "1.0.27",
"importer": "image",
"imported": true,
"uuid": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400",
"uuid": "f8c208df-8e8c-456e-9f97-1d1c07518452",
"files": [
".json",
".png"
@@ -10,14 +10,14 @@
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@6c48a",
"displayName": "1_0022_Layer-19",
"uuid": "f8c208df-8e8c-456e-9f97-1d1c07518452@6c48a",
"displayName": "PicWin",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400",
"imageUuidOrDatabaseUri": "f8c208df-8e8c-456e-9f97-1d1c07518452",
"isUuid": true,
"visible": false,
"minfilter": "linear",
@@ -34,8 +34,8 @@
},
"f9941": {
"importer": "sprite-frame",
"uuid": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@f9941",
"displayName": "1_0022_Layer-19",
"uuid": "f8c208df-8e8c-456e-9f97-1d1c07518452@f9941",
"displayName": "PicWin",
"id": "f9941",
"name": "spriteFrame",
"userData": {
@@ -45,9 +45,9 @@
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 1297,
"width": 1299,
"height": 1004,
"rawWidth": 1297,
"rawWidth": 1299,
"rawHeight": 1004,
"borderTop": 0,
"borderBottom": 0,
@@ -60,16 +60,16 @@
"meshType": 0,
"vertices": {
"rawPosition": [
-648.5,
-649.5,
-502,
0,
648.5,
649.5,
-502,
0,
-648.5,
-649.5,
502,
0,
648.5,
649.5,
502,
0
],
@@ -84,11 +84,11 @@
"uv": [
0,
1004,
1297,
1299,
1004,
0,
0,
1297,
1299,
0
],
"nuv": [
@@ -102,18 +102,18 @@
1
],
"minPos": [
-648.5,
-649.5,
-502,
0
],
"maxPos": [
648.5,
649.5,
502,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@6c48a",
"imageUuidOrDatabaseUri": "f8c208df-8e8c-456e-9f97-1d1c07518452@6c48a",
"atlasUuid": "",
"trimType": "auto"
},
@@ -129,6 +129,6 @@
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": false,
"hasAlpha": true,
"redirect": "3ef3f86f-bc1f-49b7-a50f-0e8683cd2400@6c48a"
"redirect": "f8c208df-8e8c-456e-9f97-1d1c07518452@6c48a"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -49,10 +49,10 @@
"height": 1189,
"rawWidth": 1190,
"rawHeight": 1189,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"borderTop": 220,
"borderBottom": 220,
"borderLeft": 220,
"borderRight": 220,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,