Skip to content

Commit 603b10c

Browse files
committed
add sparse volume grid docs
1 parent 389d4cb commit 603b10c

12 files changed

Lines changed: 527 additions & 0 deletions

File tree

cpp/mkdocs.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ nav:
114114
- Volume Grid:
115115
- 'Basics' : 'structures/volume_grid/basics.md'
116116
- 'Scalar Quantities' : 'structures/volume_grid/scalar_quantities.md'
117+
- Sparse Volume Grid:
118+
- 'Basics' : 'structures/sparse_volume_grid/basics.md'
119+
- 'Scalar Quantities' : 'structures/sparse_volume_grid/scalar_quantities.md'
120+
- 'Color Quantities' : 'structures/sparse_volume_grid/color_quantities.md'
117121
- Camera View:
118122
- 'Basics' : 'structures/camera_view/basics.md'
119123
- Floating Quantities:
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Sparse Volume Grids
2+
3+
Sparse volume grid structures visualize data defined on a sparse subset of cells in an axis-aligned 3D grid. Unlike the dense [Volume Grid]([[url.prefix]]/structures/volume_grid/basics), a sparse volume grid only stores and renders the cells you specify, making it well-suited for adaptive grids, occupancy maps, and other data that occupies only a portion of a regular grid.
4+
5+
<video width=100% autoplay muted loop>
6+
<source src="[[url.prefix]]/media/sparse_volume_grid.mp4" type="video/mp4">
7+
Your browser does not support the video tag.
8+
</video>
9+
10+
As usual, first you register a sparse volume grid by specifying a grid origin, cell size, and list of occupied cells. Then you can add quantities such as scalar or color data defined per-cell or per-node.
11+
12+
**Example:** registering a sparse volume grid and adding a scalar quantity
13+
```cpp
14+
#include "polyscope/polyscope.h"
15+
#include "polyscope/sparse_volume_grid.h"
16+
17+
polyscope::init();
18+
19+
// define the grid parameters
20+
glm::vec3 origin{0., 0., 0.};
21+
glm::vec3 cellWidth{0.1, 0.1, 0.1};
22+
23+
// list of occupied cells by their integer grid indices
24+
std::vector<glm::ivec3> occupiedCells = {
25+
{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 0, 1},
26+
{1, 1, 0}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1},
27+
};
28+
29+
// register the grid
30+
polyscope::SparseVolumeGrid* psGrid = polyscope::registerSparseVolumeGrid(
31+
"sample sparse grid", origin, cellWidth, occupiedCells);
32+
33+
// add a scalar function on the grid (one value per cell)
34+
std::vector<float> cellScalars(occupiedCells.size());
35+
for (size_t i = 0; i < cellScalars.size(); i++) cellScalars[i] = static_cast<float>(i);
36+
37+
psGrid->addCellScalarQuantity("cell scalar", cellScalars);
38+
39+
polyscope::show();
40+
```
41+
42+
### Registering a sparse volume grid
43+
44+
!!! note "Origin and cell width"
45+
46+
The `origin` parameter specifies the position of the node/corner origin of the grid. Cell `(0,0,0)` has its lower-left corner at the origin. If you are thinking in terms of cell centers, shift the origin you pass in by half a cell width: `origin = cellCenter - 0.5 * cellWidth`.
47+
48+
The `cellWidth` parameter gives the size of each grid cell along each axis. All cells have the same size.
49+
50+
???+ func "`#!cpp polyscope::registerSparseVolumeGrid(std::string name, glm::vec3 origin, glm::vec3 gridCellWidth, const T& occupiedCells)`"
51+
52+
Add a new sparse volume grid structure to Polyscope.
53+
54+
- `name` the name of the structure
55+
- `origin` a `glm::vec3` giving the xyz position of the node/corner origin
56+
- `gridCellWidth` a `glm::vec3` giving the width of each cell along each axis
57+
- `occupiedCells` an array of `glm::ivec3` giving the integer grid indices of all occupied cells. The type should be [adaptable]([[url.prefix]]/data_adaptors) to an array of `glm::ivec3`.
58+
59+
60+
---
61+
62+
### Render modes
63+
64+
The sparse volume grid supports two render modes, controlled by `SparseVolumeGrid::setRenderMode()`:
65+
66+
- **`SparseVolumeGridRenderMode::Gridcube`** (default) renders each occupied cell as a filled cube. Quantities are visualized on the cube faces.
67+
- **`SparseVolumeGridRenderMode::Wireframe`** renders only the grid outline as wireframe edges. This mode is useful for seeing through the grid to inspect its structure. Quantities are not drawn in wireframe mode.
68+
69+
![sparse volume grid render modes]([[url.prefix]]/media/sparse_volume_render_modes.jpg)
70+
71+
The wireframe appearance can be adjusted with `SparseVolumeGrid::setWireframeRadius()` and `SparseVolumeGrid::setWireframeColor()`.
72+
73+
```cpp
74+
polyscope::SparseVolumeGrid* psGrid = polyscope::registerSparseVolumeGrid(
75+
"sample sparse grid", origin, cellWidth, occupiedCells);
76+
77+
psGrid->setRenderMode(SparseVolumeGridRenderMode::Wireframe);
78+
psGrid->setWireframeRadius(0.5);
79+
psGrid->setWireframeColor(glm::vec3{1.f, 0.f, 0.f});
80+
```
81+
82+
### Slice planes
83+
84+
As shown in the video above, [slice planes]([[url.prefix]]/features/slice_planes) are useful for inspecting the structure of a sparse volume grid. Slice planes can be manipulated programmatically or manually in the GUI; see the slice plane documentation for more details.
85+
86+
### Picking
87+
88+
"Picking" refers to selecting and inspecting elements by clicking on the object in the scene. Picking sparse volume grid elements works similarly to other structures, see [the overview of Selection / Picking]([[url.prefix]]/basics/interactive_UIs_and_animation/#picking-selection-and-querying-the-scene) for general information.
89+
90+
By default, only cells can be selected, until you have added some data on nodes. You can override this behavior by calling `SparseVolumeGrid::markNodesAsUsed()`, to act as if a node quantity had been added.
91+
92+
As with other structures, you can call `interpretPickResult()` to get additional info about a click.
93+
94+
```cpp
95+
struct SparseVolumeGridPickResult {
96+
SparseVolumeGridElement elementType; // which kind of element was clicked (enum values: {CELL, NODE})
97+
glm::ivec3 cellIndex; // integer grid index of the clicked cell (only populated if cell)
98+
uint64_t cellFlatIndex; // flat index into the occupied cells array (only populated if cell)
99+
glm::ivec3 nodeIndex; // integer grid index of the clicked node (only populated if node)
100+
};
101+
```
102+
103+
??? func "`#!cpp SparseVolumeGridPickResult SparseVolumeGrid::interpretPickResult(PickResult result)`"
104+
105+
Get additional information about a click, specific to this structure type (if it was the structure which was clicked on).
106+
107+
108+
### Options
109+
110+
See [structure management]([[url.prefix]]/structures/structure_management/#structure-options) for options common to all structures such as enabling/disabling, transforms, and transparency.
111+
112+
**Parameter** | **Meaning** | **Getter** | **Setter** | **Persistent?**
113+
--- | --- | --- | --- | ---
114+
color | the color of the volume | `#!cpp glm::vec3 getColor()` | `#!cpp setColor(glm::vec3 val)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
115+
edge width | how thick to draw mesh edges, use `0.` to disable and `1.` for reasonable edges | `#!cpp double getEdgeWidth()` | `#!cpp setEdgeWidth(double val)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
116+
edge color | the color of the grid edges | `#!cpp glm::vec3 getEdgeColor()` | `#!cpp setEdgeColor(glm::vec3 val)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
117+
cube size factor | shrink factor from 0-1 to draw gaps between cells, 0 is no shrink (default) | `#!cpp double getCubeSizeFactor()` | `#!cpp setCubeSizeFactor(double val)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
118+
material | what [material]([[url.prefix]]/features/materials) to use | `#!cpp std::string getMaterial()` | `#!cpp setMaterial(std::string name)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values) |
119+
render mode | how to render the voxels: `Gridcube` (default, filled cubes) or `Wireframe` (grid outline only) | `#!cpp SparseVolumeGridRenderMode getRenderMode()` | `#!cpp setRenderMode(SparseVolumeGridRenderMode mode)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
120+
wireframe radius | relative radius for wireframe spheres/cylinders; `1` means radius is half the smallest cell width | `#!cpp double getWireframeRadius()` | `#!cpp setWireframeRadius(double val)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
121+
wireframe color | color used for wireframe rendering | `#!cpp glm::vec3 getWireframeColor()` | `#!cpp setWireframeColor(glm::vec3 val)` | [yes]([[url.prefix]]/basics/parameters/#persistent-values)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
Visualize color data at the nodes or cells of a sparse volume grid.
2+
3+
![sparse volume grid color quantity]([[url.prefix]]/media/sparse_volume_color_quantity.jpg)
4+
5+
6+
**Example:** adding color quantities to a sparse volume grid
7+
```cpp
8+
#include "polyscope/polyscope.h"
9+
#include "polyscope/sparse_volume_grid.h"
10+
11+
polyscope::init();
12+
13+
glm::vec3 origin{0., 0., 0.};
14+
glm::vec3 cellWidth{0.1, 0.1, 0.1};
15+
16+
std::vector<glm::ivec3> occupiedCells = {
17+
{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0},
18+
};
19+
20+
polyscope::SparseVolumeGrid* psGrid = polyscope::registerSparseVolumeGrid(
21+
"sample sparse grid", origin, cellWidth, occupiedCells);
22+
23+
// === Cell color: one RGB color per occupied cell ===
24+
std::vector<glm::vec3> cellColors = {
25+
{1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {0.f, 0.f, 1.f}, {1.f, 1.f, 0.f},
26+
};
27+
psGrid->addCellColorQuantity("cell color", cellColors);
28+
29+
// === Node color: colors at node indices ===
30+
std::vector<glm::ivec3> nodeIndices = { /* all unique corner nodes */ };
31+
std::vector<glm::vec3> nodeColors = { /* one RGB color per node index */ };
32+
psGrid->addNodeColorQuantity("node color", nodeIndices, nodeColors);
33+
34+
polyscope::show();
35+
```
36+
37+
### Add cell colors
38+
39+
???+ func "`#!cpp SparseVolumeGridCellColorQuantity* SparseVolumeGrid::addCellColorQuantity(std::string name, const T& colors)`"
40+
41+
Add a color quantity defined at the cells of the grid.
42+
43+
- `name` the name of the quantity
44+
- `colors` an array of RGB colors, one per occupied cell in the same order as the `occupiedCells` array used at registration. The type should be [adaptable]([[url.prefix]]/data_adaptors) to an array of `glm::vec3`. Colors are RGB floats in `[0, 1]`.
45+
46+
47+
### Add node colors
48+
49+
???+ func "`#!cpp SparseVolumeGridNodeColorQuantity* SparseVolumeGrid::addNodeColorQuantity(std::string name, const TI& nodeIndices, const TC& nodeColors)`"
50+
51+
Add a color quantity defined at the nodes of the grid.
52+
53+
Node colors are passed as paired arrays of node indices and colors. For a cell with grid indices `(i, j, k)`, its corner nodes have indices `(i+dx, j+dy, k+dz)` for `dx, dy, dz` in `{0, 1}`. The node indices may be passed in any order, and extra entries (for nodes not required by any occupied cell) are ignored. However, all required node values must be present.
54+
55+
- `name` the name of the quantity
56+
- `nodeIndices` an array of `glm::ivec3` node grid indices. The type should be [adaptable]([[url.prefix]]/data_adaptors) to an array of `glm::ivec3`.
57+
- `nodeColors` an array of RGB colors, one per entry in `nodeIndices`. The type should be [adaptable]([[url.prefix]]/data_adaptors) to an array of `glm::vec3`. Colors are RGB floats in `[0, 1]`.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
Visualize scalar-valued data at the nodes or cells of a sparse volume grid.
2+
3+
![sparse volume grid scalar quantity]([[url.prefix]]/media/sparse_volume_scalar_quantity.jpg)
4+
5+
6+
**Example:** adding scalar quantities to a sparse volume grid
7+
```cpp
8+
#include "polyscope/polyscope.h"
9+
#include "polyscope/sparse_volume_grid.h"
10+
11+
polyscope::init();
12+
13+
glm::vec3 origin{0., 0., 0.};
14+
glm::vec3 cellWidth{0.1, 0.1, 0.1};
15+
16+
std::vector<glm::ivec3> occupiedCells = {
17+
{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0},
18+
};
19+
20+
polyscope::SparseVolumeGrid* psGrid = polyscope::registerSparseVolumeGrid(
21+
"sample sparse grid", origin, cellWidth, occupiedCells);
22+
23+
// === Cell scalar: one value per occupied cell ===
24+
std::vector<float> cellScalars = {0.1f, 0.5f, 0.9f, 0.3f};
25+
psGrid->addCellScalarQuantity("cell scalar", cellScalars);
26+
27+
// === Node scalar: values at node indices ===
28+
// For each cell (i,j,k), its corner nodes are (i+dx, j+dy, k+dz) for dx,dy,dz in {0,1}.
29+
// Collect all unique nodes and provide a value for each.
30+
std::vector<glm::ivec3> nodeIndices = { /* all unique corner nodes */ };
31+
std::vector<float> nodeValues = { /* one value per node index */ };
32+
psGrid->addNodeScalarQuantity("node scalar", nodeIndices, nodeValues);
33+
34+
polyscope::show();
35+
```
36+
37+
### Add cell scalars
38+
39+
???+ func "`#!cpp SparseVolumeGridCellScalarQuantity* SparseVolumeGrid::addCellScalarQuantity(std::string name, const T& values, DataType type = DataType::STANDARD)`"
40+
41+
Add a scalar quantity defined at the cells of the grid.
42+
43+
- `name` the name of the quantity
44+
- `values` a flat array of scalars, one per occupied cell in the same order as the `occupiedCells` array used at registration. The type should be [adaptable]([[url.prefix]]/data_adaptors) to a `float` scalar array.
45+
- `type` the [data type]([[url.prefix]]/features/data_types) of the scalar (standard, symmetric, magnitude, etc.)
46+
47+
48+
### Add node scalars
49+
50+
???+ func "`#!cpp SparseVolumeGridNodeScalarQuantity* SparseVolumeGrid::addNodeScalarQuantity(std::string name, const TI& nodeIndices, const TV& nodeValues, DataType type = DataType::STANDARD)`"
51+
52+
Add a scalar quantity defined at the nodes of the grid.
53+
54+
Node values are passed as paired arrays of node indices and values. For a cell with grid indices `(i, j, k)`, its corner nodes have indices `(i+dx, j+dy, k+dz)` for `dx, dy, dz` in `{0, 1}`. The node indices may be passed in any order, and extra entries (for nodes not required by any occupied cell) are ignored. However, all required node values must be present.
55+
56+
- `name` the name of the quantity
57+
- `nodeIndices` an array of `glm::ivec3` node grid indices. The type should be [adaptable]([[url.prefix]]/data_adaptors) to an array of `glm::ivec3`.
58+
- `nodeValues` a flat array of scalar values, one per entry in `nodeIndices`. The type should be [adaptable]([[url.prefix]]/data_adaptors) to a `float` scalar array.
59+
- `type` the [data type]([[url.prefix]]/features/data_types) of the scalar (standard, symmetric, magnitude, etc.)
60+
61+
62+
[[% include 'common/scalar_quantity.md' %]]

py/mkdocs.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ nav:
115115
- Volume Grid:
116116
- 'Basics' : 'structures/volume_grid/basics.md'
117117
- 'Scalar Quantities' : 'structures/volume_grid/scalar_quantities.md'
118+
- Sparse Volume Grid:
119+
- 'Basics' : 'structures/sparse_volume_grid/basics.md'
120+
- 'Scalar Quantities' : 'structures/sparse_volume_grid/scalar_quantities.md'
121+
- 'Color Quantities' : 'structures/sparse_volume_grid/color_quantities.md'
118122
- Camera View:
119123
- 'Basics' : 'structures/camera_view/basics.md'
120124
- Floating Quantities:

0 commit comments

Comments
 (0)