CSG Report
CSG Report
Spring 2013
Abstract
Constructive solid geometry (CSG) is a pivotal component of CAD and CAE packages. CSG allows us to represent complex
shapes and models as a series of Boolean operations between primitives. For example, punching a hole through a cube
would be difficult to represent with an implict or explicit funciton. The CSG algorithm we have developed allows something
like this to be represented as a simple Boolean operation between a cube and cyllinder. Here we present an implementation
of CSG using an efficient spatial datastructure called a binary space partitioning tree (BSP tree). These BSP trees allow us
to perform Boolean operations on complex models in a matter of milliseconds. In this paper, we validate our concept and
implementation by performing Boolean operations on a series of intracate models. The results show our algorithm is efficient
and accurate.
Keywords
Computer-aided design(CAD) — Constructive solid geometry(CSG) — Binary space partitioning(BSP)
1 [email protected]
2 [email protected]
3 [email protected]
2. Algorithm
One of the key problems in computer aided design and graph-
ics is determining what objects are visible relative to one
another, with a constantly changing viewpoint (Figure 4).
Furthermore, the problem of surface to surface interference
is difficult to classify for models with a complex geometry.
When a scene or rendering consists of several models, this
problem becomes even more difficult. Figure 4. Concept of CSG in 3D
In order to resolve these issues, graphics software engi-
neers utilize a spatial data structure known as a binary space
partitioning tree (a.k.a. BSP tree). The BSP tree represents a side of the plane, f1 (p− ) < 0. Using this property of implicit
way to recursively divide a scene along two sides of a plane, planes we can define on which side of the plane a triangle
until some partitioning criterion is met. There are many simi- (consisting of three points) lies. Initially, let us assume that all
lar data structures known to computer graphics, (octrees, k-d of the triangles in our scene are either on one side of our parti-
tree, bounding box hierarchy etc.) but BSP trees provide us tioning plane defined by our triangle (Figure 5, Figure 6). We
with the most flexibility in partitioning our scene. That flexi- can pick one of the triangles and partition the other triangles
bility results from our ability to orient the partitioning plane about it with pseudo code in Algorithm 1.
in any direction, without being constrained by orthogonality This example can be generalized to many object, again
as in octrees or k-d trees. assuming the simple case where none of our polygons span our
dividing plane. In this example, f1 (p) is the implicit function
2.1 Create BSP tree of a plane created by triangles with counter clockwise vertices
The construction of a BSP tree is simple to visualize. Image a, b, and c:
a scene consisting of three triangles. The key properties of
the implicit planes these triangles define in 3D space is that f1 (p) = ((b − a) × (c − a)) · (p − a) = 0 (1)
for all points on one side of the plane p+ we can easily create
a function f1 (p+ ) > 0. Similarly for all points on the other However it can be faster to store the values of the implicit
Constructive Solid Geometry Using BSP Tree — 3/7
Ax + By +Cz + D = 0 (2)
D = −n · a (3)
(a) Multi-plane in 3D space (b) BSP tree representation Algorithm 2 BSP tree initial pseudo code
Require: tree.node = triangles[0]
Figure 5. BSP tree creation (without intersection) 1: for i = 2 → N do
2: tree.add(triangles[i])
3: end for
4: function ADD (triangle T)
5: if f (a) < 0 ∧ f (b) < 0 ∧ f (c) < 0 then
6: if back-subtree does not exist then
7: create back-subtree
8: back-subtree.node = T
9: else
10: front-subtree.add(T)
11: end if
12: else if f (a) > 0 ∧ f (b) > 0 ∧ f (c) > 0 then
13: if front-subtree does not exist then
14: create front-subtree
15: front-subtree.node = T
16: else
17: front-subtree.add(T)
(a) Multi-plane in 3D space (b) BSP tree representation 18: end if
19: end if
Figure 6. BSP tree creation (with intersection) 20: end function
equal to:
T1 = (a, b, A)
T2 = (b, B, A) (4)
T3 = (A, B, c)
It is clear from this representation that a special case will Algorithm 3 BSP tree final pseudo code
emerge when the triangle is split perfectly down the middle.
Although rare, We will account for this by not splitting the Require: f a = f (a), f b = f (b), f c = f (c)
triangles if this occurs. Thus our final implementation of the 1: function ADD (triangle T)
BSP tree creation is shown in Algorithm 3. 2: if | f a| < ε then
The last component of building our BSP tree is computing 3: fa = 0
A and B. Computing the A and B intersection points consist 4: end if
of simply solving a ray-plane intersection equation: 5: if | f b| < ε then
6: fb = 0
7: end if
p(t) = a + t(c − a) 8: if | f a| < ε then
n · (a + t(c − a)) + D = 0 9: fb = 0
n·a+D (5)
t =− 10: end if
n · (c − a) 11: if f a ≤ 0 ∧ f b ≤ 0 ∧ f c ≤ 0 then
A = a + t(c − a)
12: if back-subtree does not exist then
Our creation algorithm for a BSP tree is now complete. 13: created back-subtree
14: back-subtree.node = T
2.2 Merge two trees 15: else
Because of their ability to divide a series of polygons by an 16: back-subtree.add(T)
arbitrarily chosen plane, BSP trees offer the ideal data struc- 17: end if
ture to perform Boolean operations on arbitrary pieces of 18: else if f a ≥ 0 ∧ f b ≥ 0 ∧ f c ≥ 0 then
geometry. In order to perform these operations, we have de- 19: if front-subtree does not exist then
veloped an algorithm that ”merges” two BSP trees. Assuming 20: create front-subtree
a simple case of just two models in a scene with which we 21: front-subtree.node = T
want to perform Boolean operations, the first thing we need 22: else
to do is create BSP trees for both of the geometries. These 23: front-subtree.add(T)
trees are created independently for each geometry initally, 24: end if
so we will only be testing polygons in one model for each 25: else
BSP tree creation. When we create these BSP trees, instead 26: cut the triangle
of simply arbitrarily choosing planes to divide the polygons 27: end if
by, we will choose to divide the polygons by the polygons 28: compute A
on the surface of the model. Thus these BSP trees allow us 29: compute B
to create an efficient structure to traverse the boundaries of 30: T1 = (a, b, A)
a complicated mesh. Now that we have two representations 31: T2 = (b, B, A)
of the boundaries of the models, we begin to merge them by 32: T3 = (A, B, c)
traversing one of the trees to obtain a list of polygons that 33: if f c ≥ 0 then
represent the surface boundary of one of the models. We use 34: back-subtree.add(T1 )
this list of polygons because it contains new polygons created 35: back-subtree.add(T2 )
by splitting the polygons of the model by the dividing planes 36: front-subtree.add(T3 )
chosen when creating the tree. These could not be captured if 37: else
we just used the list of polygons provided with the model for 38: front-subtree.add(T1 )
the next step in the merging algorithm. The traversal of the 39: front-subtree.add(T2 )
BSP tree is quite simple as shown in Algorithm 4. 40: back-subtree.add(T3 )
This will give us a list of polygons represented as a pre- 41: end if
order traversal of the tree. Now that we have a list of polygons 42: end function
from the tree that represents model A, we have to push these
polygons through the tree of model B so that we can see how
they will be classified according to B’s dividing polygons.
Algorithm 5 looks very similar to the add function listed
above. This algorithm assumes that we are working with
models made up of only triangles.
Constructive Solid Geometry Using BSP Tree — 5/7
Acknowledgments
Thanks to Professor Kenji Shimada for his excellent lectures
which gave us enough background knowledge to start and fin-
ish this project. We appreciate his advice during the semester.
References
[1] B. Naylor, J. Amanatides and W. Thibault, Merging BSP
Trees Yields Polyhedral Set Operations, in Proc. Siggraph
’90, Computer Graphics 24(4), pp 115-124, 1990.
[2] Miklo Lysenko, Roshan D’Souza and Ching-Kuang Shene,
in Improved Binary Space Partition Merging, CAD, Vol. 40,
No. 12, pp. 1113-1120, 2009.
[3] Shirley, Peter et. al, in Fundamentals of Computer Graph-
Figure 12. CSG of werewolf & cube
ics, 3rd ed. Wellesley: A K Peters, 2009.
[4] Tom Duff, Interval arithmetic recursive subdivision
of models consisting of more than two geometries. In doing for implicit functions and constructive solid geometry,
so, we would enable Boolean operation chaining, where we inSIGGRAPH ’92, 1992.
would created composite models from our base models, and [5] H. Jones, in Computer Graphics.: Through Key Mathe-
then further perform other Boolean operations on our compos-
matics, pp. 227, 2001.
ite models for more impressive and complex results. In the
[6] https://en.wikipedia.org/wiki/
next stage of our software, we would like to take use voxel
representations of our models as input and output to our CSG Constructive_solid_geometry
algorithm. In doing so, we allow OpenGL to also render the [7] http://glscene.sourceforge.net/
volumetric information after performing the Boolean opera- oldsite/Gallery/boxedin_h.jpg
tions on the pair of models. This would enable a higher level [8] http://ars.els-cdn.com/content/image/
of accuracy and an easier visual understanding of our results
1-s2.0-S0010448508002030-gr3.jpg
since we would no longer be rendering just the surfaces of the
[9] http://exocortex.com/products/implosia
models, but the a solid in itself (Figure 13). Our algorithm,
though efficient, lacks any optimization that can be achieved [10] http://www.cs.cmu.edu/afs/cs/
with tree balancing or parallel programming. Implementing academic/class/15462-s13/www
these would further speed up our algorithm execution. Lastly,
we would look for different methods to eliminate the geom-
etry artifacts that appear in some of the results. We could
automatically increase the number of polygons in a model by
splitting surface faces into smaller polygons and get rid of
these artifacts entirely. Furthermore, we could attempt to run
the algorithm on the polygons themselves instead of having
to split the all non-triangular polygons into triangles. This
would also speed up the process and help eliminate the root
of the artifacts problem.