CocosCreator-Shader-Effect-.../assets/effects/glow-inner.effect
2019-12-20 16:00:01 +08:00

193 lines
5.3 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.

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
// 内发光特效
// 原理: 采样周边像素alpha取平均值叠加发光效果
CCEffect %{
techniques:
- passes:
- vert: vs
frag: fs
blendState:
targets:
- blend: true
rasterizerState:
cullMode: none
properties:
texture: { value: white }
alphaThreshold: { value: 0.5 }
glowColor: { value: [1.0, 1.0, 0.0, 1.0], editor: { type: color } }
glowColorSize: { value: 0.01 }
}%
CCProgram vs %{
precision highp float;
#include <cc-global>
#include <cc-local>
in vec3 a_position;
in vec4 a_color;
out vec4 v_color;
#if USE_TEXTURE
in vec2 a_uv0;
out vec2 v_uv0;
#endif
void main () {
vec4 pos = vec4(a_position, 1);
#if CC_USE_MODEL
pos = cc_matViewProj * cc_matWorld * pos;
#else
pos = cc_matViewProj * pos;
#endif
#if USE_TEXTURE
v_uv0 = a_uv0;
#endif
v_color = a_color;
gl_Position = pos;
}
}%
CCProgram fs %{
precision highp float;
#include <alpha-test>
in vec4 v_color;
#if USE_TEXTURE
in vec2 v_uv0;
uniform sampler2D texture;
#endif
#if SHOW_INNER_GLOW
uniform glow {
// 发光颜色
vec4 glowColor;
// 发光范围
float glowColorSize;
// 特别地,必须是 vec4 先于 float 声明
};
/**
* 获取指定角度方向距离为xxx的像素的透明度
*
* @param angle 角度 [0.0, 360.0]
* @param distance 距离 [0.0, 1.0]
*
* @return alpha [0.0, 1.0]
*/
float getColorAlpha(float angle, float distance) {
// 角度转弧度,公式为:弧度 = 角度 * (pi / 180)
float radian = angle * 0.01745329252; // 这个浮点数是 pi / 180
vec4 color = texture(texture, v_uv0 + vec2(distance * cos(radian), distance * sin(radian)));
return color.a;
}
/**
* 获取指定距离的周边像素的透明度平均值
*
* @param distance 距离 [0.0, 1.0]
*
* @return average alpha [0.0, 1.0]
*/
float getDistanceAverageAlpha(float distance) {
float totalAlpha = 0.0;
totalAlpha += getColorAlpha(0.0, distance);
totalAlpha += getColorAlpha(30.0, distance);
totalAlpha += getColorAlpha(60.0, distance);
totalAlpha += getColorAlpha(90.0, distance);
totalAlpha += getColorAlpha(120.0, distance);
totalAlpha += getColorAlpha(150.0, distance);
totalAlpha += getColorAlpha(180.0, distance);
totalAlpha += getColorAlpha(210.0, distance);
totalAlpha += getColorAlpha(240.0, distance);
totalAlpha += getColorAlpha(270.0, distance);
totalAlpha += getColorAlpha(300.0, distance);
totalAlpha += getColorAlpha(330.0, distance);
return totalAlpha * (1.0 / 12.0);
}
/**
* 获取发光的透明度
*/
float getGlowAlpha() {
// 原来已经透明的点不处理
vec4 srcColor = texture(texture, v_uv0);
if (srcColor.a < 0.0000000001) {
return srcColor.a;
}
// 处理原来不透明的点,求周边平均透明度
float totalAlpha = 0.0;
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.1);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.2);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.3);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.4);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.5);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.6);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.7);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.8);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 0.9);
totalAlpha += getDistanceAverageAlpha(glowColorSize * 1.0);
return totalAlpha * (1.0 / 10.0);
}
#endif
void main () {
vec4 o = vec4(1, 1, 1, 1);
#if USE_TEXTURE
o *= texture(texture, v_uv0);
#if CC_USE_ALPHA_ATLAS_TEXTURE
o.a *= texture2D(texture, v_uv0 + vec2(0, 0.5)).r;
#endif
#endif
o *= v_color;
ALPHA_TEST(o);
gl_FragColor = o;
#if SHOW_INNER_GLOW
// 目标颜色(图像)
vec4 color_dest = o;
// 源颜色(内发光)
float alpha = getGlowAlpha();
// 此时我们得到的是内部透明度为1靠近边缘的为接近0的透明度
// 而内发光恰恰相反是需要内部透明度为0靠近边缘的接近1的透明度
// 因此我们需要翻转一下透明度
// 如果图像边缘有大量渐变,那么如果我们取 0.0 的话,那么可能边缘会出现锯齿
// 因此我们取0.1作为翻转临界值0.1也不是绝对的,可以自行修改这里的值
if (alpha > 0.1) {
alpha = 1.0 - alpha;
}
vec4 color_src = glowColor * alpha;
// 按照这个顺序,源颜色就是内发光颜色,目标颜色就是图案颜色色
// 所以命名就是 color_src, color_dest
// 按照混合颜色规则 http://docs.cocos.com/creator/manual/zh/advanced-topics/ui-auto-batch.html#blend-%E6%A8%A1%E5%BC%8F
// 要在图案上方,叠加一个内发光,将两者颜色混合起来,那么最终选择的混合模式如下:
//
// 内发光color_src: GL_SRC_ALPHA
// 原图像color_dest: GL_ONE
//
// 即最终颜色如下:
// color_src * GL_SRC_ALPHA + color_dest * GL_ONE
gl_FragColor = color_src * color_src.a + color_dest;
#endif
}
}%