Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
60794bc
feat: add transform decimate action pipeline
merlotqi May 13, 2026
783eb13
feat: translate transform LOD action parsing
merlotqi May 13, 2026
94f7db9
feat: add playcanvas LOD generator tool
merlotqi May 13, 2026
89cd34f
fix: keep transform environment table split valid
merlotqi May 13, 2026
bc134a5
perf: speed up kd-tree neighbor queries
merlotqi May 13, 2026
600fcda
perf: add decimate phase profiling
merlotqi May 13, 2026
9b593fa
perf: use nanoflann for decimation knn
merlotqi May 13, 2026
b4f1cbf
refactor: remove Python bindings and related options from CMake
merlotqi May 13, 2026
f2d4ed9
bump version to 1.3.1 in CMakeLists.txt
merlotqi May 13, 2026
5ef026b
test: add data semantics and smoke tests for SplatVisualizer
merlotqi May 14, 2026
7bc1d4f
feat: enhance SplatVisualizer with new rendering options and shader s…
merlotqi May 14, 2026
505f908
Refactor: Remove renderer and shader implementations
merlotqi May 14, 2026
967090e
Add GPU compute abstraction layer with CUDA and Metal backends
merlotqi May 15, 2026
969d337
Add Playcanvas Viewer with GSplat rendering support
merlotqi May 15, 2026
1d7f99d
feat: enhance CameraController and GSplatRenderer with improved dolly…
merlotqi May 15, 2026
538646e
Add GSplatGLRenderer and associated shader sources for GSplat visuali…
merlotqi May 15, 2026
8bc923d
refactor: update PlaycanvasViewer to use new splat visualization stru…
merlotqi May 15, 2026
bde0cbf
refactor: remove legacy GSplatRenderer and associated shader sources;…
merlotqi May 15, 2026
6c631e5
Refactor SplatVisualizer and introduce SplatGaussianProp
merlotqi May 15, 2026
173fbda
refactor: remove legacy visualization components and introduce new st…
merlotqi May 15, 2026
6cff015
refactor: update CMake configuration for GPU support and add k-means …
merlotqi May 16, 2026
eee744c
refactor: remove pybind11 submodule and clean up .gitmodules
merlotqi May 16, 2026
81f837b
refactor: enhance logging in simplifyGaussians and add formatting fun…
merlotqi May 19, 2026
e04c4ae
feat(decimate): add ellipsoid_area() and caller-buffer eigen_symmetri…
merlotqi May 29, 2026
404db7a
refactor(decimate): deduplicate eigen_symmetric_3x3 Jacobi loop
merlotqi May 29, 2026
6d9ae20
refactor(decimate): switch SplatCache to Float32, remove Rt, use area…
merlotqi May 29, 2026
a1424f5
refactor(decimate): add MergeScratch, rewrite compute_edge_cost to us…
merlotqi May 29, 2026
2f9ef2b
fix(decimate): port area-weighted, mass-conserving merge math from up…
merlotqi May 29, 2026
f530ab9
refactor(decimate): remove pre-merge opacity pruning, instantiate Mer…
merlotqi May 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[submodule "thirdparty/pybind11"]
path = thirdparty/pybind11
url = https://github.com/pybind/pybind11.git
[submodule "thirdparty/meshoptimizer"]
path = thirdparty/meshoptimizer
url = https://github.com/zeux/meshoptimizer.git
98 changes: 84 additions & 14 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,27 +1,71 @@
cmake_minimum_required(VERSION 3.10...3.26)
set(CMAKE_CUDA_ARCHITECTURES "75;80;89" CACHE STRING "CUDA architectures")

# Platform detection for GPU support
set(APPLE_SILICON FALSE)
if(APPLE OR CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
set(APPLE_SILICON TRUE)
endif()

# GPU backend options
if(APPLE_SILICON)
set(_DEFAULT_CUDA OFF)
set(_DEFAULT_METAL ON)
else()
set(_DEFAULT_CUDA ON)
set(_DEFAULT_METAL OFF)
endif()

option(SPLAT_USE_CUDA "Use CUDA for GPU acceleration" ${_DEFAULT_CUDA})
option(SPLAT_USE_METAL "Use Metal for GPU acceleration (macOS only)" ${_DEFAULT_METAL})

# Set CUDA architectures only if CUDA is enabled
if(SPLAT_USE_CUDA)
set(CMAKE_CUDA_ARCHITECTURES "75;80;89" CACHE STRING "CUDA architectures")
endif()

# Configure project languages based on GPU backend
set(_PROJECT_LANGUAGES CXX C)
if(SPLAT_USE_CUDA)
list(APPEND _PROJECT_LANGUAGES CUDA)
endif()

project(SplatLib
VERSION 1.3.0
LANGUAGES CXX C CUDA
VERSION 1.3.1
LANGUAGES ${_PROJECT_LANGUAGES}
DESCRIPTION "Splat Transform")
set(SPLAT_INFO "${PROJECT_NAME} ${PROJECT_VERSION}")

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
if(SPLAT_USE_CUDA)
set(CMAKE_CUDA_STANDARD 17)
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
set(CMAKE_CUDA_EXTENSIONS OFF)
endif()

if(SPLAT_USE_METAL)
enable_language(OBJC)
enable_language(OBJCXX)
set(CMAKE_OBJC_STANDARD 17)
set(CMAKE_OBJC_STANDARD_REQUIRED ON)
set(CMAKE_OBJCXX_STANDARD 17)
set(CMAKE_OBJCXX_STANDARD_REQUIRED ON)
endif()

option(BUILD_SPLAT_SHARED "Build splat as a shared library" ON)
option(BUILD_SPLAT_CAPI "Build C API" ON)
option(BUILD_SPLAT_PYTON_BINDING "Build Python bindings" OFF)
option(BUILD_SPLAT_VIEWER "Build ImGui + OpenGL splat viewer" OFF)
option(BUILD_SPLAT_VIEWER "Build ImGui + VTK splat viewer" OFF)
option(BUILD_SPLAT_TRANSFORM_TOOL "Build splat file format transform tool" OFF)
option(BUILD_SPLAT_PLAYCANVAS_LOD "Build PlayCanvas LOD generation tool" OFF)
option(BUILD_SPLAT_TESTS "Build unit tests" OFF)
option(BUILD_SPLAT_VISUALIZATION "Build optional VTK visualization helpers" OFF)
option(BUILD_SPLAT_PLAYCANVAS_VIEWER "Build PlayCanvas-style OpenGL splat viewer" OFF)

if(BUILD_SPLAT_VIEWER AND NOT BUILD_SPLAT_VISUALIZATION)
set(BUILD_SPLAT_VISUALIZATION ON CACHE BOOL "Build optional VTK visualization helpers" FORCE)
endif()

if(BUILD_SPLAT_VISUALIZATION)
set(SPLAT_VTK_COMPONENTS
Expand All @@ -35,7 +79,15 @@ if(BUILD_SPLAT_VISUALIZATION)
)
endif()

find_package(CUDAToolkit REQUIRED)
find_package(CUDAToolkit)
if(SPLAT_USE_CUDA AND NOT CUDAToolkit_FOUND)
message(FATAL_ERROR "CUDA requested but CUDAToolkit not found")
endif()

if(SPLAT_USE_METAL AND NOT APPLE)
message(FATAL_ERROR "Metal is only supported on macOS")
endif()

find_package(Eigen3 CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(absl CONFIG REQUIRED)
Expand All @@ -55,17 +107,22 @@ if(BUILD_SPLAT_SHARED)
endif()
add_subdirectory(thirdparty/meshoptimizer)

# Export GPU backend configuration to subdirectories
set(SPLAT_GPU_BACKEND "NONE")
if(SPLAT_USE_CUDA)
set(SPLAT_GPU_BACKEND "CUDA")
elseif(SPLAT_USE_METAL)
set(SPLAT_GPU_BACKEND "METAL")
endif()

message(STATUS "SplatLib GPU Backend: ${SPLAT_GPU_BACKEND}")

add_subdirectory(src)

if(BUILD_SPLAT_CAPI)
add_subdirectory(capi)
endif()

if(BUILD_SPLAT_PYTON_BINDING)
add_subdirectory(thirdparty/pybind11)
add_subdirectory(python)
endif()

if(DOXYGEN_FOUND)
set(DOXYGEN_IN ${CMAKE_CURRENT_SOURCE_DIR}/doxygen/Doxygen.in)
set(DOXYGEN_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
Expand All @@ -86,6 +143,19 @@ if(BUILD_SPLAT_TRANSFORM_TOOL)
add_subdirectory(transform)
endif()

if(BUILD_SPLAT_PLAYCANVAS_LOD)
add_subdirectory(playcanvasLOD)
endif()

if(BUILD_SPLAT_PLAYCANVAS_VIEWER)
add_subdirectory(playcanvasViewer)
endif()

if(BUILD_SPLAT_TESTS)
enable_testing()
add_subdirectory(tests)
endif()

if(BUILD_SPLAT_VIEWER)
add_subdirectory(viewer)
endif()
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ SplatLib provides comprehensive support for various Gaussian splat formats, enab
### Advanced Features
- **Level of Detail (LOD)**: Chunk-based organization supporting multi-resolution representations
- **Data Compression**: Integrated WebP codec for efficient texture compression
- **VTK Visualization**: Optional `SplatGaussianProp` and `SplatVisualizer` APIs for Qt, ImGui, and VTK applications
- **Parallel Processing**: Built-in thread pools and parallel algorithms
- **Python Bindings**: pybind11-based Python interface

Expand Down Expand Up @@ -129,6 +130,23 @@ auto rotated_sh = splat::rotateSHCoefficients(original_sh, rotation_matrix);
auto transformed_data = splat::transform(*data, transformation_matrix);
```

### VTK Visualization

```cpp
#include <splat/splat.h>
#include <splat/visualization/splat_gaussian_prop.h>

#include <vtkRenderer.h>
#include <vtkSmartPointer.h>

auto data = splat::readPly("scene.ply");
auto prop = vtkSmartPointer<splat::SplatGaussianProp>::New();
prop->SetInputData(std::move(data));

vtkRenderer* renderer = /* owned by your Qt, ImGui, or VTK application */;
renderer->AddViewProp(prop);
```

## Extensibility and Future Development

### Adding New File Formats
Expand Down Expand Up @@ -217,6 +235,8 @@ make -j$(nproc)

### CMake Options
- `BUILD_SPLAT_TRANSFORM_TOOL` - Build command-line transform utility (default: OFF)
- `BUILD_SPLAT_VISUALIZATION` - Build VTK visualization helpers (default: OFF)
- `BUILD_SPLAT_PLAYCANVAS_VIEWER` - Build standalone PlayCanvas-style OpenGL viewer (default: OFF)
- `BUILD_PYTHON_BINDINGS` - Build Python bindings (default: OFF)
- `ENABLE_CLANG_TIDY` - Enable clang-tidy static analysis (default: OFF)

Expand All @@ -238,6 +258,7 @@ SplatLib/

- [PLY Format Specification](docs/ply.md) - Industry standard for Gaussian splats
- [SOG Format Specification](docs/sog.md) - Compressed format for web delivery
- [Visualization](docs/visualization.md) - VTK prop and managed viewer integration
- [API Documentation](docs/index.md) - Library overview and format comparison

Generate Doxygen documentation:
Expand Down
37 changes: 37 additions & 0 deletions cmake/MetalCompile.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* CMake helper for Metal compilation
* This file should be included in src/CMakeLists.txt when SPLAT_USE_METAL is enabled
*/

# NOTE: This file documents the Metal compilation process
# Integration with CMake's Metal support is still being developed

# When Metal support is needed, add this to src/CMakeLists.txt:

# if(SPLAT_USE_METAL)
# # Compile Metal kernels to AIR format
# find_program(METAL_COMPILER xcrun)
# if(METAL_COMPILER)
# # Create a custom command to compile Metal source to metallib
# add_custom_command(OUTPUT kmeans.metallib
# COMMAND ${METAL_COMPILER} -sdk macosx metal
# -ffast-math
# -O3
# ${CMAKE_CURRENT_SOURCE_DIR}/spatial/kmeans.metal
# -o ${CMAKE_CURRENT_BINARY_DIR}/kmeans.air
# COMMAND ${METAL_COMPILER} -sdk macosx metallib
# ${CMAKE_CURRENT_BINARY_DIR}/kmeans.air
# -o ${CMAKE_CURRENT_BINARY_DIR}/kmeans.metallib
# DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/spatial/kmeans.metal
# COMMENT "Compiling Metal kernels"
# )
#
# # Add the metallib to the target
# target_sources(splat PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/kmeans.metallib)
#
# # Ensure the metallib is bundled with the library
# add_custom_target(metal_kernels ALL DEPENDS kmeans.metallib)
# add_dependencies(splat metal_kernels)
# endif()
# endif()

2 changes: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ title: Splat File Formats

PlayCanvas supports two formats for 3D Gaussian Splat data:

For C++ rendering integration, see [Visualization](./visualization.md).

## [PLY Format](./ply.md) - Source & Interchange

The industry standard for Gaussian splat data. Uncompressed, full precision, and universally compatible.
Expand Down
88 changes: 88 additions & 0 deletions docs/visualization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Visualization

SplatLib routes Gaussian splat rendering through VTK when `BUILD_SPLAT_VISUALIZATION` is enabled. The recommended integration point is `splat::SplatVisualizer`: it owns or attaches to VTK rendering objects, keeps mouse and camera interaction inside VTK, and exposes the renderer/window/interactor needed by Qt, ImGui, and custom viewers.

Qt applications can place the visualizer's `vtkRenderWindow` in `QVTKOpenGLNativeWidget` or `QVTKRenderWidget`. ImGui or GLFW shells should treat VTK as the rendering canvas and use ImGui only for controls.

## VTK Canvas Integration

Use `splat::SplatVisualizer` when your application owns the UI shell but wants VTK to own rendering, camera, and mouse interaction.

```cpp
#include <splat/splat.h>
#include <splat/visualization/splat_visualizer.h>

#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>

auto data = splat::readPly("scene.ply");

auto renderer = vtkSmartPointer<vtkRenderer>::New();
auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

splat::SplatVisualizer viewer(renderer, renderWindow, interactor, "Splat Viewer");

splat::SplatRenderOptions options;
options.sortBackToFront = true;
options.depthTest = true;
options.depthWrite = false;
options.sizeScale = 1.0f;
viewer.addSplatCloud(std::move(data), "scene", options);
viewer.resetCamera();

// Qt: widget->setRenderWindow(viewer.getRenderWindow());
// ImGui/GLFW shells: keep VTK's render window as the 3D canvas and use ImGui for controls.
```

`SplatVisualizer` wraps `vtkRenderer`, `vtkRenderWindow`, `vtkRenderWindowInteractor`, camera interaction, axes, and one or more `SplatGaussianProp` instances.

## Managed Window

Use `splat::SplatVisualizer` when you want SplatLib to own a simple VTK window and interactor.

```cpp
#include <splat/splat.h>
#include <splat/visualization/splat_visualizer.h>

auto data = splat::readPly("scene.ply");

splat::SplatVisualizer viewer("Splat Viewer");
viewer.addSplatCloud(std::move(data));
viewer.resetCamera();
viewer.spin();
```

## Low-Level Prop

Use `splat::SplatGaussianProp` only when your application already has a complete VTK renderer/window/interactor setup and wants to manage camera and input itself.

```cpp
#include <splat/splat.h>
#include <splat/visualization/splat_gaussian_prop.h>

#include <vtkRenderer.h>
#include <vtkSmartPointer.h>

auto data = splat::readPly("scene.ply");

auto prop = vtkSmartPointer<splat::SplatGaussianProp>::New();
prop->SetInputData(std::move(data));

vtkRenderer* renderer = /* owned by your application */;
renderer->AddViewProp(prop);
renderer->ResetCamera();
```

`SplatGaussianProp` accepts the same `DataTable` columns used by PlayCanvas-style Gaussian splats: `x`, `y`, `z`, `rot_0..3`, `scale_0..2`, `f_dc_0..2`, and `opacity`. Internally it converts `DataTable` to `GSplatData` and renders through the shared PlayCanvas-compatible OpenGL path.

## Build

```bash
cmake -S . -B build -DBUILD_SPLAT_VISUALIZATION=ON
cmake --build build --target splat
```

When using the optional standalone PlayCanvas-style viewer, enable `BUILD_SPLAT_PLAYCANVAS_VIEWER` as well.
Binary file added images/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
50 changes: 50 additions & 0 deletions include/splat/gpu/gpu_compute.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* GPU Compute Abstraction Layer
*
* This file provides platform-agnostic GPU compute interfaces
* for CUDA and Metal backends.
*/

#pragma once

#include <cstdint>

namespace splat {
namespace gpu {

/**
* @brief Compute centroid norms for k-means clustering
*
* @param centroids Input centroids in column-major format [K×D]
* @param K Number of centroids
* @param D Number of dimensions
* @param norms Output norms [K]
* @return true on success, false on failure
*/
bool computeCentroidNorms(const float* centroids, uint32_t K, uint32_t D, float* norms);

/**
* @brief Assign points to nearest centroids for k-means clustering
*
* @param points Input points in column-major format [N×D]
* @param centroids Centroid positions in column-major format [K×D]
* @param centroid_norms Pre-computed norms of centroids [K]
* @param N Number of points
* @param K Number of centroids
* @param D Number of dimensions
* @param results Output cluster assignments [N]
* @return true on success, false on failure
*/
bool assignPointsToCentroids(const float* points, const float* centroids,
const float* centroid_norms,
uint32_t N, uint32_t K, uint32_t D,
uint32_t* results);

/**
* @brief Get backend type
* @return String describing the GPU backend (e.g., "CUDA", "Metal")
*/
const char* getBackendName();

} // namespace gpu
} // namespace splat
Loading
Loading