数学可视化(05)——2D距离场与图像

  1. 1. 有向距离场Signed Distance Field (SDF)
    1. 1.1. 2D距离场所需参数
    2. 1.2. 2D距离场

 

有向距离场Signed Distance Field (SDF)

  • 2D距离场是由原点到平面上任意一点的距离,定义为矢量,是有方向的。由这些有方向距离定义的空间,为有向距离场
  • 可以利用距离的正负来定义图形的边界,这样就可以利用距离场来绘制图形了

2D距离场所需参数

  • 原点O
  • 目标点P
  • 距离(可以是不同定义下的距离)
    • 欧式距离
    • 切比雪夫距离
    • 曼哈顿距离
    • 其他距离定义…

2D距离场

  • 圆形:sdCircle(float2 pos, float d)

  • 正方形:sdSquare(float2 pos, float d)

  • 正菱形:sdRhombic(float2 pos, float d)

  • 椭圆形:sdEllipse(float2 pos, float w, float h)

  • 矩形:sdRect(float2 pos, float w, float h)

  • 菱形:sdRhombus(float pos, float w, float h)

  • 梯形:sdTrapezoid(float2 pos, float up, float down, float h)

  • 等腰三角形:sdTriangleIsocaeles(float2 pos, float down, float h)

  • 任意多边形:sdAnything(float2 pos, float2[] points)

  • 极坐标下任意正多边形:sdPolygopn(float2 pos, float r)

  • https://iquilezles.org/articles/distfunctions2d/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
float sdCircle(float2 p, float r)
{
return length(p) - r;
}

float sdRect(float2 p, float2 b)
{
float2 d = abs(p) - b;
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}

float sdStar5(in float2 p, in float r, in float rf)
{
const float2 k1 = float2(0.809016994375, -0.587785252292);
const float2 k2 = float2(-k1.x,k1.y);
p.x = abs(p.x);
p -= 2.0*max(dot(k1,p),0.0)*k1;
p -= 2.0*max(dot(k2,p),0.0)*k2;
p.x = abs(p.x);
p.y -= r;
float2 ba = rf*float2(-k1.y,k1.x) - float2(0,1);
float hh = clamp( dot(p,ba)/dot(ba,ba), 0.0, r );
return length(p-ba*h) * sign(p.y*ba.x-p.x*ba.y);
}

half3 PixelColor(float2 uv)
{
half3 c = half3(0, 0, 0);
//---编写你的逻辑, 不要超过2023个字节(包括空格)
// 全象限
uv.y = 1.0 - uv.y;
uv = uv * 2 - 1;
// (-5,5)
const int uvScale = 5;
uv = uv * uvScale;
// 消除屏幕拉伸影响
half co = w/h;
uv = float2(uv.x * co, uv.y);

float step = 1.0 / w;
float circle = smoothstep(step, -step, sdCircle(uv - float2(5.0, 0), 1.5));
float rect = smoothstep(step, -step, sdRect(uv, float2(2, 1)));
float star5 = smoothstep(step, -step, sdStar5(uv + float2(5.0, 0), 1, 2.5));

float final = circle + rect + star5;
c = lerp(c, float3(1.0, 1.0, 1.0), final);

//
return c;
}
  • SDF的值是可以进行数学运算的,包括加、减、min、max、与或非等

1
2
3
4
5
6
...
float circle = smoothstep(step, -step, sdCircle(uv, 1.5)); // - float2(5.0, 0)
float rect = smoothstep(step, -step, sdRect(uv, float2(2, 1)));
...
float final = (!circle && !rect ) - star5;
...
  • SDF操作还可以加圆角

1
2
3
4
5
6
7
8
9
10
11
float opRound(float sdf, float r)
{
return sdf - r;
}

...

float circle = smoothstep(step, -step, opRound(sdCircle(uv - float2(5.0, 0), 1.5), 0.2));
float rect = smoothstep(step, -step, opRound(sdRect(uv, float2(2, 1)), 0.2));
float star5 = smoothstep(step, -step, opRound(sdStar5(uv + float2(5.0, 0), 1, 2.5), 0.2));

  • 还可以制作圆环效果

1
2
3
4
5
6
7
8
9
10
11
float opAnnular(float sdf, float r)
{
return abs(sdf) - r;
}

...

float circle = smoothstep(step, -step, opAnnular(sdCircle(uv - float2(5.0, 0), 1.5), 0.2));
float rect = smoothstep(step, -step, opAnnular(sdRect(uv, float2(2, 1)), 0.2));
float star5 = smoothstep(step, -step, opAnnular(sdStar5(uv + float2(5.0, 0), 1, 2.5), 0.2));