PeriDyno 1.0.0
Loading...
Searching...
No Matches
SdfSampler.cu
Go to the documentation of this file.
1#include "SdfSampler.h"
2#include "Topology/LevelSet.h"
3#include <thrust/scan.h>
4#include <thrust/execution_policy.h>
5
6#include "Matrix.h"
7namespace dyno
8{
9 IMPLEMENT_TCLASS(SdfSampler, TDataType)
10
11 __global__ void C_PointCount(
12 DArray3D<int> distance,
13 DArray<int> VerticesFlag)
14 {
15 uint i = threadIdx.x + blockDim.x * blockIdx.x;
16 uint j = threadIdx.y + blockDim.y * blockIdx.y;
17 uint k = threadIdx.z + blockDim.z * blockIdx.z;
18
19 uint nx = distance.nx();
20 uint ny = distance.ny();
21 uint nz = distance.nz();
22
23 if (i >= nx || j >= ny || k >= nz) return;
24 uint tId = i + j * nx + k * ny * nx;
25 //hexahedronFlag[tId] = 0;
26
27 if (i >= nx - 1 || j >= ny - 1 || k >= nz - 1) return;
28
29
30 if (distance(i, j, k) == 1 &&
31 distance(i + 1, j, k) == 1 &&
32
33 distance(i + 1, j + 1, k) == 1 &&
34 distance(i, j + 1, k) == 1 &&
35
36 distance(i, j, k + 1) == 1 &&
37 distance(i + 1, j, k + 1) == 1 &&
38
39 distance(i + 1, j + 1, k + 1) == 1 &&
40 distance(i, j + 1, k + 1) == 1) {
41
42 uint index1 = distance.index(i, j, k);
43 uint index2 = distance.index(i + 1, j, k);
44
45 uint index3 = distance.index(i + 1, j + 1, k);
46 uint index4 = distance.index(i, j + 1, k);
47
48 uint index5 = distance.index(i, j, k + 1);
49 uint index6 = distance.index(i + 1, j, k + 1);
50
51 uint index7 = distance.index(i + 1, j + 1, k + 1);
52 uint index8 = distance.index(i, j + 1, k + 1);
53
54 atomicExch(&VerticesFlag[index1], 1);
55 atomicExch(&VerticesFlag[index2], 1);
56 atomicExch(&VerticesFlag[index3], 1);
57 atomicExch(&VerticesFlag[index4], 1);
58 atomicExch(&VerticesFlag[index5], 1);
59 atomicExch(&VerticesFlag[index6], 1);
60 atomicExch(&VerticesFlag[index7], 1);
61 atomicExch(&VerticesFlag[index8], 1);
62 }
63 }
64 template<typename Coord>
65 __global__ void C_CalculatePoints(
66 DArray<Coord> vertices,
67 DArray<Coord> allVertices,
68 DArray<int> VerticesFlag,
69 DArray<int> VerticesFlagScan)
70 {
71 int pId = threadIdx.x + (blockIdx.x * blockDim.x);
72 if (pId >= allVertices.size()) return;
73
74 if (VerticesFlag[pId] == 1) {
75 vertices[VerticesFlagScan[pId] - 1] = allVertices[pId];
76 }
77 }
78
79 template<typename TDataType, typename Real, typename Coord>
80 __global__ void C_reconstructSDF(
81 DistanceField3D<TDataType> inputSDF,
82 DArray3D<int> distance,
83 Coord minPoint,
84 DArray<Coord> vertices,
85 Real dx,
86 Vec3f cubeTilt,
87 DArray<int> VerticesFlag,
88 Mat3f cubeRotation,
89 Mat3f Rotation)
90 {
91 int i = threadIdx.x + (blockIdx.x * blockDim.x);
92 int j = threadIdx.y + (blockIdx.y * blockDim.y);
93 int k = threadIdx.z + (blockIdx.z * blockDim.z);
94
95 uint nx = distance.nx();
96 uint ny = distance.ny();
97 uint nz = distance.nz();
98
99 if (i >= nx || j >= ny || k >= nz) return;
100 distance(i, j, k) = 0;
101 VerticesFlag[i + j * nx + k * nx * ny] = 0;
102
103 float theta = (90.0f - cubeTilt[0]) / 180.0f * M_PI;
104 float phi = (90.0f - cubeTilt[1]) / 180.0f * M_PI;
105 float psi = (90.0f - cubeTilt[2]) / 180.0f * M_PI;
106
107
108 Coord point = minPoint + Coord(i * dx, j * dx, k * dx);
109
110 Real a;
111 Coord normal;
112 inputSDF.getDistance(point, a, normal);
113
114 if (a <= 0) {
115 atomicExch(&distance(i, j, k), 1);
116 }
117
118
119
120 point = minPoint + Coord(i * dx + (j * dx) / tan(theta),
121 j * dx + (i * dx) / tan(phi), k * dx + (j * dx) / tan(psi));
122 vertices[i + j * nx + k * nx * ny] = Rotation * cubeRotation * point;
123 }
124
125 template<typename TDataType>
126 SdfSampler<TDataType>::SdfSampler()
127 : Sampler<TDataType>()
128 {
129 this->varSpacing()->setRange(0.02, 1);
130 this->varCubeTilt()->setRange(0, 80);
131 this->varX()->setRange(0.001, 5);
132 this->varY()->setRange(0.001, 5);
133 this->varZ()->setRange(0.001, 5);
134
135 this->varAlpha()->setRange(0, 360);
136 this->varBeta()->setRange(0, 360);
137 this->varGamma()->setRange(0, 360);
138
139 this->statePointSet()->promoteOuput();
140 }
141
142 template<typename TDataType>
143 SdfSampler<TDataType>::~SdfSampler()
144 {
145
146 }
147
148 template<typename Real, typename Coord>
149 __global__ void VS_SetupNodes(
150 DArray<Coord> nodes,
151 DArray3D<Real> distances,
152 Coord origin,
153 Real h)
154 {
155 uint i = threadIdx.x + blockDim.x * blockIdx.x;
156 uint j = threadIdx.y + blockDim.y * blockIdx.y;
157 uint k = threadIdx.z + blockDim.z * blockIdx.z;
158
159 uint nx = distances.nx();
160 uint ny = distances.ny();
161 uint nz = distances.nz();
162
163 if (i >= nx || j >= ny || k >= nz) return;
164
165 Coord p = origin + h * Coord(i, j, k);
166 nodes[distances.index(i, j, k)] = p;
167 }
168
169
170 template<typename Real>
171 __global__ void VS_SetupSDFValues(
172 DArray3D<Real> values,
173 DArray<Real> distances)
174 {
175 uint i = threadIdx.x + blockDim.x * blockIdx.x;
176 uint j = threadIdx.y + blockDim.y * blockIdx.y;
177 uint k = threadIdx.z + blockDim.z * blockIdx.z;
178
179 uint nx = values.nx();
180 uint ny = values.ny();
181 uint nz = values.nz();
182
183 if (i >= nx || j >= ny || k >= nz) return;
184
185 values(i, j, k) = distances[values.index(i, j, k)];
186 }
187
188 template<typename TDataType>
189 std::shared_ptr<dyno::DistanceField3D<TDataType>> SdfSampler<TDataType>::convert2Uniform(
190 VolumeOctree<TDataType>* volume,
191 Real h)
192 {
193 Coord lo = volume->lowerBound();
194 Coord hi = volume->upperBound();
195
196 int nx = (hi[0] - lo[0]) / h;
197 int ny = (hi[1] - lo[1]) / h;
198 int nz = (hi[2] - lo[2]) / h;
199
200 auto levelset = std::make_shared<DistanceField3D<TDataType>>();
201 levelset->setSpace(lo, hi, h);
202
203 auto& distances = levelset->distances();
204
205 DArray<Coord> nodes(distances.size());
206
207 cuExecute3D(make_uint3(distances.nx(), distances.ny(), distances.nz()),
208 VS_SetupNodes,
209 nodes,
210 distances,
211 lo,
212 h);
213
214 DArray<Real> sdfValues;
215 DArray<Coord> normals;
216
217 volume->stateSDFTopology()->constDataPtr()->getSignDistance(nodes, sdfValues, normals);
218
219 cuExecute3D(make_uint3(distances.nx(), distances.ny(), distances.nz()),
220 VS_SetupSDFValues,
221 distances,
222 sdfValues);
223
224 nodes.clear();
225 sdfValues.clear();
226 normals.clear();
227
228 return levelset;
229 }
230
231 template<typename TDataType>
232 void SdfSampler<TDataType>::resetStates()
233 {
234 auto vol = this->getVolume();
235 Real dx = this->varSpacing()->getData();
236
237 //Adaptive mesh to uniform mesh
238 auto inputSDF = this->convert2Uniform(vol, dx);
239
240
241 if (this->statePointSet()->isEmpty()) {
242 auto pts = std::make_shared<PointSet<TDataType>>();
243 this->statePointSet()->setDataPtr(pts);
244 }
245
246 Coord minPoint = inputSDF->lowerBound();
247 Coord maxPoint = inputSDF->upperBound();
248
249 Vec3f cubeTilt = this->varCubeTilt()->getData();
250 Vec3f Xax = this->varX()->getData();
251 Vec3f Yax = this->varY()->getData();
252 Vec3f Zax = this->varZ()->getData();
253 Mat3f cubeRotation(Xax, Yax, Zax);
254 cubeRotation = cubeRotation.transpose();
255
256 uint ni = std::floor((maxPoint[0] - minPoint[0]) / dx) + 1;
257 uint nj = std::floor((maxPoint[1] - minPoint[1]) / dx) + 1;
258 uint nk = std::floor((maxPoint[2] - minPoint[2]) / dx) + 1;
259
260 DArray3D<int> distance(ni + 1, nj + 1, nk + 1);
261 DArray<Coord> allVertices((ni + 1) * (nj + 1) * (nk + 1));
262 DArray<int> VerticesFlag((ni + 1) * (nj + 1) * (nk + 1));
263
264 float Alpha = this->varAlpha()->getData() / 180.0f * M_PI;
265 float Beta = this->varBeta()->getData() / 180.0f * M_PI;
266 float Gamma = this->varGamma()->getData() / 180.0f * M_PI;
267 Mat3f Rotation(cos(Alpha) * cos(Beta), cos(Alpha) * sin(Beta) * sin(Gamma) - sin(Alpha) * cos(Gamma), cos(Alpha) * sin(Beta) * cos(Gamma) + sin(Alpha) * sin(Gamma),
268 sin(Alpha) * cos(Beta), sin(Alpha) * sin(Beta) * sin(Gamma) + cos(Alpha) * cos(Gamma), sin(Alpha) * sin(Beta) * cos(Gamma) - cos(Alpha) * sin(Gamma),
269 -sin(Beta), cos(Beta) * sin(Gamma), cos(Beta) * cos(Gamma));
270
271 cuExecute3D(make_uint3(distance.nx(), distance.ny(), distance.nz()),
272 C_reconstructSDF,
273 *inputSDF,
274 distance,
275 minPoint,
276 allVertices,
277 dx,
278 cubeTilt,
279 VerticesFlag,
280 cubeRotation,
281 Rotation);
282
283 cuExecute3D(make_uint3(distance.nx(), distance.ny(), distance.nz()),
284 C_PointCount,
285 distance,
286 VerticesFlag);
287
288
289 CArray<int> CVerticesFlag;
290 CVerticesFlag.assign(VerticesFlag);
291
292 CArray3D<int> Cdistance;
293 Cdistance.assign(distance);
294
295 Reduction<int> reduce;
296 int verticesNum = reduce.accumulate(VerticesFlag.begin(), VerticesFlag.size());
297 DArray<Coord> vertices;
298 vertices.resize(verticesNum);
299 DArray<int> VerticesFlagScan;
300 VerticesFlagScan.assign(VerticesFlag);
301 thrust::inclusive_scan(thrust::device, VerticesFlagScan.begin(), VerticesFlagScan.begin() + VerticesFlagScan.size(), VerticesFlagScan.begin()); // in-place scan
302 cuExecute(allVertices.size(),
303 C_CalculatePoints,
304 vertices,
305 allVertices,
306 VerticesFlag,
307 VerticesFlagScan);
308
309 if (vertices.size() >= 0) {
310 auto topo = this->statePointSet()->getDataPtr();
311 topo->setPoints(vertices);
312 topo->update();
313 }
314 }
315
316 template<typename TDataType>
317 bool dyno::SdfSampler<TDataType>::validateInputs()
318 {
319 return this->getVolume() != nullptr;
320 }
321
322 DEFINE_CLASS(SdfSampler);
323}