前言:
原理是获取图像的A通道进行膨胀+高斯模糊+uv移动旋转
这个例子没写很好随便写的,将就着用
代码:
shader_type canvas_item;
uniform vec2 offset;
uniform float rotation;
uniform int blursize;
uniform float shadow_size;
float normpdf(in float x, in float sigma){
return 0.39894*exp(-.5*x*x/(sigma*sigma))/sigma;
}
vec4 gaussian_blur(sampler2D src, vec2 size, vec2 uv, int m_size){
vec4 cc = texture(src, uv);
vec3 c = cc.rgb;
int k_size = (m_size-1)/2;
float sigma = 7.;
vec3 final_color = vec3(0.);
float z = 0.;
for(int i=-k_size;i<=k_size;i++){
float n = normpdf(float(i), sigma);
z+=n;
for(int j=-k_size;j<=k_size;j++){
final_color+=n*n*texture(src,uv+size*vec2(float(i),float(j))).rgb;
}
}
return vec4(final_color/z/z,1.);
}
void fragment() {
// 获取当前像素的坐标
vec2 uv = UV;
// 获取原始图像的Alpha通道值
vec4 originalTex = textureLod(TEXTURE, uv, 0.0);
float alpha = originalTex.a;
// 计算投影坐标
vec2 projectedUV = vec2(uv.x + offset.x, uv.y + offset.y);
projectedUV = vec2(
cos(rotation) * (projectedUV.x - uv.x) - sin(rotation) * (projectedUV.y - uv.y) + uv.x,
sin(rotation) * (projectedUV.x - uv.x) + cos(rotation) * (projectedUV.y - uv.y) + uv.y
);
// 获取投影位置的纹理采样值
//vec4 projectedTex = textureLod(TEXTURE, projectedUV, 0.0);
vec4 projectedTex = gaussian_blur(TEXTURE ,TEXTURE_PIXEL_SIZE ,projectedUV , blursize);
// 使用原始图像的Alpha通道值创建投影形状
vec4 projection = vec4(0.0, 0.0, 0.0, projectedTex.r * shadow_size);
// 将当前像素的颜色设置为原始图像和投影形状的混合
//COLOR = max(projection, originalTex);
COLOR = originalTex;
if (COLOR.a <= 0.5){
COLOR.a = COLOR.a + projection.a;
COLOR.rgb = projection.rgb
}
//COLOR = projection;
}
左图是原图,右图是shader的效果
其实有点像PS的混合选项,网上也有大佬写过原理的文章。
因为shader无法栅格化,所以有需求的话可以加入opencv对图像进行处理。
参考资料:
【PS算法理论探讨二】 Photoshop中图层样式之 投影样式 算法原理初探讨。 - Imageshop - 博客园 (cnblogs.com)