33

If I construct a shape using constructive solid geometry techniques, how can I construct a wireframe mesh for rendering? I'm aware of algorithms for directly rendering CSG shapes, but I want to convert it into a wireframe mesh just once so that I can render it "normally"

To add a little more detail. Given a description of a shape such as "A cube here, intersection with a sphere here, subtract a cylinder here" I want to be able to calculate a polygon mesh.

Martin
  • 12,469
  • 13
  • 64
  • 128

7 Answers7

23

There are two main approaches. If you have a set of polygonal shapes, it is possible to create a BSP tree for each shape, then the BSP trees can be merged. From Wikipedia,

1990 Naylor, Amanatides, and Thibault provide an algorithm for merging two bsp trees to form a new bsp tree from the two original trees. This provides many benefits including: combining moving objects represented by BSP trees with a static environment (also represented by a BSP tree), very efficient CSG operations on polyhedra, exact collisions detection in O(log n * log n), and proper ordering of transparent surfaces contained in two interpenetrating objects (has been used for an x-ray vision effect).

The paper is found here Merging BSP trees yields polyhedral set operations.

Alternatively, each shape can be represented as a function over space (for example signed distance to the surface). As long as the surface is defined as where the function is equal to zero, the functions can then be combined using (MIN == intersection), (MAX == union), and (NEGATION = not) operators to mimic the set operations. The resulting surface can then be extracted as the positions where the combined function is equal to zero using a technique like Marching Cubes. Better surface extraction methods like Dual Marching Cubes or Dual Contouring can also be used. This will, of course, result in a discrete approximation of the true CSG surface. I suggest using Dual Contouring, because it is able to reconstruct sharp features like the corners of cubes .

Joe
  • 2,008
  • 1
  • 17
  • 25
  • Also, note that Dual Contouring requires normal information, in addition to the distance function information needed by marching cubes. (Though you can compute normals by taking the gradient of the signed distance function.) – batty Feb 25 '10 at 04:54
  • To clarify about batty's comment on taking the gradient, you want to make sure that you take the gradient of the function as close to on the surface as possible. If the function is defined over all space rather than just at regular intervals, you can perform a binary search along edges to make sure that you find the surface intersection. If you don't care about sharp features, you can still use Dual Contouring and simply place dual vertices at the average of the edge intersections in a cell. – Joe Feb 28 '10 at 03:08
  • 7
    Updated links: http://www.gilbertbernstein.com/resources/booleans2009.pdf and http://www.graphics.rwth-aachen.de/media/papers/campen_2010_eg_021.pdf – Warty May 11 '14 at 21:37
  • 1
    One author of Fast, Exact, Linear Booleans has a project named "cork" on github that implements mesh-based CSG: https://github.com/gilbo/cork. His site http://www.gilbertbernstein.com/project_boolean.html indicates that this is _not_ the same method as that of the paper. – Nathan May 15 '15 at 18:27
4

These libraries seems to do what you want:

www.solidgraphics.com/SolidKit/ carve-csg.com/ gts.sourceforge.net/

Roman
  • 41
  • 1
  • Wow, I had given up on this ever being answered. Fortuitously, you answered just as I regained interest in this project. I'll go and check these out and see if they do what I need. Thanks! – Martin Apr 25 '10 at 21:06
  • the GTS library is open source and fast, look great. Now to see if I can get it running with C# ;) – Martin Apr 25 '10 at 21:13
  • Unfortunately I can't make it work with C#. I also realised that I can't use any native code libraries because this needs to be able to run on xbox, so managed code only :( – Martin Apr 29 '10 at 09:30
  • The SolidKit Library provides also version for .NET. It is not free however. – Roman May 12 '10 at 03:19
3

See also "Constructive Solid Geometry for Triangulated Polyhedra" (1990) Philip M. Hubbard doi:10.1.1.34.9374

2

Here are some Google Scholar links which may be of use.

From what I can tell of the abstracts, the basic idea is to generate a point cloud from the volumetric data available in the CSG model, and then use some more common algorithms to generate a mesh of faces in 3D to fit that point cloud.

Edit: Doing some further research, this kind of operation is called "conversion from CSG to B-Rep (boundary representation)". Searches on that string lead to a useful PDF:

http://www.scielo.br/pdf/jbsmse/v29n4/a01v29n4.pdf

And, for further information, the key algorithm is called the "Marching Cubes Algorithm". Essentially, the CSG model is used to create a volumetric model of the object with voxels, and then the Marching Cubes algorithm is used to create a 3D mesh out of the voxel data.

e.James
  • 116,942
  • 41
  • 177
  • 214
1

I've had some luck with the BRL-CAD application MGED where I can construct a convex polyhedron by intersecting planes using CSG then extract the boundary representation using the command-line g-stl command. Check http://brlcad.org/ Malcolm

  • I just found this question by searching on Google. And then I see that you mention the g-stl tool. I tried some years ago to convert a relatively complicated CSG model built using MGED to STL using that tool. This was in 2009 and I was using the windows build of BRL-CAD. The process always crashed on me. Has there been any improvements on the g-stl tool since then? Is the algorithm behind g-stl known to be robust or good in any way? – Ole Thomsen Buus Oct 29 '12 at 20:25
1

You could try to triangulate (tetrahedralize) each primitive, then perform the boolean operations on the tetrahedral mesh, which is "easier" since you only need to worry about tetrahedron-tetrahedron operations. Then you can perform boundary extraction to get the B-rep. Since you know the shapes of your primitives analytically, you can construct custom tetrahedralizations of your primitives to suit your needs instead of relying on a mesh generation library.

For example, suppose your object was the union of a cube and a cylinder, and suppose you have a tetrahedralization of both objects. In order to compute the boundary representation of the resulting object, you first label all the boundary facets of the tetrahedra of each primitive object. Then, you perform the union operation: if two tetrahedra are disjoint, then nothing needs to be done; both tetrahedra must exist in the resulting polyhedron. If they intersect, then there are a number of cases (probably on the order of a dozen or so) that need to be handled. In each of these cases, the volume of the two tetrahedra needs to be re-triangulated in a way that respects the surface constraints. This is made somewhat easier by the fact that you only need to worry about tetrahedra, as opposed to more complicated shapes. The boundary facet labels need to be maintained in the process so that in the final collection of tetrahedra, the boundary facets can be extracted to form a triangle mesh of the surface.

Victor Liu
  • 3,545
  • 2
  • 24
  • 37
  • Could you explain this in a little more detail? If I understand you correctly you mean have a mesh for each basic csg shape, and then do set operations on the meshes? – Martin Jan 04 '10 at 23:50
  • The basic idea is to perform the operations in even simpler primitives (simplices) instead of the actual CSG primitives. I've added a slightly more detailed example, but the actual details of how to handle all cases of tetrahedron-tetrahedron intersection are more complicated than I can describe here (I've never implemented such a method, nor have I seen an implementation, but the idea is pretty simple). – Victor Liu Jan 05 '10 at 07:33
  • I don't think this reduces the complexity at all. Tet-tet intersections will still be difficult and tetrahedralizing a giving surface is non-trivial at best. – Alec Jacobson Apr 20 '15 at 21:29
1

If you can convert you input primitives to polyhedral meshes then you could use libigl's C++ mesh boolean routines. The following computes the union of a mesh (VA,FA) and another mesh (VB,FB):

igl::mesh_boolean(VA,FA,VB,FB,"union",VC,FC);

where VA is a #VA by 3 matrix of vertex positions and FA is a #FA by 3 matrix of triangle indices into VA, and so on. The technique used in libigl is different from those two mentioned in Joe's answer. All pairs of triangles are intersected against each other (using spatial acceleration) and then resulting sub-triangles are categorized as belonging to the output surface or not.

Alec Jacobson
  • 6,032
  • 5
  • 51
  • 88