Code Monkey home page Code Monkey logo

cuda_voxelizer's Introduction

Build Status license
ko-fi

cuda_voxelizer v0.6

A command-line tool to convert polygon meshes to (annotated) voxel grids.

  • Supported input formats: .ply, .off, .obj, .3DS, .SM and RAY
  • Supported output formats: .vox, .binvox, .obj cubes and point cloud, morton ordered grid
  • Requires a CUDA-compatible video card. Compute Capability 2.0 or higher (Nvidia Fermi or better).
    • Since v0.4.4, the voxelizer reverts to a (slower) CPU voxelization method when no CUDA device is found

Important: In v0.6 I replaced all GLM math types with builtin CUDA types, removing an external dependency. This is a big change. I've tested the release as well as I can, but if you encounter any weirdness, it's advised to check if you can reproduce the problem with an older version. Thanks!

Usage

Program options:

  • -f <path to model file>: (required) A path to a polygon-based 3D model file.
  • -s <voxel grid length>: (default: 256) The length of the cubical voxel grid. The process will construct the tightest possible cubical bounding box around the input model.
  • -o <output format>: The output format for voxelized models, default: binvox. Output files are saved in the same folder as the input file, in the format <original file name>_<grid_size>.extension.
    • vox: (default) A vox file, which is the native format of and can be viewed with the excellent MagicaVoxel.
    • binvox: A binvox file. Can be viewed using viewvox.
    • obj: A mesh containing actual cubes (made up of triangle faces) for each voxel.
    • obj_points: A mesh containing a point cloud, with a vertex for each voxel. Can be viewed using any compatible viewer that can just display vertices, like Blender or Meshlab.
    • morton: a binary file containing a Morton-ordered grid. This is an internal format I use for other tools.
  • -cpu: Force multi-threaded voxelization on the CPU instead of GPU. Can be used when a CUDA device is not detected/compatible, or for very small models where GPU call overhead is not worth it.
  • -solid : (Experimental) Use solid voxelization instead of voxelizing the mesh faces. Needs a watertight input mesh.

Examples

cuda_voxelizer -f bunny.ply -s 256 generates a 256 x 256 x 256 vox-based voxel model which will be stored in bunny_256.vox.

cuda_voxelizer -f torus.ply -s 64 -o obj -solid generates a solid (filled) 64 x 64 x 64 .obj voxel model which will be stored in torus_64.obj.

output_examples

Building

The build process is aimed at 64-bit executables. It's possible to build for 32-bit as well, but I'm not actively testing/supporting this. You can build using CMake or using the provided Visual Studio project. Since 2022, cuda_voxelizer builds via Github Actions as well, check the .yml config file for more info.

Dependencies

The project has the following build dependencies:

Build using CMake (Windows, Linux)

After installing dependencies, do mkdir build and cd build, followed by:

For Windows with Visual Studio:

$env:CUDAARCHS="your_cuda_compute_capability"
cmake -A x64 -DTrimesh2_INCLUDE_DIR:PATH="path_to_trimesh2_include" -DTrimesh2_LINK_DIR:PATH="path_to_trimesh2_library_dir" .. 

For Linux:

CUDAARCHS="your_cuda_compute_capability" cmake -DTrimesh2_INCLUDE_DIR:PATH="path_to_trimesh2_include" -DTrimesh2_LINK_DIR:PATH="path_to_trimesh2_library_dir" -DCUDA_ARCH:STRING="your_cuda_compute_capability" .. 

Where your_cuda_compute_capability is a string specifying your CUDA architecture (more info here and here CMake). For example: CUDAARCHS="50;61" or CUDAARCHS="60".

Finally, run

cmake --build . --parallel number_of_cores

Build using Visual Studio project (Windows)

A project solution for Visual Studio 2022 is provided in the msvc folder. It is configured for CUDA 12.1, but you can edit the project file to make it work with other CUDA versions. You can edit the custom_includes.props file to configure the library locations, and specify a place where the resulting binaries should be placed.

    <TRIMESH_DIR>C:\libs\trimesh2\</TRIMESH_DIR>
    <GLM_DIR>C:\libs\glm\</GLM_DIR>
    <BINARY_OUTPUT_DIR>D:\dev\Binaries\</BINARY_OUTPUT_DIR>

Details

cuda_voxelizer implements an optimized version of the method described in M. Schwarz and HP Seidel's 2010 paper Fast Parallel Surface and Solid Voxelization on GPU's. The morton-encoded table was based on my 2013 HPG paper Out-Of-Core construction of Sparse Voxel Octrees and the work in libmorton.

cuda_voxelizer is built with a focus on performance. Usage of the routine as a per-frame voxelization step for real-time applications is viable. These are the voxelization timings for the Stanford Bunny Model (1,55 MB, 70k triangles).

  • This is the voxelization time for a non-solid voxelization. No I/O - from disk or to GPU - is included in this timing.
  • CPU voxelization time is heavily dependent on how many cores your CPU has - OpenMP allocates 1 thread per core.
Grid size GPU (GTX 1050 TI) CPU (Intel i7 8750H, 12 threads)
64³ 0.2 ms 39.8 ms
128³ 0.3 ms 63.6 ms
256³ 0.6 ms 118.2 ms
512³ 1.8 ms 308.8 ms
1024³ 8.6 ms 1047.5 ms
2048³ 44.6 ms 4147.4 ms

Thanks

See also

  • The .binvox file format was created by Michael Kazhdan.
    • Patrick Min wrote some interesting tools to work with it:
      • viewvox: Visualization of voxel grids (a copy of this tool is included in cuda_voxelizer releases)
      • thinvox: Thinning of voxel grids
    • binvox-rw-py is a Python module to interact with .binvox files
  • Zarbuz's FileToVox looks interesting as well
  • If you want a good customizable CPU-based voxelizer, I can recommend VoxSurf.
  • Another hackable voxel viewer is Sean Barrett's excellent stb_voxel_render.h.
  • Nvidia also has a voxel library called GVDB, that does a lot more than just voxelizing.

Todo / Possible future work

This is on my list of "nice things to add".

  • Better output filename control
  • Noncubic grid support
  • Memory limits test
  • Implement partitioning for larger models
  • Do a pre-pass to categorize triangles
  • Implement capture of normals / color / texture data

Citation

If you use cuda_voxelizer in your published paper or other software, please reference it, for example as follows:

@Misc{cudavoxelizer17,
author = "Jeroen Baert",
title = "Cuda Voxelizer: A GPU-accelerated Mesh Voxelizer",
howpublished = "\url{https://github.com/Forceflow/cuda_voxelizer}",
year = "2017"}

If you end up using cuda_voxelizer in something cool, drop me an e-mail: mail (at) jeroen-baert.be

Donate

cuda_voxelizer is developed in my free time. If you want to support the project, you can do so through:

  • Kofi
  • BTC: 3GX3b7BZK2nhsneBG8eTqEchgCQ8FDfwZq
  • ETH: 0x7C9e97D2bBC2dFDd93EF56C77f626e802BA56860

cuda_voxelizer's People

Contributors

conceptclear avatar forceflow avatar kernela avatar ndroi avatar philipp-m avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cuda_voxelizer's Issues

Program cannot be launched on Windows: cudart64_102.dll is missing

I just tried the Windows version from this release. Unfortunately it does not seem to work and gives the following error. Is there anythin needed in addition to make it work?

Also it seems like the DLLs contained in the release zip are cudart64_90.dll, so maybe they need an update?

postion calculation may be en error

Hi, Thank you for this project, it helps me very much.

I found a small issue when calculating the voxel location here:

size_t location = static_cast<size_t>(x) + (static_cast<size_t>(y)* static_cast<size_t>(info.gridsize.y)) + (static_cast<size_t>(z)* static_cast<size_t>(info.gridsize.y)* static_cast<size_t>(info.gridsize.z));

I think it should be :

size_t location = static_cast<size_t>(x) + (static_cast<size_t>(y)* static_cast<size_t>(info.gridsize.x)) + (static_cast<size_t>(z)* static_cast<size_t>(info.gridsize.x)* static_cast<size_t>(info.gridsize.y));

since you made the info.gridsize.x == info.gridsize.y == info.gridsize.z when creating AABox we can't reproduce this issue. I found this by accident when experimenting the code and use a grid size with different value on three directions.

Add translate and scale to binvox file

I used cuda_voxelizer to generate binvox files and intended to read the file using binvox_rw_py

However, the file generated lacks translate and scale in its ASCII header, I have to manually add following lines to the function write_binvox:

    output << "translate " << info.bbox.min.x << " " << info.bbox.min.y << " " << info.bbox.min.z << endl;
    output << "scale " << max(max(info.bbox.max.x - info.bbox.min.x, info.bbox.max.y - info.bbox.min.y),
                              info.bbox.max.z - info.bbox.min.z) << endl;

I guess it is right, because I checked that all vertices falls in to voxel using the following coordinate translation function:

def cartesian2voxcoord(v, vox):
    vn = (v - vox.translate) / vox.scale
    vc = np.floor(vn * vox.dims)
    vc = np.clip(vc, 0, vox.dims - np.ones(3, dtype=np.int)).astype(int)
    # original code: vc = np.round(vc).astype(int)
    return vc

Do you have any support for this feature?

CUDA freeze when using CudaMallocManaged()

Lately, theres's been a strange bug with CUDA and unified memory:

I'm working on a solution to temporarily switch back to the old, more hands-on way of allocating memory for triangles and voxel table.

Point Cloud generation matching between input and output files.

Hello all,

I found a workaround but I do not know if its intended to be an issue or not.

I you try to input a mesh file and generate a pointcloud, the resulting pointcloud would have the same dimensions but not the same center of the input mesh. This is because of the createMeshBBCube function in the utils.h file.

When you try to scale the two non-maximum dimensions to math the largest one, it creates a grid where it matches only with the largest dimension.

To do workaround, I decided to make the scaling go only on the max point of the input bounding box.

float delta = max_length - lengths[i]; // compute difference between largest length and current (X,Y or Z) length
//answer.min[i] = box.min[i] - (delta / 2.0f); // don't pad in the min direction
answer.max[i] = box.max[i] + (delta); // pad with difference behind current max

this ensures that when I use the voxelization_info.unit vector to scale back the resulting pointcloud to original dimensions, the scaling is correct.

I do not know if this should be done pre or post voxelization, I decided to do it before.

I do not know if the double-sided sacling was preferred to preserve the center of the mesh, but by using it we can only preserve dimensions and lose center, or preserve center and lose dimensions.

So if anyone is trying to use this code to check if a point in a uniform grid is inside or outside the input mesh, this modification is necessary I think.

I also noticed instability if the input mesh has small dimensions (e-3 magnitude), but that's a different issue and I wrote about it in the solid voxelization issue thread.

image

GPU mode yield inaccurate result

I just voxelized a simple cube, defined as (obj file):
v 150.100006 400.100006 550.099976
v 550.099976 400.100006 550.099976
v 150.100006 800.099976 550.099976
v 550.099976 800.099976 550.099976
v 150.100006 800.099976 150.100006
v 550.099976 800.099976 150.100006
v 150.100006 400.100006 150.100006
v 550.099976 400.100006 150.100006

f 1 2 4
f 1 4 3
f 3 4 6
f 3 6 5
f 5 6 8
f 5 8 7
f 7 8 2
f 7 2 1
f 2 8 6
f 2 6 4
f 7 1 3
f 7 3 5

The CPU mode generate fine result, but the GPU mode yield something inaccurate:
image
31
32
33
The first image is the voxelization result visualized by marching cubes algorithm and meshLab, some glitch appears along the diagonal line. The latter 3 images are 3 continuous 2-D plane of the voxelization result, the middle one shows that the glitches comes from the voxelizer.

I barely know about cuda programming and the voxelization algorithm, just point out this issue, maybe someone can fix it.
Still very nice voxelizer 😃 !

Performance improvements

I've made a few code improvements to your CPU version that increase efficiency by about 10 times
The test results in the same environment are as follows:
646464--->5ms
128128128--->7ms
256256256--->19ms
512512512--->121ms
102410241024--->728ms
204820482048---->5576ms

Issues in Setting up Cuda Voxelizer

Hi,
I've been running into a lot of trouble setting up the repo and it's probably because I'm extremely new to the art of supporting C++ dependencies.
My rig right now:
Windows 10 win64, Visual Studio v141, and the CUDA 9.2 toolset

I also downloaded the prebuilt libraries of trimesh2 (your version) and added libWin64v141 to src. I also got the 'release' version not the debug version.
I also downloaded Trimesh2 repo and added the header files to src.
I also got glm and added the glm folder in include to src.

As of now when I try to build the binaries on Visual Studio, I get the following link error:
unrecognized flag 'Ot' not in 'p2'.
Based on my debugging it seems that this is because trimesh was compiled differently from my cuda_voxelizer solution build. But I am sure my build is Release, 64 and v141, the same as Trimesh.
Any help is much appreciated.

What is the "unit length"? Does gridsize represent the size of a voxel?

I am attempting to create a CPU version of this code. In that effort, I have figured out what part of voxelize_triangle() does, but I need a hand.

What is this "unit length" (unit.x, unit.y, unit.z)? It is the dimensions of the bounding box divided by "gridsize". That would seem to suggest unit length is the number of voxels in each direction, with gridsize being the width of a voxel in each direction. Is that true?

Does that mean this code supports voxels that aren't perfect cubes?

Maybe some of the code has to do with tiling, something I won't need to do and don't totally follow.

Further, I don't follow what the critical point and delta_p are used for. Neither are changed within the voxelize_triangle loop, but both are used. It's very odd.

In any case, here is what I have so far for my rough overview of what the code is doing:

for all triangles...

// fetch the triangle's 9 coordinates (3 vertices)
// compute the edge vectors
// use edge vectors to get tri's normal
// get tri's bounding box in global coordinates (not relative to grid)
// get "t_bbox_grid" (I don't really follow this part. If unit.x is number of voxels in x direction, I don't see what this does. I know what clamp is, though)
// without knowing the prior step, don't want to speculate on the rest

Thanks for any assistance!

What the does the `TopLeftEdge` mean

Hi, thanks for sharing this code and I'm experimenting the code.
I don't quite understand the TopLeftEdge function

__device__ inline bool TopLeftEdge(glm::vec2 v0, glm::vec2 v1)

  • Is this check necessary?
  • What does it mean in geometry, does it mean the top left edge of a triange as the name implies, if yes why we should do this check?

cmake error

/data/guojingfeng/trimesh2/include/Color.h(165): error: more than one instance of overloaded function "cbrt" matches the argument list:
function "cbrt(float)"
function "std::cbrt(float)"
argument types are: (float)

/data/guojingfeng/trimesh2/include/Color.h(165): error: more than one instance of overloaded function "cbrt" matches the argument list:
function "cbrt(float)"
function "std::cbrt(float)"
argument types are: (float)

1 error detected in the compilation of "/tmp/tmpxft_000027fe_00000000-6_voxelize_solid.cpp1.ii".
CMakeFiles/cuda_voxelizer.dir/build.make:160: recipe for target 'CMakeFiles/cuda_voxelizer.dir/src/voxelize_solid.cu.o' failed
make[2]: *** [CMakeFiles/cuda_voxelizer.dir/src/voxelize_solid.cu.o] Error 1
make[2]: *** Waiting for unfinished jobs....
1 error detected in the compilation of "/tmp/tmpxft_000027fb_00000000-6_voxelize.cpp1.ii".
CMakeFiles/cuda_voxelizer.dir/build.make:145: recipe for target 'CMakeFiles/cuda_voxelizer.dir/src/voxelize.cu.o' failed
make[2]: *** [CMakeFiles/cuda_voxelizer.dir/src/voxelize.cu.o] Error 1
CMakeFiles/Makefile2:82: recipe for target 'CMakeFiles/cuda_voxelizer.dir/all' failed
make[1]: *** [CMakeFiles/cuda_voxelizer.dir/all] Error 2
Makefile:90: recipe for target 'all' failed
make: *** [all] Error 2

Can you help me figure out what the problem is?

Is it a bug in src/main.cpp ?

size_t vtable_size = static_cast<size_t>(ceil(static_cast<size_t>(voxelization_info.gridsize.x) * static_cast<size_t>(voxelization_info.gridsize.y) * static_cast<size_t>(voxelization_info.gridsize.z)) / 8.0f)

Should we ceil it after '/ 8.0f' ?

Wrong axis order for Equation 2 for ZX plane (d_xz_ei) in voxelize.cu

I think I noticed something I think is slightly off in the implementation of equation 2 (second part where one calculates d) inside voxelize.cu in lines 131 - 133. For each edge projection into the ZX plane there is written:
float d_xz_ei = (-1.0f * glm::dot(n_zx_ei, glm::vec2(v0.z, v0.x))) + glm::max(0.0f, info.unit.x*n_zx_ei[0]) + glm::max(0.0f,info.unit.z*n_zx_ei[1]);
but shouldnt the supplied axis to each max function actually be the same order as the previous two plane projections? For example XY where the first call to max has the first axis X like info.unit.x * n_xy_ei[0] and the second call to max has the second axis Y like info.unit.y * n_xy_ei[1].
For the ZX axis this would look like:
float d_xz_ei = (-1.0f * glm::dot(n_zx_ei, glm::vec2(v0.z, v0.x))) + glm::max(0.0f, info.unit.z*n_zx_ei[0]) + glm::max(0.0f,info.unit.x*n_zx_ei[1]);
I think for the end product it does not matter currently as info.unit.x/y/z are the same at the moment (gridSize in main.cpp) but technically it is still wrong, or am i missing something here?

Windows error

Hi,

capture

Could you please help me ?

My OS is Windows 10 & i'm using VS 15.

thnx.

VTK support

Hi,
Is VTK (Legacy file format) supported for input?

Problems for building cuda_voxelizer in Linux

GLM is mostly headers and it doens't have a library to be linked so there is no need to include it in TARGET_LINK_LIBRARIES and because Cmake can not find it, it is better that its include directory be set by the user the same as trimesh2.

Official Linux releases

Currently it looks like one has to build for Linux manually. Unfortuantely I am not experienced in that and also there is not much documentation here about how to do that. I suspect it requires some pre setup of dependencies and is not just a simple command?

Thus it would be helpful having a Linux release available for download.

glm/glm.hpp: No such file or directory

Can't build on Ubuntu 16.04 even if I set up the GLM_INCLUDE_DIR correctly.
cuda_voxelizer/./src/thrust_operations.cuh:14:23: fatal error: glm/glm.hpp: No such file or directory

Axis-aligned surfaces problem mentioned in util.h

Hi,@Forceflow
I have found the reason which caused the problem that you mentioned in util.h.
In cpu_voxelizer.cpp Line 133 to Line 135
and voxelize.cu Line 131 to Line 133
The positions of z and x in these lines of code are wrong.
The modified code could be

float d_xz_e0 = (-1.0f * glm::dot(n_zx_e0, glm::vec2(v0.z, v0.x))) + glm::max(0.0f, info.unit.z * n_zx_e0[0]) + glm::max(0.0f, info.unit.x * n_zx_e0[1]);
float d_xz_e1 = (-1.0f * glm::dot(n_zx_e1, glm::vec2(v1.z, v1.x))) + glm::max(0.0f, info.unit.z * n_zx_e1[0]) + glm::max(0.0f, info.unit.x * n_zx_e1[1]);
float d_xz_e2 = (-1.0f * glm::dot(n_zx_e2, glm::vec2(v2.z, v2.x))) + glm::max(0.0f, info.unit.z * n_zx_e2[0]) + glm::max(0.0f, info.unit.x * n_zx_e2[1]);

After modifying these codes, the problems mentioned in #7 should not happen again :)

Missing include directory in CMakeLists.txt

CMakeList.txt only specifies

INCLUDE_DIRECTORIES(${Trimesh2_INCLUDE_DIR})

but it should be

INCLUDE_DIRECTORIES(${Trimesh2_INCLUDE_DIR} ${GLM_INCLUDE_DIR})

if I am not mistaken.

Edit: Reading the readme helps

Linux compatibility

Hi,

Greate code, I'm trying to compile the code in linux but I'm having a wrong voxel grid (doesn't look ok) than the one in windows? any idea about the difference ?

Thanks

Solid Voxels

Hello,

I was wondering if your software can generate solid voxels. I noticed that with
the example, I get only the surface voxels.

Regards.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.