有向距离场(SDF)在Shader中的简单应用

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对应的代码区域,然后编译下就能看到图像了,第二个画雷达图的代码比较多,等到后面再具体讲下算法以及完整的实现方式;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值