消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
4.9 KiB

1 week ago
// chenshw23
// cocos store : https://store.cocos.com/dashboard/detail/8073
// 修改说明:增加了边缘虚化功能 (edgeBlurRadius)
CCEffect %{
techniques:
- passes:
- vert: lightScene-vs:vert
frag: lightScene-fs:frag
depthStencilState:
depthTest: false
depthWrite: false
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
rasterizerState:
cullMode: none
properties:
wh_ratio: { value: 2.22222 }
lights: { value: [-1, 0.5, -1, 0.05]}
occluders: { value: [0.0, 0.0, 0.0, 0.0]}
lightShadow: { value: [0.0, 0.0, 0.0, 0.0]}
edgeBlurRadius: { value: 0.1 }
}%
CCProgram lightScene-vs %{
precision highp float;
#include <builtin/uniforms/cc-global>
in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;
out vec4 v_color;
out vec2 v_uv;
vec4 vert() {
vec4 pos = vec4(a_position, 1);
pos = cc_matViewProj * pos;
v_uv = a_texCoord;
v_color = a_color;
return pos;
}
}%
CCProgram lightScene-fs %{
precision highp float;
#include <legacy/output>
in vec2 v_uv;
in vec4 v_color;
uniform sampler2D mainTexture;
#pragma define light_max_num 30
#pragma define occluder_max_num 200
#pragma define PI 3.14159265359
uniform Constant {
vec4 lights[light_max_num];
vec4 lightShadow[light_max_num];
vec4 occluders[occluder_max_num];
float wh_ratio;
float edgeBlurRadius;
};
bool lineSegmentIntersectOptimized(vec2 p1, vec2 p2, vec2 p3, vec2 p4) {
if (max(p1.x, p2.x) < min(p3.x, p4.x) ||
max(p3.x, p4.x) < min(p1.x, p2.x) ||
max(p1.y, p2.y) < min(p3.y, p4.y) ||
max(p3.y, p4.y) < min(p1.y, p2.y)) {
return false;
}
vec2 a = p2 - p1;
vec2 b = p4 - p3;
vec2 c = p3 - p1;
float denom = a.x * b.y - a.y * b.x;
if (abs(denom) < 1e-6) {
return false;
}
float t = (c.x * b.y - c.y * b.x) / denom;
float u = (c.x * a.y - c.y * a.x) / denom;
return (t >= 0.0 && t <= 1.0 && u >= 0.0 && u <= 1.0);
}
bool isLightOccluder(vec2 lightPos) {
bool isCross = false;
vec2 bPos = vec2(0.0);
int nextNum = 0;
bool isLast = false;
for (int o_i = 0; o_i < occluder_max_num; o_i++) {
if (o_i == nextNum) {
if (occluders[o_i].x <= 0.0) {
break;
}
isLast = occluders[o_i].y <= 0.0;
bPos = occluders[o_i].zw;
nextNum = o_i + int(occluders[o_i].x) + 1;
} else {
vec2 p_prev = (o_i == 0) ? bPos : occluders[o_i-1].zw; // 简单保护
// 原逻辑还原开始
isCross = lineSegmentIntersectOptimized(v_uv, lightPos, occluders[o_i-1].zw, occluders[o_i].xy);
if (isCross) {break;}
if (o_i+1 != nextNum || isLast) {
isCross = lineSegmentIntersectOptimized(v_uv, lightPos, occluders[o_i].xy, occluders[o_i].zw);
if (isCross) {break;}
}
if (o_i+1 == nextNum) {
isCross = lineSegmentIntersectOptimized(v_uv, lightPos, isLast ? occluders[o_i].zw : occluders[o_i].xy, bPos);
if (isCross) {break;}
}
// 原逻辑还原结束
}
}
return isCross;
}
vec4 frag() {
vec4 col = v_color;
// 1. 原有的光照计算逻辑
for (int c_i = 0; c_i < light_max_num; c_i++) {
if (lights[c_i].x <= -1.0) {
break;
}
vec2 v2 = v_uv - lights[c_i].xy;
v2.x *= wh_ratio;
float dis = length(v2);
if (dis <= (lights[c_i].z + lights[c_i].w)) {
bool isCross = false;
#if CALC_OCCLUDER
if (lightShadow[c_i].x > 0.5) {
isCross = isLightOccluder(lights[c_i].xy);
}
#endif
if (!isCross) {
if (dis <= lights[c_i].z) {
col.a = 0.0;
break;
} else if (lights[c_i].w > 0.0 && dis <= (lights[c_i].z + lights[c_i].w)) {
float t = smoothstep(0.0, 1.0, (dis - lights[c_i].z) / lights[c_i].w);
col.a -= (1.0-t);
}
if (col.a <= 0.0) {
col.a = 0.0;
break;
}
}
}
}
// 如果光照已经让透明度为 0,直接返回,无需计算边缘
if (col.a <= 0.0) {
col.a = 0.0;
return col;
}
// 2. 新增:边缘虚化逻辑
if (edgeBlurRadius > 0.0) {
// 计算当前像素距离四边的距离 (UV 范围 0.0 ~ 1.0)
float distLeft = v_uv.x;
float distRight = 1.0 - v_uv.x;
float distBottom = v_uv.y;
float distTop = 1.0 - v_uv.y;
// 取最小距离
float minDist = min(min(distLeft, distRight), min(distBottom, distTop));
// 如果距离小于虚化半径,进行平滑过渡
if (minDist < edgeBlurRadius) {
// 使用 smoothstep 产生柔和的渐变
// 当 minDist 为 0 时,factor 为 0 (完全透明)
// 当 minDist 为 edgeBlurRadius 时,factor 为 1 (不透明)
float factor = smoothstep(0.0, edgeBlurRadius, minDist);
col.a *= factor;
}
}
// 最终钳制透明度
if (col.a <= 0.0) {
col.a = 0.0;
}
return col;
}
}%