Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
57 changes: 37 additions & 20 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ set(OPENSPLAT_BUILD_VISUALIZER OFF CACHE BOOL "Build visualizer application")
set(OPENSPLAT_USE_FAST_MATH OFF CACHE BOOL "Enable fast math optimizations for GPU kernels (-use_fast_math / -ffast-math)")
set(OPENSPLAT_USE_PCH ON CACHE BOOL "Use precompiled headers to speed up compilation")

set(FETCH_DEPENDENCIES ON CACHE BOOL "Fetch additional dependencies from the Internet during configuration")

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

# Read version
Expand Down Expand Up @@ -53,41 +51,59 @@ include(FetchContent)

set(NANOFLANN_BUILD_EXAMPLES OFF)
set(NANOFLANN_BUILD_TESTS OFF)
set(SPZ_BUILD_PYTHON_BINDINGS OFF)
set(SPZ_BUILD_TOOLS OFF)
set(SPZ_BUILD_EXTENSIONS OFF)
set(SPZ_BUILD_WASM OFF)
set(SPZ_SHOULD_INSTALL OFF)
set(ZLIB_BUILD_TESTING OFF)
set(ZLIB_BUILD_SHARED OFF)
set(ZLIB_INSTALL OFF)

if(FETCH_DEPENDENCIES)
find_package(nlohmann_json QUIET)
if(NOT nlohmann_json_FOUND)
message(STATUS "nlohmann_json not found, fetching it")
FetchContent_Declare(nlohmann_json
URL https://github.com/nlohmann/json/archive/refs/tags/v3.11.3.zip
)
FetchContent_MakeAvailable(nlohmann_json)
endif()

find_package(nanoflann QUIET)
if(NOT nanoflann_FOUND)
message(STATUS "nanoflann not found, fetching it")
FetchContent_Declare(nanoflann
URL https://github.com/jlblancoc/nanoflann/archive/refs/tags/v1.5.5.zip
)
FetchContent_MakeAvailable(nanoflann)
endif()

find_package(cxxopts QUIET)
if(NOT cxxopts_FOUND)
message(STATUS "cxxopts not found, fetching it")
FetchContent_Declare(cxxopts
URL https://github.com/jarro2783/cxxopts/archive/refs/tags/v3.2.0.zip
)
FetchContent_Declare(spz
URL https://github.com/nianticlabs/spz/archive/affd0ecea7fbb4c265ee119475af7ee5b2997482.zip
)
FetchContent_MakeAvailable(nlohmann_json nanoflann cxxopts spz)
FetchContent_MakeAvailable(cxxopts)
endif()

find_package(ZLIB QUIET)
if(ZLIB_FOUND)
set(ZLIB_LIB ZLIB::ZLIB)
else()
find_package(nlohmann_json)
find_package(nanoflann)
find_package(cxxopts)
find_package(spz)
message(STATUS "ZLIB not found, fetching it")
FetchContent_Declare(zlib
URL https://github.com/pierotofy/OpenSplat/releases/download/v1.1.4/zlib-1.3.2.tar.gz
)
FetchContent_MakeAvailable(zlib)
set(ZLIB_LIB zlibstatic)
endif()

add_subdirectory(vendor/spz)

if((GPU_RUNTIME STREQUAL "CUDA") OR (GPU_RUNTIME STREQUAL "HIP"))
if(FETCH_DEPENDENCIES)
find_package(glm QUIET)
if(NOT glm_FOUND)
message(STATUS "glm not found, fetching it")
FetchContent_Declare(glm
URL https://github.com/g-truc/glm/archive/refs/tags/1.0.1.zip
)
FetchContent_MakeAvailable(glm)
else()
find_package(glm)
endif()
endif()

Expand Down Expand Up @@ -265,7 +281,7 @@ target_include_directories(gsplat_cpu PRIVATE ${TORCH_INCLUDE_DIRS})
set(OPENSPLAT_SRC_FILES opensplat.cpp point_io.cpp nerfstudio.cpp model.cpp
kdtree_tensor.cpp spherical_harmonics.cpp cv_utils.cpp utils.cpp project_gaussians.cpp
rasterize_gaussians.cpp ssim.cpp optim_scheduler.cpp colmap.cpp opensfm.cpp openmvg.cpp input_data.cpp
tensor_math.cpp)
tensor_math.cpp rad.cpp)

if (OPENSPLAT_BUILD_VISUALIZER)
if (Pangolin_FOUND)
Expand Down Expand Up @@ -302,6 +318,7 @@ target_link_libraries(opensplat PRIVATE
nlohmann_json::nlohmann_json
cxxopts::cxxopts
nanoflann::nanoflann
${ZLIB_LIB}
spz::spz
)
if (NOT WIN32)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A free and open source implementation of 3D [gaussian splatting](https://www.you
<img src="https://github.com/pierotofy/OpenSplat/assets/1951843/c9327c7c-31ad-402d-a5a5-04f7602ca5f5" width="49%" />
<img src="https://github.com/pierotofy/OpenSplat/assets/1951843/eba4ae75-2c88-4c9e-a66b-608b574d085f" width="49%" />

OpenSplat takes camera poses + sparse points in [COLMAP](https://colmap.github.io/), [OpenSfM](https://github.com/mapillary/OpenSfM), [ODX](https://github.com/WebODM/ODX), [OpenMVG](https://github.com/OpenMVG/OpenMVG) or [nerfstudio](https://docs.nerf.studio/quickstart/custom_dataset.html) project format and computes a [scene file](https://drive.google.com/file/d/12lmvVWpFlFPL6nxl2e2d-4u4a31RCSKT/view?usp=sharing) (.ply, .splat, or .spz) that can be later imported for [viewing](https://antimatter15.com/splat/?url=https://splat.uav4geo.com/banana.splat), editing and rendering in other [software](https://github.com/MrNeRF/awesome-3D-gaussian-splatting?tab=readme-ov-file#open-source-implementations).
OpenSplat takes camera poses + sparse points in [COLMAP](https://colmap.github.io/), [OpenSfM](https://github.com/mapillary/OpenSfM), [ODX](https://github.com/WebODM/ODX), [OpenMVG](https://github.com/OpenMVG/OpenMVG) or [nerfstudio](https://docs.nerf.studio/quickstart/custom_dataset.html) project format and computes a [scene file](https://drive.google.com/file/d/12lmvVWpFlFPL6nxl2e2d-4u4a31RCSKT/view?usp=sharing) (.ply, .splat, .spz, or .rad) that can be later imported for [viewing](https://antimatter15.com/splat/?url=https://splat.uav4geo.com/banana.splat), editing and rendering in other [software](https://github.com/MrNeRF/awesome-3D-gaussian-splatting?tab=readme-ov-file#open-source-implementations).

Graphics card recommended, but not required! OpenSplat runs the fastest on NVIDIA, AMD and Apple (Metal) GPUs, but can also run entirely on the CPU (~100x slower).

Expand Down
56 changes: 45 additions & 11 deletions model.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <filesystem>
#include <load-spz.h>
#include "model.hpp"
#include "constants.hpp"
#include "splat-types.h"
Expand All @@ -8,7 +9,7 @@
#include "tensor_math.hpp"
#include "gsplat.hpp"
#include "utils.hpp"
#include <load-spz.h>
#include "rad.hpp"

#ifdef USE_MPS
#include <torch/mps.h>
Expand Down Expand Up @@ -510,6 +511,14 @@ void Model::save(const std::string &filename, int step){
savePly(filename, step);
std::cout << "Wrote " << filename << std::endl;
}
else if (extension == ".rad") {
if (saveRad(filename)) {
std::cout << "Wrote " << filename << std::endl;
}
else {
std::cerr << "Failed to write " << filename << ", aborting save." << std::endl;
}
}
else {
bool success = saveSpz(filename);
if (success) {
Expand Down Expand Up @@ -621,14 +630,14 @@ bool Model::saveSpz(const std::string &filename){


torch::Tensor meansCpu = keepCrs ? (means.cpu() / scale) + translation : means.cpu();
torch::Tensor scalesCpu = keepCrs ? (scales.cpu() / scale) : scales.cpu();
torch::Tensor scalesCpu = keepCrs ? torch::log(torch::exp(scales.cpu()) / scale) : scales.cpu();

torch::Tensor meansFlat = meansCpu.flatten();
torch::Tensor scalesFlat = scalesCpu.flatten();
torch::Tensor colorsFlat = featuresDc.cpu().flatten(); // raw DC coefficients
torch::Tensor opacFlat = opacities.flatten().cpu();
torch::Tensor quatsFlat = quats.flatten().cpu();
torch::Tensor shRestFlat = featuresRest.cpu().transpose(1, 2).flatten();
torch::Tensor quatsFlat = torch::roll(quats.cpu(), -1, 1).flatten();
torch::Tensor shRestFlat = featuresRest.cpu().flatten();

spz::GaussianCloud gaussians;
gaussians.numPoints = meansCpu.size(0);
Expand All @@ -641,16 +650,41 @@ bool Model::saveSpz(const std::string &filename){
gaussians.colors = tensor_to_vector<float>(colorsFlat);
gaussians.sh = tensor_to_vector<float>(shRestFlat);

auto options = spz::PackOptions{
.version = 3, // V4 available but not handled by many viewers
.from = spz::CoordinateSystem::RUB,
.sh1Bits = 6,
.shRestBits = 5
};
spz::PackOptions options;
options.version = 3; // V4 available but not handled by many viewers
options.from = spz::CoordinateSystem::RUB;
options.sh1Bits = 6;
options.shRestBits = 5;
bool success = spz::saveSpz(gaussians, options, filename);
return success;
}

bool Model::saveRad(const std::string &filename){
size_t numPoints = means.size(0);

// Same value preparation as savePly; rad.cpp expects exactly the values
// a saved PLY would contain
torch::Tensor meansCpu = (keepCrs ? (means.cpu() / scale) + translation : means.cpu()).contiguous();
torch::Tensor featuresDcCpu = featuresDc.cpu().contiguous();
// featuresRest [N, K, 3] coefficient-major matches rad's SH layout; no transpose
torch::Tensor featuresRestCpu = featuresRest.cpu().contiguous();
torch::Tensor opacitiesCpu = opacities.cpu().contiguous();
torch::Tensor scalesCpu = (keepCrs ? torch::log(torch::exp(scales.cpu()) / scale) : scales.cpu()).contiguous();
torch::Tensor quatsCpu = quats.cpu().contiguous();

rad::SplatData data;
data.numPoints = numPoints;
data.numRestCoeffs = featuresRest.size(1);
data.means = tensor_to_vector<float>(meansCpu);
data.featuresDc = tensor_to_vector<float>(featuresDcCpu);
data.featuresRest = tensor_to_vector<float>(featuresRestCpu);
data.opacities = tensor_to_vector<float>(opacitiesCpu);
data.scales = tensor_to_vector<float>(scalesCpu);
data.quats = tensor_to_vector<float>(quatsCpu);

return rad::saveRad(filename, data);
}

void Model::saveDebugPly(const std::string &filename, int step){
// A standard PLY
std::ofstream o(filename, std::ios::binary);
Expand Down
1 change: 1 addition & 0 deletions model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ struct Model{
void savePly(const std::string &filename, int step);
void saveSplat(const std::string &filename);
bool saveSpz(const std::string &filename);
bool saveRad(const std::string &filename);
void saveDebugPly(const std::string &filename, int step);
int loadPly(const std::string &filename);
torch::Tensor mainLoss(torch::Tensor &rgb, torch::Tensor &gt, float ssimWeight);
Expand Down
2 changes: 1 addition & 1 deletion opensplat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ int main(int argc, char *argv[]){

if (step % displayStep == 0) {
const float percentage = static_cast<float>(step) / numIters;
std::cout << "Step " << step << ": " << mainLoss.item<float>() << " (" << floor(percentage * 100) << "%)" << std::endl;
std::cout << "Step " << step << ": " << mainLoss.item<float>() << " [" << floor(percentage * 100) << "%]" << std::endl;
}

model.optimizersStep();
Expand Down
Loading
Loading