# Graphics3D: Objects with holes

In a recent project, I found out that there is a big limitation when using Graphics3D to construct objects - it lacks the ability to construct objects with holes in them. For example, we can get a regular wall-like Graphics3D object with the Cuboid primitive, but we can not get a wall with a window. Like this one

Naturally, a Boolean operation is the way to go. But, in Mathematica the functions belonging to Boolean operations class, like RegionUnion and RegionIntersection can not be used in Graphics3D

Is there a way to construct Graphics3D objects with holes in them ?

• – kglr
Commented Jan 28, 2015 at 10:38
• @kguler nice. To answer OP question, then one can just do cub1 = Cuboid[{0, 0, 0}, {20, 2, 20}]; cub2 = Cuboid[{12, 0, 8}, {17, 2, 17}]; r2 = RegionDifference[cub1, cub2]; RegionPlot3D[r2] !Mathematica graphics but the edges need some work. Original question at community.wolfram.com/groups/-/m/t/430092?p_p_auth=EAP2rQun Commented Jan 28, 2015 at 11:08
• that post at wolfram is also mine. thanks for your suggestion very much! Commented Jan 28, 2015 at 11:17
• Commented Jan 28, 2015 at 14:07
• Actually just wrap Show around mesh object. See the Community link I posted - there are mo answers there. Commented Jan 28, 2015 at 17:54

This is a repost of Wolfram Community answer

cub1 = Cuboid[{0, 0, 0}, {20, 2, 20}];
cub2 = Cuboid[{12, 0, 8}, {17, 2, 17}];
Graphics3D[{cub1, cub2}];
reg = DiscretizeRegion[RegionDifference[cub1, cub2]]


You have a lot of tetrahedrons:

MeshCells[reg, 3] // Length


10093

And a lot of polygons:

MeshCells[reg, 2] // Length


22096

You do not need all that for visual, - so get the surface (boundary):

surface = BoundaryDiscretizeRegion[reg];
polygons = MeshCells[surface, 2];
polygons // Length


3820

Now so few polygons! Get the coordinates of the mesh too:

points = MeshCoordinates[surface];
points // Length
> 1910


And here you go:

Graphics3D[{EdgeForm[Gray],
GraphicsComplex[points, Polygon[polygons /. Polygon[x_] -> x]]},
Boxed -> False, Lighting -> "Neutral"]


• Why not use BoundaryDiscretizeRegion instead of DiscretizeRegion? (You get even fewer polygons.) Commented Jan 28, 2015 at 14:33
• @MichaelE2 sure just was in a Rush ;) Commented Jan 28, 2015 at 14:59
• This is not working in MM 12.1.1 I get an error "A non-degenerate region is expected at position..." Any thoughts?
– Lou
Commented Jun 23, 2020 at 12:33

Here's one way.

I'm going to use the contourRegionPlot3D function from here. I include the function definition here for convenience:

contourRegionPlot3D[region_, {x_, x0_, x1_}, {y_, y0_, y1_}, {z_, z0_, z1_},
opts : OptionsPattern[]] := Module[{reg, preds},
reg = LogicalExpand[region && x0 <= x <= x1 && y0 <= y <= y1 && z0 <= z <= z1];
preds = Union@Cases[reg, _Greater | _GreaterEqual | _Less | _LessEqual, -1];
Show @ Table[ContourPlot3D[
Evaluate[Equal @@ p], {x, x0, x1}, {y, y0, y1}, {z, z0, z1},
RegionFunction -> Function @@ {{x, y, z}, Refine[reg, p] && Refine[! reg, ! p]},
opts], {p, preds}]]


Now create a region from the Graphics3D objects:

c1 = Cuboid[{0, 0, 0}, {20, 2, 20}];
c2 = Cuboid[{12, 0, 8}, {17, 2, 17}];
c3 = Cylinder[{{5, -1, 10}, {5, 2, 10}}, 3];
reg = Fold[RegionDifference, c1, {c2, c3}];


Use RegionMember to turn this into inequalities:

ineqs = Rest @ RegionMember[reg, {x, y, z}]


0 <= x <= 20 && 0 <= y <= 2 && 0 <= z <= 20 && ! (12 <= x <= 17 && 0 <= y <= 2 && 8 <= z <= 17) && ! (0 <= (1 + y)/3 <= 1 && (-5 + x)^2 + (-10 + z)^2 <= 9)

And then:

contourRegionPlot3D[ineqs, {x, 0, 20}, {y, 0, 2}, {z, 0, 20},
Mesh -> None, BoxRatios -> Automatic, PlotRange -> All, Boxed -> False, Axes -> False]