WIP
To run the editor in the docker container, the Dockerfile needs to contain:
EXPOSE 8080
ENV NVIDIA_DRIVER_CAPABILITIES compute,graphics,utility
RUN apt-get update \
&& apt-get install -y \
libxext6 \
libegl1Then run with the NVIDIA runtime selected (https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html):
docker run --runtime=nvidia --net=host --gpus=all ...- git
- C++ compiler
- CMake at least 3.25
- Python 3.x
- Vulkan runtime/loader:
- Windows: Vulkan Runtime (
vulkan-1) - Linux: system Vulkan loader/driver packages
- macOS: MoltenVK (or the macOS Vulkan SDK)
- Windows: Vulkan Runtime (
- NVIDIA Driver Version at least 550.0 (https://developer.nvidia.com/vulkan/video/get-started)
- Vulkan video at least 1.3.275.0 (checked during editor startup, prints out a message if the upgrade is needed)
- Download the latest Vulkan SDK from: https://vulkan.lunarg.com/sdk/home#linux
- Follow the instructions for manual installation in section
Install the SDK: https://vulkan.lunarg.com/doc/view/latest/linux/getting_started.html
VULKAN_SDK_VERSION="1.3.275.0"
cd ~
mkdir vulkan
cd vulkan
wget "https://sdk.lunarg.com/sdk/download/${VULKAN_SDK_VERSION}/linux/vulkansdk-linux-x86_64-${VULKAN_SDK_VERSION}.tar.xz"
tar xf "vulkansdk-linux-x86_64-${VULKAN_SDK_VERSION}.tar.xz"
echo "source ~/vulkan/${VULKAN_SDK_VERSION}/setup-env.sh" >> ~/.profile
. ~/.profile
# check the version
echo $VULKAN_SDK- vcpkg (recommended; required for Windows H.264 support)
pip install scikit-build wheel build numpy
For pytest:
pip install pytest parameterized
By default, editor is built with enabled NANOVDB_EDITOR_USE_GLFW which requires:
sudo apt-get install libgl1-mesa-devIn Conda environment:
- mesalib
The NANOVDB_EDITOR_USE_GLFW option can be disabled when using the editor in headless and streaming mode only. In that case, libvulkan.so.1 is built locally to ensure compatibility.
The NANOVDB_EDITOR_USE_H264 option is enabled by default. Make sure you have:
sudo apt-get install make# install homebrew from https://brew.sh
brew install cmake molten-vkNotes:
- If the Vulkan loader does not discover MoltenVK automatically on your machine, point
VK_ICD_FILENAMESandVK_DRIVER_FILESatMoltenVK_icd.json.
The project can use vcpkg for dependency management. If NANOVDB_EDITOR_USE_VCPKG is set, vcpkg.json automatically installs required dependencies.
NANOVDB_EDITOR_USE_H264 is supported on Windows only when NANOVDB_EDITOR_USE_VCPKG=ON. In that configuration, CMake consumes the openh264 package from vcpkg instead of the Unix-only source build path used on Linux.
To set up vcpkg:
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
bootstrap-vcpkg.batThe following dependencies are automatically managed by vcpkg.json:
- libe57format (and xerces-c dependency) when
NANOVDB_EDITOR_E57_FORMAT=ON - openh264
Put any data files into the data folder, which is linked to the location next to the libraries.
Shaders are generated into the shaders/_generated folder next to the libraries.
Run the build script with -h for available build options.
The Linux/macOS build script supports the following flags (combine as needed):
- -x: Perform a clean build (removes
build/, also forces shader recompile) - -r: Build in Release configuration
- -d: Build in Debug configuration
- -v: Enable verbose CMake build output
- -s: Compile Slang to ASM and clean shaders first
- -a: Build Debug with sanitizers enabled
- -p: Build and install the Python module (auto-installs
scikit-build-coreandwheel) - -e: Install the Python module in editable mode (use with
-p) - -t: Run tests (ctest + pytest); honors
-r/-dto pick configuration - -f: Disable GLFW for a headless build
- -c: Force CMake reconfigure (needed when switching build options like GLFW on/off)
Notes:
- If neither
-rnor-dis provided (and not using-por-t), the script defaults to a Release build. - For Python builds (
-p),-dselects Debug wheels; otherwise Release is used. - CMake configure is skipped automatically when the build directory already exists. Use
-cto force reconfigure when changing options (e.g., switching between GLFW enabled/disabled).
Examples:
# Clean Release build
./build.sh -x -r
# Debug build with sanitizers
./build.sh -a
# Headless Release build (GLFW disabled)
./build.sh -f -r
# Build and install Python package (Release)
./build.sh -p
# Build and install Python package in Debug, editable mode
./build.sh -p -d -e
# Run tests (defaults to Release tests)
./build.sh -t
# Generate Slang ASM during build
./build.sh -s -r
# Rebuild after changing options
./build.sh -r -c./build.shOptionally, rename the config file config next to the build script to config.ini and set the environment variables (use unquoted values; build.bat passes them to CMake with quotes):
MSVS_VERSION=Visual Studio 17 2022
USE_VCPKG=ON
NANOVDB_EDITOR_E57_FORMAT=ON
VCPKG_ROOT=path/to/vcpkg
When USE_VCPKG=ON, NANOVDB_EDITOR_USE_H264 defaults to ON on Windows. Without vcpkg, H.264 remains disabled on Windows because the fallback OpenH264 source build depends on Unix command-line tools.
Set NANOVDB_EDITOR_E57_FORMAT=ON to enable E57 support and install the optional vcpkg e57 feature on Windows.
To select a different profile for the Slang compiler (https://github.com/shader-slang/slang/blob/master/source/slang/slang-profile-defs.h):
SLANG_PROFILE="sm_5_1"
Then, run the build script:
./build.batAfter building, run the editor app:
./build/Release/pnanovdbeditorappThe libraries can be bundled into a Python package with a wrapper for the C-type functions. The following script will automatically install scikit-build, wheel, and build dependencies:
Build with -p to build and install the nanovdb_editor package.
./build.sh -p
python3 test/test_editor.py./build.sh -p
python3 test/test_streaming.pyAdd this line to the Python test script to print the PID of the process:
import os
print(os.getpid())- Build the debug configuration
- Run the test script; the console output will print the PID of the process
- Attach to the process:
With GDB:
gdb -p <PID>We keep the Vulkan headless FVDB viewer validated in both CI and local development with a shared integration suite and a consistent Docker image recipe.
./scripts/run_fvdb_viz_integration.sh mirrors the GitHub Actions job:
# Run release package tests (default)
./scripts/run_fvdb_viz_integration.sh
# Force rebuild the cached Docker image
./scripts/run_fvdb_viz_integration.sh --force-rebuild
# Validate the dev PyPI stream
./scripts/run_fvdb_viz_integration.sh --stream dev
# Smoke-test a locally built wheel
./scripts/run_fvdb_viz_integration.sh --local-wheel pymodule/dist/nanovdb_editor-*.whl
# Test against the latest fvdb-core nightly (pip install --pre)
./scripts/run_fvdb_viz_integration.sh --fvdb-nightlyHighlights:
- Ensures (and caches) the
nanovdb-editor_fvdb-<fvdb-core-version>Docker image with matching Torch/fvdb-core versions. - Prints the installed
nanovdb_editorversion inside the container before runningpytests/test_fvdb_viz_integration.py -vv -s --full-trace. - Prints the available Vulkan ICDs plus
vulkaninfo --summary, then fails fast iffvdb.vizcannot initialize instead of reporting a skipped upstream suite. - Accepts
--force-rebuildto bypass the local.cachetarball when you need a fresh base image.
.github/workflows/fvdb-viz-integration.yml runs on workflow_dispatch or workflow_call and:
- Resolves the package stream (release/dev) plus optional wheel artifact.
- Builds a lightweight
ubuntu:24.04-based Docker image with prebuilt fvdb-core wheels (pinned release or nightly viapip install --pre). - Runs the same pytest selector in Docker.
build-wheels.yml triggers two parallel integration jobs when run_fvdb_viz_integration is enabled: one against the pinned fvdb-core release and one against the latest nightly.
Shaders can have a defined struct with shader parameters that are intended to be shown in the editor's UI:
struct shader_params_t
{
float4 color;
bool use_color;
bool3 _pad1;
int _pad2;
};Shader-backed parameters live under the top-level JSON key ShaderParams; editor-only custom scene parameters live under SceneParams. Both support the numeric field options below. SceneParams also supports the control options described below.
Shader-backed parameters can define UI defaults and bounds in a JSON file:
{
"ShaderParams": {
"color": {
"value": [1.0, 0.0, 1.0, 1.0],
"min": 0.0,
"max": 1.0,
"step": 0.01
}
}
}Each field under SceneParams must declare type because there is no shader reflection to infer it:
{
"SceneParams": {
"exposure_bias": {
"type": "float",
"value": 0.0,
"min": -4.0,
"max": 4.0,
"step": 0.1,
"useSlider": true
},
"debug_slice": {
"type": "bool",
"value": false
},
"language_query": {
"type": "string",
"length": 128,
"value": "a red chair"
}
}
}Field schema (applies under either key unless restricted below):
ShaderParams/SceneParams: object whose keys are field names mapped to field-definition objects. UnderShaderParamsonly, the value may instead be an array of shader paths to define a group file.value: scalar or array initial value shown in the UI. Fortype: "string"it must be a JSON string.type: required for custom scene params; ignored for shader-backed params because the type comes from shader reflection.elementCount: optional explicit array length for custom scene params whenvalueis omitted or when zero-initialized storage is desired. Not valid fortype: "string"(uselengthinstead).length: required only fortype: "string"; positive integer capacity of thechar[length]buffer including the trailing\0. Capped at an editor-internal maximum.min: optional scalar or array lower bound for numeric widgets. Not valid fortype: "string".max: optional scalar or array upper bound for numeric widgets. Not valid fortype: "string".step: optional numeric increment for drag widgets. Defaults to0.01. Ignored fortype: "string".useSlider: optional boolean; renders a slider instead of a drag widget. Not valid fortype: "string".isBool: optional boolean; renders numeric0/1storage as a checkbox. Not valid fortype: "string".hidden: optional boolean; keeps the field mapped but hides it from the UI.
Supported scalar types: bool, int, int32, uint, uint32, int64, uint64, float, double, string.
Arrays are represented by using an array value or explicit elementCount; common reflected shader types such as float vectors and float4x4 are exposed this way.
type: "string" maps to a fixed-capacity char[length] in the reflected data type. The widget writes directly into the buffer on every keystroke, and map_params clients always observe the current widget contents. Clients that need to throttle per-string-change work (e.g. a text encoder) should debounce on their side.
Variables with _pad in the name are not shown in the UI.
Shader-backed parameters are shown in the object properties/shader parameter UI. Custom scene params are editor-only, loaded per scene through set_custom_scene_params(editor, scene, json_token, error_buf, error_buf_size) where json_token->str contains the JSON payload; on failure the function returns PNANOVDB_FALSE and writes a human-readable message into error_buf. Custom scene params are rendered in the dedicated Params window. They do not currently change object map_shader_params output.
Custom scene parameters also support these UI options under SceneParams only:
widget:"button"or"toggleButton". Both require scalarboolorbool32storage, a booleanvalueif supplied, andelementCountomitted or set to the integer1. Omitwidgetfor the default control.activeLabel: optional string for a toggle button's active state; an absent or empty label uses the field name. Active toggles use the active button color and keep their identity when the label changes.readOnly: optional boolean, defaultfalse; prevents UI edits while leaving the mapped value writable by the application. Read-only text remains selectable and can be copied.readOnlyField: optional name of a scalarboolorbool32field in the same schema. A true mapped value prevents UI edits to this control. StaticreadOnly: truetakes precedence. The named field can be hidden. Change the mapped boolean to lock or unlock controls without reloading the schema.sameLine: optional boolean, defaultfalse; places the control after the preceding visible custom field on the same row. The first visible field starts its own row. Inputs shrink to the available width or start a new row when there is too little space.tooltip: optional string shown on hover, including for read-only controls.
Unknown widget names and incorrectly typed optional UI hints (widget, activeLabel, readOnly, sameLine, tooltip) are ignored. Recognized button widgets still require valid scalar boolean storage. An invalid readOnlyField reference is an error.
For example, load this payload through the existing custom scene parameter API:
{
"SceneParams": {
"Play": {"type": "bool", "widget": "toggleButton", "activeLabel": "Stop"},
"Step": {"type": "bool", "widget": "button", "sameLine": true, "readOnlyField": "Play", "tooltip": "Advance one frame while paused"},
"Frame": {"type": "uint", "value": 0, "readOnly": true}
}
}A button sets its value to true when clicked and leaves it set until the application consumes the request and resets it to false. A toggle button changes its value on each click. Read and update these values through the existing map_params / unmap_params API with a null shader name (None in Python). Keep each mapping short: map, copy the requests, clear consumed button latches, and unmap. Run simulation, rendering, I/O, or waits after unmapping; an open mapping holds a lock that the Params window needs. Clicks before a latch is cleared coalesce into one request. No playback loop runs inside the widgets.
Explicitly reloading a schema resets values to their JSON defaults, including pending button requests. Reload is rejected while that scene has an active custom parameter mapping. Data-type handles remain valid until editor shutdown, but an old layout may no longer match the new schema; fetch the current handle after reloading. Use readOnlyField for runtime locking so playback values and pending requests stay intact.
To display a group of shader parameters from different shaders, define a group JSON file with shader paths:
{
"ShaderParams": [
"editor/editor.slang",
"test/test.slang"
]
}To convert the output to mp4:
ffmpeg -i input.h264 -c:v copy -f mp4 output.mp4
This project makes use of the following libraries:
- zlib – Compression library
- c-blosc – High-performance compressor optimized for binary data
- Vulkan-Headers – Vulkan API headers
- Vulkan-Loader – Vulkan ICD loader
- GLFW – Windowing, context, and input (optional)
- Dear ImGui – Immediate-mode GUI
- ImGuiFileDialog – File dialog for Dear ImGui
- ImGuiColorTextEdit – Syntax-highlighted text/code editor widget
- Slang – Shading language and compiler
- filewatch – Cross-platform file watching
- JSON for Modern C++ – JSON serialization for C++
- cnpy – Read/write NumPy .npy/.npz files from C++
- zstr – Transparent zlib iostream wrappers
- llhttp – High-performance HTTP parser
- Asio – Asynchronous networking and concurrency primitives
- RESTinio – Lightweight HTTP server framework
- fmt – Modern formatting library
- argparse – Header-only argument parser for C++17
- expected-lite – std::expected-like type for C++11/14/17
- libE57Format – E57 point cloud IO (optional)
- OpenH264 – H.264 encoder (optional)
- GoogleTest – C++ testing framework
Many thanks to the authors and contributors of these projects.