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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
static const std::string INTERACT_SHADER_CODE = R"(
#version 430
layout (local_size_x = 1, local_size_y = 1) in;
layout (std430, binding=3) buffer bufferFluid { float fluidCells[]; };
layout (std430, binding=4) buffer bufferExtra { float extraCells[]; };
uniform uint nX;
uniform uint nY;
/// External influence
uniform bool wall_requested;
uniform bool fluid_requested;
uniform vec2 start;
uniform vec2 end;
/// Vector utilities
float norm(vec2 v) {
return sqrt(dot(v,v));
}
float distanceToLineSegment(vec2 a, vec2 b, vec2 p) {
const vec2 ab = b - a;
const vec2 pa = a - p;
if ( dot(ab, pa) > 0.0 ) {
return norm(pa);
}
const vec2 bp = p - b;
if ( dot(ab, bp) > 0.0 ) {
return norm(bp);
}
return norm(pa - ab * (dot(ab, pa) / dot(ab, ab)));
}
bool isNearLine(uint x, uint y, float eps) {
if ( start == end ) {
return norm(vec2(x,y) - end) < eps;
} else {
return distanceToLineSegment(start, end, vec2(x,y)) < eps;
}
}
/// Array indexing
uint indexOfFluidVertex(uint x, uint y) {
return 3*nX*y + 3*x;
}
/// Data access
int getMaterial(uint x, uint y) {
const uint idx = indexOfFluidVertex(x, y);
return int(fluidCells[idx + 2]);
}
void setMaterial(uint x, uint y, int m) {
const uint idx = indexOfFluidVertex(x, y);
fluidCells[idx + 2] = m;
extraCells[idx + 2] = m;
}
/// Geometry cleanup
void disableWallInterior(uint x, uint y) {
int wallNeighbors = 0;
for ( int i = -1; i <= 1; ++i ) {
for ( int j = -1; j <= 1; ++j ) {
const int material = getMaterial(x+i,y+j);
if ( material == 0 || material == 2 || material == 3 ) {
++wallNeighbors;
}
}
}
if ( wallNeighbors == 9 ) {
setMaterial(x,y,0);
}
}
void fixWallExterior(uint x, uint y) {
for ( int i = -1; i <= 1; ++i ) {
for ( int j = -1; j <= 1; ++j ) {
if ( getMaterial(x+i,y+j)== 0 ) {
setMaterial(x+i,y+j,3);
}
}
}
}
/// Actual interaction kernel
void main() {
const uint x = gl_GlobalInvocationID.x;
const uint y = gl_GlobalInvocationID.y;
if ( !(x < nX && y < nY) ) {
return;
}
const int material = getMaterial(x,y);
if ( material == 1 ) {
if ( isNearLine(x, y, 3) ) {
if ( wall_requested ) {
setMaterial(x,y,3);
return;
}
}
}
if ( material == 0 || material == 3 ) {
if ( fluid_requested ) {
if ( isNearLine(x, y, 3) ) {
setMaterial(x,y,1);
fixWallExterior(x,y);
return;
}
}
}
if ( material == 3 ) {
disableWallInterior(x,y);
}
}
)";
|