English | 中文 | Nederlands
ExplodedVolumes is a C++17/OpenGL application for interactive visualization of volumetric data. It loads NIfTI volume data, extracts an iso-surface with Marching Cubes, computes or selects an explosion axis, constructs cutting planes, separates the resulting components, and renders the result in both normal and exploded-view modes.
The project is designed as a source-only archive and as a course project of TU Eindhoven. Third-party headers and platform-specific binary libraries are intentionally not bundled. Before compiling, each user must reconstruct the local dependency folder using libraries that match their operating system, CPU architecture, and compiler toolchain.
- 1. Project Context
- 2. Results
- 3. Functional Overview
- 4. Methodological Pipeline
- 5. Source Tree
- 6. Dependency Model
- 7. Windows Build
- 8. macOS Build
- 9. Running the Application
- 10. Interaction Guide
- 11. VS Code Configuration Notes
- 12. Known Limitations
- 13. Third-Party Components and References
Many volumetric data sets contain internal structures that cannot be adequately understood from the exterior iso-surface alone. An exploded view addresses this limitation by cutting a surface into a sequence of components and translating those components along a chosen direction. The resulting visualization exposes hidden geometry while preserving the spatial relationship between the separated pieces.
In this implementation, the input is a scientific or medical volume stored in NIfTI format. The program extracts a triangulated iso-surface, estimates candidate explosion directions, creates cutting planes, separates the mesh into components, and renders the output in an interactive OpenGL viewer. The rendering style is intentionally edge-enhanced to improve surface readability.
Main window with Marching Cubes control panel, explosion axis settings, and explosion view controls
| Normal View | Exploded View |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Comparison between normal rendering (left) and exploded view (right) for multiple datasets
The current implementation provides the following functionality:
- loading
.niiNIfTI volume files through a native file dialog; - extracting triangulated iso-surfaces with Marching Cubes;
- rendering normal and exploded views in an OpenGL 3.3 Core profile context;
- estimating or selecting explosion axes using PCA-, symmetry-, and combined-strategy code paths;
- constructing cutting planes and separating the mesh into exploded components;
- interactively adjusting the iso-level and explosion distance;
- visualizing the explosion axis;
- rotating and zooming the camera;
- applying a framebuffer-based post-processing pass for edge-enhanced rendering;
- exposing runtime controls through Dear ImGui.
The implementation can be read as the following data-flow pipeline:
NIfTI volume
↓
VolumeData representation
↓
Marching Cubes iso-surface extraction
↓
Explosion-axis estimation or selection
↓
Cutting-plane generation and selection
↓
Surface segmentation
↓
Normal or exploded-view rendering
↓
Post-processing and ImGui overlay
The active rendering loop is located in main.cpp. Rendering and user-interface construction are implemented mainly in visual.cpp, while post-processing is handled by post_processor.cpp. Cutting-plane and exploded-view logic is implemented under planes/, and explosion-axis estimation is implemented under explosionaxis/.
A source-only copy of the project has the following approximate structure:
.
├── main.cpp # Program entry point and active render loop
├── data.cpp # NIfTI loading and volume utilities
├── marching_cubes.cpp # Marching Cubes iso-surface extraction
├── visual.cpp # GLFW/OpenGL/ImGui rendering and UI
├── post_processor.cpp # FBO-based post-processing pass
├── glad.c # GLAD OpenGL loader implementation
├── nifti1_io.c # NIfTI reader implementation
├── znzlib.c # NIfTI low-level file I/O helper
├── file_dialog.h # Wrapper around portable-file-dialogs
├── headers/
│ ├── data.h
│ ├── marching_cubes.h
│ ├── visual.h
│ ├── post_processor.h
│ ├── explosionaxis/ # Explosion-axis strategy headers
│ └── planes/ # Cutting-plane and exploded-view headers
├── explosionaxis/ # Explosion-axis strategy implementations
├── planes/ # Cutting-plane, selection, and exploded-view code
├── imgui/ # Dear ImGui implementation files used by the project
└── dependencies/ # Local dependency folder; reconstructed by the user
The dependencies/ directory is normally not committed. It should be created locally according to the platform-specific build instructions below.
This project is distributed as source code without third-party binary dependencies. This avoids shipping platform-specific libraries that may be incompatible with a different compiler, operating system, or CPU architecture.
In practice, this indicates:
- do not expect a pre-filled dependency folder in a clean source archive;
- reconstruct the dependency folder locally;
- use Windows libraries only for Windows builds;
- use macOS libraries only for macOS builds;
- do not mix binary artifacts from different operating systems, CPU architectures, or compiler toolchains.
The build commands in this README assume the following local layout. Equivalent paths can be used, but the include and library flags must then be adjusted accordingly.
dependencies/
├── include/
│ ├── GLFW/ # GLFW headers
│ ├── glad/ # glad.h
│ ├── KHR/ # khrplatform.h
│ ├── glm/ # GLM headers
│ ├── Eigen/ # Eigen headers, or use an external Eigen include path
│ ├── imgui.h
│ ├── imconfig.h
│ ├── imgui_internal.h
│ ├── imstb_rectpack.h
│ ├── imstb_textedit.h
│ ├── imstb_truetype.h
│ ├── imgui_impl_glfw.h
│ ├── imgui_impl_opengl3.h
│ ├── nifti1.h
│ ├── nifti1_io.h
│ ├── nifti1_io_version.h
│ ├── znzlib.h
│ ├── znzlib_version.h
│ └── portable-file-dialogs.h
└── library/
└── platform-specific libraries, such as GLFW and OpenMP runtimes
The following components are used by the application:
| Dependency | Role | Typical handling |
|---|---|---|
| C++17 compiler | Compiles the application | Clang, MinGW-w64, or MSVC |
| OpenGL 3.3 | Rendering backend | Provided by platform and graphics driver |
| GLFW | Window, OpenGL context, input | Header + platform-specific library |
| GLAD | OpenGL function loader | Compile glad.c; provide matching glad/ and KHR/ headers |
| Dear ImGui | Runtime GUI | Compile the bundled ImGui .cpp files; provide matching headers |
| GLM | Graphics mathematics | Header-only |
| Eigen | Linear algebra for axis estimation | Header-only |
| NIfTI C files | Volume loading | Compile nifti1_io.c and znzlib.c; provide matching headers |
| portable-file-dialogs | Native file dialog | Single header |
| OpenMP | Parallel CPU loops | Compiler flag and runtime library |
| zlib | Optional compressed NIfTI support | Link when HAVE_ZLIB is enabled or required by the local NIfTI configuration |
| PCL / VTK / Boost | Geometry and rendering support used by the current Makefile | Install with Homebrew on macOS |
Compiled libraries must match the target platform and compiler ABI.
| File type | Typical context |
|---|---|
.a |
Windows MinGW-w64 or compatible GCC-style toolchain |
.lib |
Windows MSVC |
.dll |
Windows runtime library |
.dylib |
macOS dynamic library |
.framework |
macOS system or framework dependency |
For example, MSVC should not link against MinGW .a files, and macOS .dylib files cannot be used in a Windows build. Apple Silicon builds require arm64-compatible dependencies; Intel macOS builds require x86_64-compatible dependencies.
Windows builds should use Windows-compatible headers and libraries only. Do not reuse macOS .dylib files, Homebrew paths, or macOS framework flags.
Create the local dependency directories:
mkdir dependencies
mkdir dependencies\include
mkdir dependencies\libraryPopulate dependencies\include with the headers listed in Section 6.2, and place the matching Windows GLFW/OpenMP runtime libraries under dependencies\library.
Run from the project root in PowerShell:
$Sources = @(
"glad.c", "znzlib.c", "nifti1_io.c",
"imgui\imgui.cpp", "imgui\imgui_draw.cpp", "imgui\imgui_impl_glfw.cpp",
"imgui\imgui_impl_opengl3.cpp", "imgui\imgui_tables.cpp", "imgui\imgui_widgets.cpp",
"explosionaxis\eigen_reflective_symmetry_detector.cpp",
"explosionaxis\eigen_rotational_symmetry_detector.cpp",
"explosionaxis\explosion_axis_strategy.cpp",
"explosionaxis\mitra_reflective_symmetry_detector.cpp",
"explosionaxis\mitra_rotational_symmetry_detector.cpp",
"explosionaxis\pca_analyzer.cpp",
"explosionaxis\pcl_reflective_symmetry_detector.cpp",
"explosionaxis\pcl_rotational_symmetry_detector.cpp",
"explosionaxis\vector_ops.cpp",
"planes\cutting_planes.cpp", "planes\exploded_view.cpp", "planes\selecting_planes.cpp",
"data.cpp", "main.cpp", "marching_cubes.cpp", "post_processor.cpp", "visual.cpp"
)
g++ -std=c++17 -O2 -g -fopenmp `
-I "dependencies\include" `
-I "headers" `
-I "headers\explosionaxis" `
-I "headers\planes" `
$Sources `
-L "dependencies\library" `
-lglfw3 -lopengl32 -lgdi32 -lole32 -lcomctl32 -loleaut32 -luuid `
-o explodedvolumes-mingw.exeIf the GLFW build is dynamic, copy the matching GLFW .dll next to the generated executable.
Run from an x64 Native Tools Command Prompt for Visual Studio, or another shell where cl.exe is configured:
set GLFW_LIB=C:\path\to\glfw\lib-vc2022
cl /std:c++17 /EHsc /O2 /openmp ^
/I dependencies\include ^
/I headers ^
/I headers\explosionaxis ^
/I headers\planes ^
glad.c znzlib.c nifti1_io.c ^
imgui\imgui.cpp imgui\imgui_draw.cpp imgui\imgui_impl_glfw.cpp ^
imgui\imgui_impl_opengl3.cpp imgui\imgui_tables.cpp imgui\imgui_widgets.cpp ^
explosionaxis\eigen_reflective_symmetry_detector.cpp ^
explosionaxis\eigen_rotational_symmetry_detector.cpp ^
explosionaxis\explosion_axis_strategy.cpp ^
explosionaxis\mitra_reflective_symmetry_detector.cpp ^
explosionaxis\mitra_rotational_symmetry_detector.cpp ^
explosionaxis\pca_analyzer.cpp ^
explosionaxis\pcl_reflective_symmetry_detector.cpp ^
explosionaxis\pcl_rotational_symmetry_detector.cpp ^
explosionaxis\vector_ops.cpp ^
planes\cutting_planes.cpp planes\exploded_view.cpp planes\selecting_planes.cpp ^
data.cpp main.cpp marching_cubes.cpp post_processor.cpp visual.cpp ^
/Fe:explodedvolumes-msvc.exe ^
/link /LIBPATH:%GLFW_LIB% glfw3.lib opengl32.lib gdi32.lib ole32.lib comctl32.lib oleaut32.lib uuid.lib user32.lib shell32.libIf the GLFW build is dynamic, copy the matching GLFW .dll next to explodedvolumes-msvc.exe.
The current build entry point is the root Makefile.
Install the Homebrew dependency set:
brew install glfw glm eigen boost pcl vtk libomp nlohmann-jsonPrepare the local dependency layout expected by the Makefile:
mkdir -p dependencies/include dependencies/library
ln -sf "$(brew --prefix glfw)/lib/libglfw.3.dylib" dependencies/library/libglfw.3.4.dylib
ln -sfn "$(brew --prefix vtk)" dependencies/VTK
ln -sfn "$(brew --prefix glm)/include/glm" dependencies/include/glm
ln -sfn "$(brew --prefix eigen)/include/eigen3/Eigen" dependencies/include/Eigen
ln -sfn "$(brew --prefix boost)/include/boost" dependencies/include/boostThe project-local headers listed in Section 6.2 must also be available under dependencies/include.
Build:
makeIf your PCL version differs from the Makefile default:
make PCL_VERSION=1.15.1For Intel macOS or a custom Homebrew prefix:
make BREW_PREFIX=/usr/localClean build outputs:
make cleanmacOS:
make runWindows MinGW:
.\explodedvolumes-mingw.exeWindows MSVC:
explodedvolumes-msvc.exeThe application opens a file dialog. Select a .nii volume file for which you have permission to use and, if applicable, redistribute. Public releases should not include private or identifiable medical data.
| Action | Control |
|---|---|
| Rotate camera | Left mouse drag |
| Zoom | Mouse wheel |
| Adjust camera distance | + / - |
| Close application | Esc |
| Change iso-level | ImGui Marching Cubes control panel |
| Toggle exploded view | ImGui Explosion View control panel |
| Adjust explosion distance | ImGui Explosion View control panel |
| Show or hide explosion axis | ImGui Explosion Axis Settings panel |
For macOS, create a VS Code build task named Build OpenGL that runs:
makeA launch configuration can use:
{
"program": "${workspaceFolder}/app",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build OpenGL"
}Use ${workspaceFolder} rather than ${fileDirname}. The latter changes depending on which file is currently focused in the editor and can lead to inconsistent build or runtime paths.
- The repository does not yet provide a cross-platform CMake configuration.
- The source-only distribution requires users to reconstruct third-party headers and platform-specific libraries locally.
- The current Makefile is macOS-oriented and version-sensitive when PCL or VTK paths change.
- The current file dialog focuses on
.niiinput. Additional work may be needed for convenient.nii.gzhandling. imgui.inimay be generated or updated by Dear ImGui to store UI layout. This is normal and does not indicate that input volume files have been modified.
Before compiling, check the availability of all third-party components used in the local build:
The visualization concept follows the general idea of exploded-view representations of complex surfaces, especially:
Olga Karpenko, Wilmot Li, Niloy Mitra, and Maneesh Agrawala. Exploded View Diagrams of Mathematical Surfaces. IEEE Transactions on Visualization and Computer Graphics, 16(6), 2010, 1311–1318. DOI:
10.1109/TVCG.2010.151.
The authors gratefully acknowledge M. Chamberland and H. van de Wetering for their guidance and valuable feedback during the development of this project.








