Skip to content

Commit e91a709

Browse files
authored
fix VolumeGrid isosurface indexing bug with non-uniform dimensions (#378)
* add failing test for bug * fix volume grid isosurface indexing bug
1 parent 25e27b9 commit e91a709

File tree

2 files changed

+73
-25
lines changed

2 files changed

+73
-25
lines changed

src/volume_grid_scalar_quantity.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ void VolumeGridNodeScalarQuantity::createIsosurfaceProgram() {
165165

166166
// Extract the isosurface from the level set of the scalar field
167167
MC::mcMesh isosurfaceMesh;
168-
MC::marching_cube(&values.data.front(), isosurfaceLevel.get(), parent.getGridNodeDim().x, parent.getGridNodeDim().y,
169-
parent.getGridNodeDim().z, isosurfaceMesh);
168+
MC::marching_cube(&values.data.front(), isosurfaceLevel.get(), parent.getGridNodeDim().z, parent.getGridNodeDim().y,
169+
parent.getGridNodeDim().x, isosurfaceMesh);
170170

171171
// Transform the result to be aligned with our volume's spatial layout
172172
glm::vec3 scale = parent.gridSpacing();
@@ -215,8 +215,8 @@ SurfaceMesh* VolumeGridNodeScalarQuantity::registerIsosurfaceAsMesh(std::string
215215

216216
// extract the mesh
217217
MC::mcMesh isosurfaceMesh;
218-
MC::marching_cube(&values.data.front(), isosurfaceLevel.get(), parent.getGridNodeDim().x, parent.getGridNodeDim().y,
219-
parent.getGridNodeDim().z, isosurfaceMesh);
218+
MC::marching_cube(&values.data.front(), isosurfaceLevel.get(), parent.getGridNodeDim().z, parent.getGridNodeDim().y,
219+
parent.getGridNodeDim().x, isosurfaceMesh);
220220
glm::vec3 scale = parent.gridSpacing();
221221
for (auto& p : isosurfaceMesh.vertices) {
222222
// swizzle to account for change of coordinate/buffer ordering in the MC lib

test/src/volume_grid_test.cpp

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
// ============================================================
1010

1111
TEST_F(PolyscopeTest, ShowVolumeGrid) {
12-
// clang-format off
1312
uint32_t dimX = 8;
1413
uint32_t dimY = 10;
1514
uint32_t dimZ = 12;
@@ -19,7 +18,7 @@ TEST_F(PolyscopeTest, ShowVolumeGrid) {
1918
polyscope::VolumeGrid* psGrid = polyscope::registerVolumeGrid("test grid", {dimX, dimY, dimZ}, bound_low, bound_high);
2019

2120
polyscope::show(3);
22-
21+
2322
EXPECT_TRUE(polyscope::hasVolumeGrid("test grid"));
2423
EXPECT_FALSE(polyscope::hasVolumeGrid("other grid"));
2524
polyscope::removeAllStructures();
@@ -28,7 +27,7 @@ TEST_F(PolyscopeTest, ShowVolumeGrid) {
2827

2928

3029
TEST_F(PolyscopeTest, VolumeGridBasicOptions) {
31-
30+
3231
// these are node dim
3332
uint32_t dimX = 8;
3433
uint32_t dimY = 10;
@@ -38,8 +37,8 @@ TEST_F(PolyscopeTest, VolumeGridBasicOptions) {
3837

3938
polyscope::VolumeGrid* psGrid = polyscope::registerVolumeGrid("test grid", {dimX, dimY, dimZ}, bound_low, bound_high);
4039

41-
EXPECT_EQ(psGrid->nNodes(), dimX*dimY*dimZ);
42-
EXPECT_EQ(psGrid->nCells(), (dimX-1)*(dimY-1)*(dimZ-1));
40+
EXPECT_EQ(psGrid->nNodes(), dimX * dimY * dimZ);
41+
EXPECT_EQ(psGrid->nCells(), (dimX - 1) * (dimY - 1) * (dimZ - 1));
4342

4443
// Material
4544
psGrid->setMaterial("flat");
@@ -49,7 +48,7 @@ TEST_F(PolyscopeTest, VolumeGridBasicOptions) {
4948
// Edge width
5049
psGrid->setEdgeWidth(0.5);
5150
polyscope::show(3);
52-
51+
5352
// Grid size factor
5453
psGrid->setCubeSizeFactor(0.5);
5554
polyscope::show(3);
@@ -58,15 +57,14 @@ TEST_F(PolyscopeTest, VolumeGridBasicOptions) {
5857
}
5958

6059
TEST_F(PolyscopeTest, VolumeGridOrthographicRendering) {
61-
// clang-format off
6260
uint32_t dimX = 8;
6361
uint32_t dimY = 10;
6462
uint32_t dimZ = 12;
6563
glm::vec3 bound_low{-3., -3., -3.};
6664
glm::vec3 bound_high{3., 3., 3.};
6765

6866
polyscope::VolumeGrid* psGrid = polyscope::registerVolumeGrid("test grid", {dimX, dimY, dimZ}, bound_low, bound_high);
69-
67+
7068
// try orthographic rendering
7169
polyscope::view::setProjectionMode(polyscope::ProjectionMode::Orthographic);
7270
polyscope::show(3);
@@ -75,7 +73,7 @@ TEST_F(PolyscopeTest, VolumeGridOrthographicRendering) {
7573
}
7674

7775
TEST_F(PolyscopeTest, VolumeGridSlicePlane) {
78-
76+
7977
// these are node dim
8078
uint32_t dimX = 8;
8179
uint32_t dimY = 10;
@@ -87,20 +85,21 @@ TEST_F(PolyscopeTest, VolumeGridSlicePlane) {
8785

8886
// plain old inspecting
8987
polyscope::SlicePlane* p = polyscope::addSceneSlicePlane();
90-
psGrid->setCullWholeElements(true);
88+
psGrid->setCullWholeElements(true);
9189
polyscope::show(3);
92-
90+
9391
// cull whole elements
94-
// we don't actually support rendering like this yet, so right now this is 'handled' by automatically unsetting it internally
95-
psGrid->setCullWholeElements(false);
92+
// we don't actually support rendering like this yet, so right now this is 'handled' by automatically unsetting it
93+
// internally
94+
psGrid->setCullWholeElements(false);
9695
polyscope::show(3);
9796

9897
polyscope::removeLastSceneSlicePlane();
9998
polyscope::removeAllStructures();
10099
}
101100

102101
TEST_F(PolyscopeTest, VolumeGridScalar) {
103-
102+
104103
// these are node dim
105104
uint32_t dimX = 8;
106105
uint32_t dimY = 10;
@@ -126,19 +125,19 @@ TEST_F(PolyscopeTest, VolumeGridScalar) {
126125
psGrid->addNodeScalarQuantity("node scalar1", nodeScalar)->setEnabled(true);
127126
polyscope::show(3);
128127
}
129-
128+
130129
{ // node scalar from callable
131130
// internally this bootstraps off the batch version, so we're kinda testing it too
132131
psGrid->addNodeScalarQuantityFromCallable("node scalar2", torusSDF)->setEnabled(true);
133132
polyscope::show(3);
134133
}
135-
134+
136135
{ // cell scalar from array
137136
std::vector<double> cellScalar(psGrid->nCells(), 3.0f);
138137
psGrid->addCellScalarQuantity("cell scalar1", cellScalar)->setEnabled(true);
139138
polyscope::show(3);
140139
}
141-
140+
142141
{ // cell scalar from callable
143142
// internally this bootstraps off the batch version, so we're kinda testing it too
144143
psGrid->addCellScalarQuantityFromCallable("cell scalar2", torusSDF)->setEnabled(true);
@@ -149,7 +148,7 @@ TEST_F(PolyscopeTest, VolumeGridScalar) {
149148
}
150149

151150
TEST_F(PolyscopeTest, VolumeGridScalarIsosurfaceAndOpts) {
152-
151+
153152
// these are node dim
154153
uint32_t dimX = 8;
155154
uint32_t dimY = 10;
@@ -177,14 +176,14 @@ TEST_F(PolyscopeTest, VolumeGridScalarIsosurfaceAndOpts) {
177176

178177
q->setGridcubeVizEnabled(false);
179178
polyscope::show(3);
180-
179+
181180
q->setIsosurfaceVizEnabled(true); // extracts the isosurface
182181
polyscope::show(3);
183-
182+
184183
polyscope::SlicePlane* p = polyscope::addSceneSlicePlane();
185184
polyscope::show(3);
186185

187-
q->setSlicePlanesAffectIsosurface(true);
186+
q->setSlicePlanesAffectIsosurface(true);
188187
polyscope::show(3);
189188

190189
q->registerIsosurfaceAsMesh();
@@ -198,3 +197,52 @@ TEST_F(PolyscopeTest, VolumeGridScalarIsosurfaceAndOpts) {
198197
polyscope::removeLastSceneSlicePlane();
199198
polyscope::removeAllStructures();
200199
}
200+
201+
TEST_F(PolyscopeTest, VolumeGridScalarIsosurfaceIndexing) {
202+
203+
std::vector<std::array<int32_t, 3>> perms{{0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0}};
204+
205+
std::array<uint32_t, 3> dims = {5, 8, 20};
206+
207+
// these are node dim
208+
glm::vec3 bound_low{-10., -2., -5.};
209+
glm::vec3 bound_high{20., 3., 6.};
210+
211+
for (auto& perm : perms) {
212+
uint32_t dimX = dims[perm[0]];
213+
uint32_t dimY = dims[perm[1]];
214+
uint32_t dimZ = dims[perm[2]];
215+
216+
polyscope::VolumeGrid* psGrid =
217+
polyscope::registerVolumeGrid("test grid", {dimX, dimY, dimZ}, bound_low, bound_high);
218+
219+
std::vector<float> vals(dimX * dimY * dimZ, 0.f);
220+
for (uint32_t iX = 0; iX < dimX; iX++) {
221+
for (uint32_t iY = 0; iY < dimY; iY++) {
222+
for (uint32_t iZ = 0; iZ < dimZ; iZ++) {
223+
vals[iX * (dimY * dimZ) + iY * dimZ + iZ] = ((iX + iY + iZ) % 2) - 0.5; // checkerboard function
224+
}
225+
}
226+
}
227+
228+
polyscope::VolumeGridNodeScalarQuantity* q = psGrid->addNodeScalarQuantity("node scalar", vals);
229+
q->setIsosurfaceVizEnabled(true); // extracts the isosurface
230+
q->registerIsosurfaceAsMesh("iso test");
231+
232+
// get the vertices from the is surface
233+
polyscope::SurfaceMesh* isoTest = polyscope::getSurfaceMesh("iso test");
234+
isoTest->vertexPositions.ensureHostBufferPopulated();
235+
std::vector<glm::vec3> isoverts = isoTest->vertexPositions.data;
236+
237+
// test that all vertices are within the bounds
238+
float EPS = 0.0001;
239+
for (glm::vec3 p : isoverts) {
240+
for (int i = 0; i < 3; i++) {
241+
EXPECT_GE(p[i], bound_low[i] - EPS);
242+
EXPECT_LT(p[i], bound_high[i] + EPS);
243+
}
244+
}
245+
246+
polyscope::removeAllStructures();
247+
}
248+
}

0 commit comments

Comments
 (0)