SDF, 全称Signed Distance Filed,就是有符号的距离区域
看下简单的例子,一个圆型区域
那么我们定义一个距离场函数:
float sdfCircle(vec2 tex, vec2 center, float dis)
{
return -length(vec2(tex - center)) + dis;
}
传入的参数分别是:当前像素点坐标, 圆心坐标,半径,函数的返回值是一个有正负的浮点数,通俗点说就是在园内的区域返回的是一个正值,大小是离原边界的距离;而在圆外面的区域,返回的值是负值,大小也是与边界的距离;这就相当于以前学过的什么电场磁场等,只不过定义的含义不同;那么说了这么多,这个sdf的应用有哪些的,下面我们看一些应用:
eg1:在一个画布上画一个抗锯齿的圆,下图是在shadertoy上画的一个圆,代码非常简单,
代码如下:
float sdfCircle(vec2 tex, vec2 center, float dis)
{
return -length(vec2(tex - center)) + dis;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord;
vec2 center = 0.5 * iResolution.xy;
vec3 background_color = vec3(0.3, 0.3, 0.3);
vec3 circle_color = vec3(0.6, 0.6, 0.);
vec3 edge_color = vec3(1., 1., 1.);
float edge_width =iResolution.y * 0.005;
float radius = iResolution.y * 0.25;
float d = sdfCircle(uv, center, radius);
float anti = fwidth(d);
vec3 col = mix(background_color, edge_color, smoothstep(-anti, anti, d ));
float d1 = sdfCircle(uv, center, radius - edge_width);
float anti1 = fwidth(d1);
float edge_alpha = smoothstep(-anti1, anti1, d1);
col = mix(col, circle_color, edge_alpha);
// Output to screen
fragColor = vec4(col,1.0);
}
可以从图看出来,边界分解线上,是没有什么锯齿的,原理就是在边界处sdf返回的值是0,而在边界附近,sdf的值是在0附近的一些数,所以加上我们的插值函数(mix) 与(fwidth)就可以画出丝滑般的图形了,至于mix函数和fwidth函数这里不细讲,后面有时间会加到博客里面;我们也可以画一个更复杂的平面几何图形,如下所示:
像这种图形在游戏和许多app上都有,通常称为雷达图,就是根据输入的几个数据,然后依次连接起来成为一个多边形,例如王者荣耀结算时的评分,支付宝芝麻信用分的评分都是这种图形;其代码如下:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord;
vec2 center = 0.5 * iResolution.xy;
vec3 background_color = vec3(0.3, 0.3, 0.3);
vec3 circle_color = vec3(0.6, 0.6, 0.);
vec3 edge_color = vec3(1., 1., 1.);
float edge_width =iResolution.y * 0.05;
MyPoints res = getPoints();
float d = sdfPloygon(res.point_vec, fragCoord); //和上面画圆代码最大的区别是这个SDF函数
float anti = fwidth(d);
vec3 col = mix(background_color, circle_color, smoothstep(-anti, anti, d));
// Output to screen
fragColor = vec4(col,1.0);
}
画圆和画这个雷达图,他们方法大部分是一样的,主要的区别就是SDF函数不同,只要我们能求出的对应的有向距离场,就可以很快的画出对应没有锯齿的图形。
最后推荐一个网站,一个用Glsl语言画图的网站
在这个网站可以很方便的画图,不需要自己去搭建一些什么渲染管线环境,还是挺方便的;上诉画圆的代码直接赋值粘贴到shadertoy对应的代码区域,然后编译下就能看到图像了,第二个画雷达图的代码比较多,等到后面再具体讲下算法以及完整的实现方式;