Godot - Shader - Sobel简单边缘算法

Sobel Filter是一个相当简单的边缘查找算法,他能检测比较锐利的边缘(模糊的图片或不锐利的边缘无法有效检测,请搜索Canny Filter算法)

方法是获得当前点以及周围点的权重来描述当前点位置上的边缘强度(颜色变化速度)

  • 横向边缘检测Mx


  • 紫色像素的周围九宫格与横向检测矩阵dot得到一个值,这个值的大小就是边缘颜色变化率,当两侧颜色相同或相近时,你可以看到这个值趋近于0. 整体图视作Gx


  • 同样方法可以检测纵向的颜色变化,这样可以得到一张图片的两个不同方向的灰度变化图Gx和Gy


  • 如何混合两个不同方向上的边缘强度变化?


  • 答案是两个方向的平方和开方
    强度为 G = (Gx*Gx+Gy*Gy)^0.5;
    方向为 R = atan(Gy/Gx);

godot shader实现

  • 这里只用到了强度
  • 因为gdshader的内建函数还不能在自定义函数中直接调用,暂时使用传参方法
shader_type canvas_item;

vec3 samplef(vec2 offset, vec2 uv, sampler2D text, vec2 tsize){
    return texture(text, vec2(uv+offset*tsize)).rgb;
}

float luminance(vec3 c){
    return dot(c,vec3(.2126,.7152,.0722));
//  return dot(c,vec3(1.))*0.3333;
}

vec3 sobelFilter(vec2 uv, sampler2D text, vec2 tsize){
    //
    vec3 hc=samplef(vec2(-1.,-1.),uv,text,tsize)+samplef(vec2(0.,-1.),uv,text,tsize)*2.
        +samplef(vec2(1.,-1.),uv,text,tsize)+samplef(vec2(-1.,1.),uv,text,tsize)*-1.
        +samplef(vec2(0.,1.),uv,text,tsize)*-2.+samplef(vec2(1.,1.),uv,text,tsize)*-1.;
    //
    vec3 vc=samplef(vec2(-1.,-1.),uv,text,tsize)+samplef(vec2(-1.,0.),uv,text,tsize)*2.
        +samplef(vec2(-1.,1.),uv,text,tsize)+samplef(vec2(1.,-1.),uv,text,tsize)*-1.
        +samplef(vec2(1.,0.),uv,text,tsize)*-2.+samplef(vec2(1.,1.),uv,text,tsize)*-1.;
    return texture(text,uv).rgb*pow(luminance(vc*vc+hc*hc),.6);
}

void fragment(){
//  COLOR = vec4(sobelFilter(UV, TEXTURE, TEXTURE_PIXEL_SIZE),1.0);
//  COLOR = vec4(vec3(length(sobelFilter(UV,TEXTURE,TEXTURE_PIXEL_SIZE))),1.);
    COLOR = vec4(vec3(length(sobelFilter(UV,TEXTURE,TEXTURE_PIXEL_SIZE))),texture(TEXTURE,UV).a);
}
原图 结果

视频:
https://www.bilibili.com/video/av15346632?from=search&seid=17167334084508443686

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容