1#include "FastSweepingMethodGPU.h"
3#include "Algorithm/Reduction.h"
5#include "Collision/Distance3D.h"
9 IMPLEMENT_TCLASS(FastSweepingMethodGPU, TDataType)
11 template<typename TDataType>
12 FastSweepingMethodGPU<TDataType>::FastSweepingMethodGPU()
17 template<typename TDataType>
18 FastSweepingMethodGPU<TDataType>::~FastSweepingMethodGPU()
29 template<typename TDataType>
30 void FastSweepingMethodGPU<TDataType>::compute()
35#define TRI_MIN(x, y, z) glm::min(x, glm::min(y, z))
36#define TRI_MAX(x, y, z) glm::max(x, glm::max(y, z))
38 template<typename Real>
39 __global__ void FSM_AssignInifity(
41 DArray3D<int> closest_tri_id,
42 DArray3D<GridType> types)
44 int i = threadIdx.x + (blockIdx.x * blockDim.x);
45 int j = threadIdx.y + (blockIdx.y * blockDim.y);
46 int k = threadIdx.z + (blockIdx.z * blockDim.z);
52 if (i >= nx || j >= ny || k >= nz) return;
54 phi(i, j, k) = REAL_MAX;
55 closest_tri_id(i, j, k) = -1;
56 types(i, j, k) = GridType::Infinite;
59 template<typename Real, typename Coord>
60 __global__ void FSM_FindNeighboringGrids(
61 DArray3D<uint> counter,
62 DArray<Coord> vertices,
63 DArray<TopologyModule::Triangle> indices,
67 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
69 if (tId >= indices.size()) return;
71 int ni = counter.nx();
72 int nj = counter.ny();
73 int nk = counter.nz();
75 auto t = indices[tId];
77 Coord vp = vertices[t[0]];
78 Coord vq = vertices[t[1]];
79 Coord vr = vertices[t[2]];
81 // coordinates in grid to high precision
82 Real fip = (vp[0] - origin[0]) / dx;
83 Real fjp = (vp[1] - origin[1]) / dx;
84 Real fkp = (vp[2] - origin[2]) / dx;
85 Real fiq = (vq[0] - origin[0]) / dx;
86 Real fjq = (vq[1] - origin[1]) / dx;
87 Real fkq = (vq[2] - origin[2]) / dx;
88 Real fir = (vr[0] - origin[0]) / dx;
89 Real fjr = (vr[1] - origin[1]) / dx;
90 Real fkr = (vr[2] - origin[2]) / dx;
92 // do distances nearby
93 const int exact_band = 1;
95 int i0 = glm::clamp(int(TRI_MIN(fip, fiq, fir)) - exact_band, 0, ni - 1);
96 int i1 = glm::clamp(int(TRI_MAX(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
97 int j0 = glm::clamp(int(TRI_MIN(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
98 int j1 = glm::clamp(int(TRI_MAX(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
99 int k0 = glm::clamp(int(TRI_MIN(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
100 int k1 = glm::clamp(int(TRI_MAX(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);
102 TTriangle3D<Real> tri(vp, vq, vr);
103 for (int k = k0; k <= k1; ++k) for (int j = j0; j <= j1; ++j) for (int i = i0; i <= i1; ++i) {
104 TPoint3D<Real> point(origin + Coord(i * dx, j * dx, k * dx));
105 if (glm::abs(point.distance(tri)) < dx * 1.74) //1.74 is chosen to be slightly larger than sqrt(3)
107 atomicAdd(&counter(i, j, k), 1);
112 template<typename Real, typename Coord>
113 __global__ void FSM_StoreTriangleIds(
114 DArrayList<uint> triIds,
115 DArray3D<uint> counter,
116 DArray<Coord> vertices,
117 DArray<TopologyModule::Triangle> indices,
121 int tId = threadIdx.x + (blockIdx.x * blockDim.x);
123 if (tId >= indices.size()) return;
125 int ni = counter.nx();
126 int nj = counter.ny();
127 int nk = counter.nz();
129 auto t = indices[tId];
131 Coord vp = vertices[t[0]];
132 Coord vq = vertices[t[1]];
133 Coord vr = vertices[t[2]];
135 // coordinates in grid to high precision
136 Real fip = (vp[0] - origin[0]) / dx;
137 Real fjp = (vp[1] - origin[1]) / dx;
138 Real fkp = (vp[2] - origin[2]) / dx;
139 Real fiq = (vq[0] - origin[0]) / dx;
140 Real fjq = (vq[1] - origin[1]) / dx;
141 Real fkq = (vq[2] - origin[2]) / dx;
142 Real fir = (vr[0] - origin[0]) / dx;
143 Real fjr = (vr[1] - origin[1]) / dx;
144 Real fkr = (vr[2] - origin[2]) / dx;
146 // do distances nearby
147 const int exact_band = 1;
149 int i0 = glm::clamp(int(TRI_MIN(fip, fiq, fir)) - exact_band, 0, ni - 1);
150 int i1 = glm::clamp(int(TRI_MAX(fip, fiq, fir)) + exact_band + 1, 0, ni - 1);
151 int j0 = glm::clamp(int(TRI_MIN(fjp, fjq, fjr)) - exact_band, 0, nj - 1);
152 int j1 = glm::clamp(int(TRI_MAX(fjp, fjq, fjr)) + exact_band + 1, 0, nj - 1);
153 int k0 = glm::clamp(int(TRI_MIN(fkp, fkq, fkr)) - exact_band, 0, nk - 1);
154 int k1 = glm::clamp(int(TRI_MAX(fkp, fkq, fkr)) + exact_band + 1, 0, nk - 1);
156 TTriangle3D<Real> tri(vp, vq, vr);
157 for (int k = k0; k <= k1; ++k) for (int j = j0; j <= j1; ++j) for (int i = i0; i <= i1; ++i) {
158 TPoint3D<Real> point(origin + Coord(i * dx, j * dx, k * dx));
159 if (glm::abs(point.distance(tri)) < dx * 1.74) //1.74 is chosen to be slightly larger than sqrt(3)
161 triIds[counter.index(i, j, k)].atomicInsert(tId);
166 __global__ void FSM_Array3D_To_Array1d(
168 DArray3D<uint> arr3d)
170 int i = threadIdx.x + (blockIdx.x * blockDim.x);
171 int j = threadIdx.y + (blockIdx.y * blockDim.y);
172 int k = threadIdx.z + (blockIdx.z * blockDim.z);
174 uint nx = arr3d.nx();
175 uint ny = arr3d.ny();
176 uint nz = arr3d.nz();
178 if (i >= nx || j >= ny || k >= nz) return;
180 uint index1d = arr3d.index(i, j, k);
182 arr1d[index1d] = arr3d(i, j, k);
185 template<typename Real, typename Coord, typename Tri2Edg>
186 __global__ void FSM_InitializeSDFNearMesh(
188 DArray3D<int> closestId,
189 DArray3D<GridType> gridType,
190 DArrayList<uint> triIds,
191 DArray<Coord> vertices,
192 DArray<TopologyModule::Triangle> indices,
193 DArray<TopologyModule::Edge> edges,
196 DArray<Coord> vertexN,
200 int i = threadIdx.x + (blockIdx.x * blockDim.x);
201 int j = threadIdx.y + (blockIdx.y * blockDim.y);
202 int k = threadIdx.z + (blockIdx.z * blockDim.z);
208 if (i >= nx || j >= ny || k >= nz) return;
210 Coord gx(i * dx + origin[0], j * dx + origin[1], k * dx + origin[2]);
212 auto& list = triIds[phi.index(i, j, k)];
216 ProjectedPoint3D<Real> p3d;
218 bool valid = calculateSignedDistance2TriangleSetFromNormal(p3d, gx, vertices, edges, indices, t2e, edgeN, vertexN, list);
220 phi(i, j, k) = p3d.signed_distance;
221 closestId(i, j, k) = p3d.id;
222 gridType(i, j, k) = GridType::Accepted;
227 template<typename Real, typename Coord>
228 GPU_FUNC void FSM_CheckNeighbour(
230 DArray3D<int>& closest_tri,
231 const DArray<Coord>& vert,
232 const DArray<TopologyModule::Triangle>& tri,
234 int i0, int j0, int k0,
235 int i1, int j1, int k1)
237 if (closest_tri(i1, j1, k1) >= 0) {
238 unsigned int p, q, r;
239 auto trijk = tri[closest_tri(i1, j1, k1)];
244 auto t = TTriangle3D<Real>(vert[p], vert[q], vert[r]);
245 Real d = TPoint3D<Real>(gx).distance(t);
247 Real phi0 = phi(i0, j0, k0);
248 Real phi1 = phi(i1, j1, k1);
250 if (glm::abs(d) < glm::abs(phi0)) {
251 phi(i0, j0, k0) = phi1 > 0 ? glm::abs(d) : -glm::abs(d);
252 closest_tri(i0, j0, k0) = closest_tri(i1, j1, k1);
257 template<typename Real, typename Coord>
258 __global__ void FSM_SweepX(
260 DArray3D<int> closestId,
261 DArray3D<GridType> gridType,
262 DArray<Coord> vertices,
263 DArray<TopologyModule::Triangle> indices,
268 int j = threadIdx.x + (blockIdx.x * blockDim.x);
269 int k = threadIdx.y + (blockIdx.y * blockDim.y);
274 if (j >= ny || k >= nz) return;
276 int i0 = di > 0 ? 1 : phi.nx() - 2;
277 int i1 = di > 0 ? phi.nx() : -1;
279 for (int i = i0; i != i1; i += di) {
280 if (gridType(i, j, k) != GridType::Accepted)
282 Coord gx(i * dx + origin[0], j * dx + origin[1], k * dx + origin[2]);
283 FSM_CheckNeighbour(phi, closestId, vertices, indices, gx, i, j, k, i - di, j, k);
288 template<typename Real, typename Coord>
289 __global__ void FSM_SweepY(
291 DArray3D<int> closestId,
292 DArray3D<GridType> gridType,
293 DArray<Coord> vertices,
294 DArray<TopologyModule::Triangle> indices,
299 int i = threadIdx.x + (blockIdx.x * blockDim.x);
300 int k = threadIdx.y + (blockIdx.y * blockDim.y);
305 if (i >= nx || k >= nz) return;
307 int j0 = dj > 0 ? 1 : phi.ny() - 2;
308 int j1 = dj > 0 ? phi.ny() : -1;
310 for (int j = j0; j != j1; j += dj) {
311 if (gridType(i, j, k) != GridType::Accepted)
313 Coord gx(i * dx + origin[0], j * dx + origin[1], k * dx + origin[2]);
314 FSM_CheckNeighbour(phi, closestId, vertices, indices, gx, i, j, k, i, j - dj, k);
319 template<typename Real, typename Coord>
320 __global__ void FSM_SweepZ(
322 DArray3D<int> closestId,
323 DArray3D<GridType> gridType,
324 DArray<Coord> vertices,
325 DArray<TopologyModule::Triangle> indices,
330 int i = threadIdx.x + (blockIdx.x * blockDim.x);
331 int j = threadIdx.y + (blockIdx.y * blockDim.y);
336 if (i >= nx || j >= ny) return;
338 int k0 = dk > 0 ? 1 : phi.nz() - 2;
339 int k1 = dk > 0 ? phi.nz() : -1;
341 for (int k = k0; k != k1; k += dk) {
342 if (gridType(i, j, k) != GridType::Accepted)
344 Coord gx(i * dx + origin[0], j * dx + origin[1], k * dx + origin[2]);
345 FSM_CheckNeighbour(phi, closestId, vertices, indices, gx, i, j, k, i, j, k - dk);
350 template<typename TDataType>
351 void FastSweepingMethodGPU<TDataType>::makeLevelSet()
353 if (this->outLevelSet()->isEmpty()) {
354 this->outLevelSet()->allocate();
357 DistanceField3D<TDataType>& sdf = this->outLevelSet()->getDataPtr()->getSDF();
359 auto ts = this->inTriangleSet()->constDataPtr();
361 DArray<Coord> edgeNormal, vertexNormal;
362 ts->updateEdgeNormal(edgeNormal);
363 ts->updateAngleWeightedVertexNormal(vertexNormal);
365 ts->updateTriangle2Edge();
366 auto& tri2edg = ts->getTriangle2Edge();
368 auto& vertices = ts->getPoints();
369 auto& edges = ts->getEdges();
370 auto& triangles = ts->getTriangles();
372 Reduction<Coord> reduce;
373 Coord min_box = reduce.minimum(vertices.begin(), vertices.size());
374 Coord max_box = reduce.maximum(vertices.begin(), vertices.size());
376 Real dx = this->varSpacing()->getValue();
377 uint padding = this->varPadding()->getValue();
380 min_box -= padding * dx * unit;
381 max_box += padding * dx * unit;
386 sdf.setSpace(min_box, max_box, dx);
387 auto& phi = sdf.distances();
393 //initialize distances near the mesh
394 DArray3D<uint> counter3d(ni, nj, nk);
395 DArray<uint> counter1d(ni * nj * nk);
398 DArray3D<GridType> gridType(ni, nj, nk);
399 DArray3D<int> closestTriId(ni, nj, nk);
401 cuExecute3D(make_uint3(ni, nj, nk),
407 cuExecute(triangles.size(),
408 FSM_FindNeighboringGrids,
415 cuExecute3D(make_uint3(ni, nj, nk),
416 FSM_Array3D_To_Array1d,
420 DArrayList<uint> neighbors;
421 neighbors.resize(counter1d);
423 cuExecute(triangles.size(),
424 FSM_StoreTriangleIds,
432 cuExecute3D(make_uint3(ni, nj, nk),
433 FSM_InitializeSDFNearMesh,
447 // fill in the rest of the distances with fast sweeping
448 uint passMax = this->varPassNumber()->getValue();
449 for (unsigned int pass = 0; pass < passMax; ++pass) {
452 cuExecute2D(make_uint2(nj, nk),
464 cuExecute2D(make_uint2(nj, nk),
476 cuExecute2D(make_uint2(ni, nk),
488 cuExecute2D(make_uint2(ni, nk),
500 cuExecute2D(make_uint2(ni, nj),
512 cuExecute2D(make_uint2(ni, nj),
529 vertexNormal.clear();
532 DEFINE_CLASS(FastSweepingMethodGPU);