Append the spatial-hash neighbour-gather loop nest to a kernel body.
The kernel body must already have in scope: vec3 p; uint stride_words, position_offset; the grid push constants grid_min_x/y/z, cell_size, dim_x/y/z; and the vertices, cell_start, cell_count, particle_index bindings. When walk.cluster_scoped is set, also uint my_cluster, uint cross_cluster and the cluster_id binding.
28{
29 const std::string& r = walk.
reach;
30
31 body += " vec3 gmin = vec3(grid_min_x, grid_min_y, grid_min_z);\n";
32 body += " uvec3 dims = uvec3(dim_x, dim_y, dim_z);\n";
33 body += " ivec3 base = ivec3(floor((p - gmin) / cell_size));\n";
34 body += " base = clamp(base, ivec3(0), ivec3(dims) - ivec3(1));\n";
35 body += "\n";
36 body += " for (int dz = -" + r + "; dz <= " + r + "; dz = dz + 1) {\n";
37 body += " for (int dy = -" + r + "; dy <= " + r + "; dy = dy + 1) {\n";
38 body += " for (int dx = -" + r + "; dx <= " + r + "; dx = dx + 1) {\n";
39 body += " ivec3 nc = base + ivec3(dx, dy, dz);\n";
40 body += " if (nc.x < 0 || nc.y < 0 || nc.z < 0 || "
41 "nc.x >= int(dim_x) || nc.y >= int(dim_y) || nc.z >= int(dim_z)) {\n";
42 body += " continue;\n";
43 body += " }\n";
44 body += " uint cell = uint(nc.x) + uint(nc.y) * dim_x + uint(nc.z) * dim_x * dim_y;\n";
45 body += " uint start = cell_start[cell];\n";
46 body += " uint count = cell_count[cell];\n";
47 body += " for (uint k = 0u; k < count; k = k + 1u) {\n";
48 body += " uint j = particle_index[start + k];\n";
49 body +=
" if (" + walk.
skip_self +
") { continue; }\n";
51 body += " if (cross_cluster == 0u && cluster_id[j] != my_cluster) "
52 "{ continue; }\n";
53 }
54 body += " uint bj = j * stride_words;\n";
55 body += " vec3 pj = vec3(vertices[bj + position_offset], "
56 "vertices[bj + position_offset + 1u], vertices[bj + position_offset + 2u]);\n";
57 body +=
" if (length(pj - p) < " + walk.
radius +
") {\n";
58
59 for (std::size_t start = 0; start < walk.
on_hit.size();) {
60 const std::size_t nl = walk.
on_hit.find(
'\n', start);
61 const std::size_t end = nl == std::string::npos ? walk.
on_hit.size() : nl;
62 body += " ";
63 body += walk.
on_hit.substr(start, end - start);
64 body += "\n";
65 if (nl == std::string::npos) {
66 break;
67 }
68 start = nl + 1;
69 }
70
71 body += " }\n";
72 body += " }\n";
73 body += " }\n";
74 body += " }\n";
75 body += " }\n";
76}
std::string radius
Distance cutoff, a GLSL expression.
std::string reach
Cell-block half-extent, a GLSL expression or int local name.
bool cluster_scoped
Emit the cross_cluster / cluster_id guard.
std::string on_hit
Statements run per in-range candidate; j, bj, pj, p in scope. One per line, no braces,...
std::string skip_self
Candidate skipped when this GLSL predicate holds.