CCEffect %{
techniques:
- name: opaque
passes:
- vert: sprite-vs:vert
frag: sprite-fs:frag4
depthStencilState:
depthTest: false
depthWrite: false
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
blendDstAlpha: one_minus_src_alpha
rasterizerState:
cullMode: none
properties: &props
colorLight : { value : [1.0,0.0,0.0,1.0] , editor: { type: color }}
outlineSlider : { value : 0.01 , target : outlineW , editor : { slide : true , range : [0.00,0.1], step: 0.01} }
outRadiusSlider : { value : 0.0 , target : outRadius , editor : { slide : true , range : [0.0,0.3], step: 0.01} }
textureSize: { value: [100.0, 100.0], editor: { tooltip: "纹理尺寸 " } }
}%
CCProgram sprite-vs %{
precision highp float;
#include <cc-global>
in vec3 a_position;
in vec2 a_texCoord;
in vec4 a_color;
out vec2 v_uv0;
out vec4 v_color;
vec4 vert () {
vec4 pos = vec4(a_position,1.0);
pos = cc_matProj * cc_matView * pos;
v_uv0 = a_texCoord;
v_color = a_color;
return pos;
}
}%
CCProgram sprite-fs %{
precision highp float;
#define PI 3.14159265359
// 定义无理数
#define e 2.718281828459045
#define stDev 5.0
in vec2 v_uv0;
in vec4 v_color;
uniform Constant {
vec4 colorLight;
float outlineW;
float outRadius;
vec2 textureSize;
};
#pragma builtin(local)
layout(set = 2, binding = 11) uniform sampler2D cc_spriteTexture;
//边缘光方法1
bool checkIsMakeOutline(vec2 pos){
//alpha检测值
float alpha = 0.1;
vec4 color = texture(cc_spriteTexture, pos);
if(color.a <= alpha || outlineW == 0.0)return false;
// if(color.a >= 0.8 )return false;
//检测当前点周围的8个点的alpha值
color = texture(cc_spriteTexture, pos + vec2(0, outlineW));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(outlineW, outlineW));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(outlineW, 0));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(outlineW, -outlineW));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(0, -outlineW));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(-outlineW, -outlineW));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(-outlineW, 0));
if(color.a <= alpha)return true;
color = texture(cc_spriteTexture, pos + vec2(-outlineW, outlineW));
if(color.a <= alpha)return true;
//当前点已是纹理边缘
if(pos.x <= outlineW || pos.x >= 1.0 - outlineW)return true;
if(pos.y <= outlineW || pos.y >= 1.0 - outlineW)return true;
return false;
}
float getBackArea()
{
vec4 color_up;
vec4 color_down;
vec4 color_left;
vec4 color_right;
// vec4 color_up_left;
// vec4 color_up_right;
// vec4 color_down_left;
// vec4 color_down_right;
float total = 0.0 ;
color_up = texture(cc_spriteTexture, v_uv0 + vec2(0.0, outlineW));
color_down = texture(cc_spriteTexture, v_uv0 - vec2(0.0, outlineW));
color_left = texture(cc_spriteTexture, v_uv0 - vec2(outlineW, 0.0));
color_right = texture(cc_spriteTexture, v_uv0 + vec2(outlineW, 0.0));
// color_up_left = texture(cc_spriteTexture, v_uv0 + vec2(outlineW, -outlineW));
// color_up_right = texture(cc_spriteTexture, v_uv0 + vec2(outlineW, outlineW));
// color_down_left = texture(cc_spriteTexture, v_uv0 + vec2(-outlineW, -outlineW));
// color_down_right = texture(cc_spriteTexture, v_uv0 + vec2(-outlineW, outlineW));
// total = color_right.a + color_left.a + color_down.a + color_up.a + color_up_left.a + color_up_right.a + color_down_left.a + color_down_right.a;
total = color_right.a + color_left.a + color_down.a + color_up.a;
return clamp(total, 0.0, 1.0);
}
//边缘光方法 1
vec4 frag0 () {
vec4 o = vec4(1, 1, 1, 1);
o *= texture(cc_spriteTexture,v_uv0);
o*= v_color;
if(checkIsMakeOutline(v_uv0)){
// //检查到v_uv0点需要描边,直接改变颜色值
o = vec4(1, 0, 0, o.a);
// o*=o;
}
return o;
}
// 边缘光方法 2
vec4 frag1 () {
vec4 fragColor = v_color * texture(cc_spriteTexture, v_uv0);
float isBack = getBackArea();
// 正常的rgb + 正常的透明区域 * 背面颜色 * 描边颜色
vec4 o = vec4(fragColor.rgb + (1.0 - fragColor.a)* colorLight.rgb * isBack, isBack);
return o;
}
//圆角裁切
vec4 frag2 () {
float radius = outRadius;
vec2 o1 = v_uv0;
vec4 o = vec4(0,0,0,0);
if((o1.x > radius && o1.x < 1.0-radius) || (o1.y > radius && o1.y < 1.0-radius) ){
o = texture(cc_spriteTexture,o1);
}else{
float tx = 0.5 + abs(o1.x - 0.5);
float ty = 0.5 - abs(o1.y - 0.5);
float len = distance(vec2(tx,ty), vec2(1.0-radius, radius));
float smo = radius * 0.01;//抗锯齿
if( len <= radius ){
o = texture(cc_spriteTexture,o1);
}else if(len <= radius + smo){
float cur = radius + smo-len;
o = texture(cc_spriteTexture,o1);
o.a = smoothstep(0.0, smo, cur);
};
};
return o;
}
//高斯模糊1 只取一圈的8个正点位,均值模糊,模糊基础原理实现
vec4 frag3 () {
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
float onePxWidth = 1.0 / textureSize.x;
float onePxHeight = 1.0 / textureSize.y;
float dif = 4.0;//取第4层
finalColor += texture(cc_spriteTexture, v_uv0) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(0.0, onePxHeight * dif)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(0.0, -onePxHeight * dif)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * dif, 0.0)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(-onePxWidth * dif, 0.0)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * dif, onePxHeight * dif)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * dif, -onePxHeight * dif)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(-onePxWidth * dif, -onePxHeight * dif)) * (1.0/9.0);
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(-onePxWidth * dif, onePxHeight * dif)) * (1.0/9.0);
return finalColor;
}
//高斯模糊2 取相邻若干层 进行均值模糊 未使用高斯模糊算法
vec4 frag4 () {
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
const float size = floor( 5.0 * 2.0 + 1.0);//取5层
const float halfSize = floor(size / 2.0);
float onePxWidth = 1.0 / textureSize.x;
float onePxHeight = 1.0 / textureSize.y;
for(float x = -halfSize; x<= halfSize; x++) {
for (float y = -halfSize; y<= halfSize; y++) {
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * x, onePxHeight * y)) * (1.0/ pow(size,2.0));
}
}
return finalColor;
}
float getWeight(float x, float y) {
return (1.0 / (2.0 * PI * pow(stDev, 2.0))) * pow(1.0 / e, (pow(x, 2.0) + pow(y, 2.0)) / (2.0 * pow(stDev, 2.0)));
}
//高斯模糊3 使用高斯模糊算法
vec4 frag5 () {
// 根据高斯分布(也叫正态分布),在3个标准差范围内的分布比例占到99%的权重,因此我们只需要计算矩阵范围 [6 * stDev + 1, 6 * stDev +1] 上的权重
const float size = floor(stDev * 6.0 + 1.0);
const float halfSize = floor(size / 2.0);
// 步骤一:计算高斯矩阵上所有权重的和
// 原点
float totalWeight = getWeight(0.0, 0.0);
// X轴正方向上的权重 * 2.0 就是整个X轴上的权重
for(float x = 1.0; x <= halfSize; x++) {
totalWeight += getWeight(x, 0.0) * 2.0;
}
// Y轴正方向上的权重 * 2.0 就是整个Y轴上的权重
for(float y = 1.0; y <= halfSize; y++) {
totalWeight += getWeight(0.0, y) * 2.0;
}
// 第一象限的权重 * 4.0 就是4个象限的权重
for(float x = 1.0; x <= halfSize; x++) {
for (float y = 1.0; y<= halfSize; y++) {
totalWeight += getWeight(x, y) * 4.0;
}
}
// 步骤二:采样周边像素并应用加权平均值,得出最终像素值
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
float onePxWidth = 1.0 / textureSize.x;
float onePxHeight = 1.0 / textureSize.y;
for(float x = -halfSize; x<= halfSize; x++) {
for (float y = -halfSize; y<= halfSize; y++) {
// 求出对应坐标的真正权重(对应权重矩阵)
float weight = getWeight(x, y) / totalWeight;
// 求出对应坐标像素颜色值的加权值
finalColor += texture(cc_spriteTexture, v_uv0 + vec2(onePxWidth * x, onePxHeight * y)) * weight;
}
}
return finalColor;
}
}%
【进击的Shader】【入门二】Cocos Shader Effect 实现Sprite 边缘光效果,圆角裁切抗锯齿效果,高斯模糊效果
于 2024-01-31 18:01:49 首次发布