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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
#version 450
#extension GL_ARB_separate_shader_objects : enable
#define WIDTH 3200
#define HEIGHT 2400
#define WORKGROUP_SIZE 32
layout (local_size_x = WORKGROUP_SIZE, local_size_y = WORKGROUP_SIZE, local_size_z = 1 ) in;
layout ( binding = 0, rgba8 ) uniform writeonly image2D buf;
// License: CC0 (http://creativecommons.org/publicdomain/zero/1.0/)
// A standard gaussian function, used for weighting samples
float gaussian(float x, float sigma) {
const float pi = 3.141592653589793;
return exp(-(x * x) / (2.0 * sigma * sigma)) / (sqrt(2.0 * pi) * sigma);
}
// This approximates the error function, needed for the gaussian integral
vec2 erf(vec2 x) {
vec2 s = sign(x), a = abs(x);
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
x *= x;
return s - s / (x * x);
}
// Return the blurred mask along the x dimension
float roundedBoxShadowX(float x, float y, float sigma, float corner, vec2 halfSize) {
float delta = min(halfSize.y - corner - abs(y), 0.0);
float curved = halfSize.x - corner + sqrt(max(0.0, corner * corner - delta * delta));
vec2 integral = 0.5 + 0.5 * erf((x + vec2(-curved, curved)) * (sqrt(0.5) / sigma));
return integral.y - integral.x;
}
// Return the mask for the shadow of a box from lower to upper
float roundedBoxShadow(vec2 lower, vec2 upper, vec2 point, float sigma, float corner) {
// Center everything to make the math easier
vec2 center = (lower + upper) * 0.5;
vec2 halfSize = (upper - lower) * 0.5;
point -= center;
// The signal is only non-zero in a limited range, so don't waste samples
float low = point.y - halfSize.y;
float high = point.y + halfSize.y;
float start = clamp(-3.0 * sigma, low, high);
float end = clamp(3.0 * sigma, low, high);
// Accumulate samples (we can get away with surprisingly few samples)
float step = (end - start) / 4.0;
float y = start + step * 0.5;
float value = 0.0;
for (int i = 0; i < 4; i++) {
value += roundedBoxShadowX(point.x, point.y - y, sigma, corner, halfSize) * gaussian(y, sigma) * step;
y += step;
}
return value;
}
//---------------------------------------------------------
// draw rectangle frame with rounded edges
//---------------------------------------------------------
float roundedFrame (vec2 uv, vec2 pos, vec2 size, float radius, float thickness)
{
float d = length(max(abs(uv - pos),size) - size) - radius;
return smoothstep(0.95, 0.05, abs(d / thickness));
//return 1.0/abs(d / thickness);
}
void main() {
if(gl_GlobalInvocationID.x >= WIDTH || gl_GlobalInvocationID.y >= HEIGHT)
return;
vec2 pos = {float(gl_GlobalInvocationID.x) / float(WIDTH),float(gl_GlobalInvocationID.y) / float(HEIGHT)};
//vec4 color = vec4( 1.0,0.0,0.0,1.0);
//float s = roundedBoxShadow (vec2(0.1,0.1), vec2(0.5,0.5), vec2(x,y), 0.02, 0.1);
float s = roundedFrame (pos, vec2(0.6,0.6), vec2(0.1,0.1), 0.1,0.002);
vec4 color = vec4(s,s,s,s);
imageStore(buf, ivec2(gl_GlobalInvocationID.xy), color);
}
|