17

I want to draw a solid or partially transparent hemisphere above a partially transparent cuboid object in Graphics3D. However, I do not know how to do this such that only half the sphere is drawn. Here's what the object looks like with the full sphere:

SphereOpacity = 0.5;
CuboidOpacity = 0.5;
SphereColor = Blue;
CuboidColor = Orange;
Graphics3D[{SphereColor, Opacity[SphereOpacity], Sphere[{0, 0, 0.5}, 0.5], 
            CuboidColor, Opacity[CuboidOpacity], Cuboid[{-5, -5, 0}, {5, 5, 0.5}]}, 
            Boxed -> False
]

figure

How might I proceed to "remove" the bottom half the sphere embedded in the cuboid primitive? In general, is there a way to not render/draw parts of a graphics primitive conditioned intersection with another primitive?

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
QuadraticU
  • 421
  • 3
  • 9

9 Answers9

12

This peculiar method works in Mathematica versions 7 (thanks, Mr. Wizard!) and 8, but apparently no longer in version 9 onwards (per rm and Reb.Cabin):

Graphics3D[{CapForm["Round"], Tube[{{0, 0, 0}, {0, 0, 0}}, {0, 1}]}, Boxed -> False]

half a ball

(I know CapForm["Round"] can be omitted, since it's the default; I just wanted to indicate that it's the reason for this behavior.)

Replace the 1 with your desired radius. As has been noted, if you need to put your hemispheres into an arbitrary position/orientation, GeometricTransformation[] comes in handy.


A workaround suggested by Pickett for version 9 involves a slight perturbation of one of the endpoints, like so:

With[{r = 1, ε = $MachineEpsilon},
     Graphics3D[{CapForm["Round"], Tube[{{0, 0, 0}, {0, 0, ε r}}, {0, r}]}, 
                Boxed -> False]]
J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
12

To show that there's more than one way to skin a cat, here's another primitive-based method, using NURBS surfaces to render a hemisphere:

With[{r = 1}, 
     Graphics3D[{EdgeForm[],
                 BSplineSurface[Outer[Append[First[#1] #2, Last[#1]] &, 
                       r {{0, 1}, {1, 1}, {1, 0}},
                       {{1, 0}, {1, 1}, {-1, 1}, {-1, 0}, {-1, -1}, {1, -1}, {1, 0}}, 1], 
                                SplineClosed -> {False, True}, SplineDegree -> 2, 
                                SplineKnots -> {{0, 0, 0, 1, 1, 1},
                                                {0, 0, 0, 1/4, 1/2, 1/2, 3/4, 1, 1, 1}}, 
                                SplineWeights -> Outer[Times, {1, 1/Sqrt[2], 1},
                                                       {1, 1/2, 1/2, 1, 1/2, 1/2, 1}]]},
                BaseStyle -> {BSplineSurface3DBoxOptions ->
                              {Method -> {"SplinePoints" -> 40}}}, Boxed -> False]]

another hemisphere

Change r to vary the radius; the control points in the first argument of BSplineSurface[] can be translated and rotated, if the hemisphere needs to be positioned/oriented differently.

If you're interested in this sort of thing, you can refer to work by Piegl and Tiller, e.g. this paper and their book.


Here's another NURBS representation of a hemisphere:

With[{r = 1}, 
     Graphics3D[{EdgeForm[], 
                 BSplineSurface[Outer[Insert[First[#1] #2, Last[#1], 2] &, 
                                      r {{0, -1}, {1, -1}, {1, 1}, {0, 1}},
                                      {{-1, 0}, {-1, 1}, {1, 1}, {1, 0}}, 1],
                                SplineDegree -> 2, 
                                SplineKnots -> {{0, 0, 0, 1/2, 1, 1, 1},
                                                {0, 0, 0, 1/2, 1, 1, 1}},
                                SplineWeights -> Outer[Times, {1, 1/2, 1/2, 1},
                                                              {1, 1/2, 1/2, 1}]]}, 
                BaseStyle -> {BSplineSurface3DBoxOptions ->
                              {Method -> {"SplinePoints" -> 40}}}, Boxed -> False]]

still another hemisphere

N.B. The previous version of this answer featured BSplineSurface[] objects with noticeable blemishes; this turned out to be due to insufficient internal sampling. Adding the option BaseStyle -> {BSplineSurface3DBoxOptions -> {Method -> {"SplinePoints" -> 40}}} (similar to what Mr. Wizard did here) minimizes the blemishes to a barely noticeable spot.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
9
ParametricPlot3D[{Cos[u] Sin[v], Sin[u] Sin[v], Cos[v]}, 
                 {u, 0, π}, {v, 0, π},             
                 Mesh -> None, 
                 Boxed -> False, 
                 Axes -> None
]

some hemisphere

r = 0.5;
d = {0, 0, 0.5}
sphere = ParametricPlot3D[r {Cos[u] Sin[v], Sin[u] Sin[v], Cos[v]} + d, 
            {u, -π/2, π/2}, {v, -π/2, π/2}, 
            Mesh -> None, Boxed -> False, Axes -> None][[1]];

SphereOpacity = 0.5;
CuboidOpacity = 0.5;
SphereColor = Blue;
CuboidColor = Orange;
Graphics3D[{SphereColor, Opacity[SphereOpacity], sphere, CuboidColor, 
            Opacity[CuboidOpacity], Cuboid[{-5, -5, 0}, {5, 5, 0.5}]}, 
           Boxed -> False]

hemisphere and box

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Sjoerd C. de Vries
  • 65,815
  • 14
  • 188
  • 323
7

Here is another simple way to draw a hemisphere that makes use of the symmetry axis:

hemisphere = 
  First@RevolutionPlot3D[Sqrt[1 - r^2], {r, 0, 1}, Mesh -> None];

Here you can vary the option PlotPoints if needed, to get a more or less dense polygon mesh.

I also extract the contents of the Graphics3D object before using it. This needs to be done whenever you plan to combine the result of a Plot3D-related function with other objects in a single Graphics3D (and be able to do translations, rotations, etc. on the individual objects). To show how it works, here is an example:

plant = First@ExampleData[{"Geometry3D", "PottedPlant"}];

Graphics3D[{
  Translate[
   Scale[Rotate[
     {Brown,
      hemisphere},
     {{0, 0, -1}, {0, 0, 1}}], 25],
   {0, 0, 28}],
  {Darker[Green], plant}
  },
 Lighting -> "Neutral",
 Boxed -> False]

pottedplant

Edit: a raster based approach in version 9

Motivated by cormullion's answer, here is another way:

data3D = With[{reso = .05},
   Table[Boole[x^2 + y^2 + z^2 <= 1
          && 
       z >= 0 || (-5 < x < 5) && (-5 < y < 5) && (-0.5 < z < 
         0)], {x, -2, 2, reso}, {y, -2, 2, reso}, {z, -2, 2, reso}]
   ];

Image3D[data3D]

image3d

The Image3D command is not available before version 9, and its rasterized output may not be desirable - but it has a certain appeal in that you get something similar to a RegionPlot3D, but with a more volumetric appearance.

Jens
  • 97,245
  • 7
  • 213
  • 499
6

Since no-one has done a RegionPlot3D, I'll do one.

RegionPlot3D[
   x^2 + y^2 + z^2 <= 1
   &&
   z >= 0 ||  
   (-5 < x < 5) && (-5 < y < 5) && (-0.5 < z < 0),
 {x, -2, 2}, {y, -2, 2}, {z, -2, 2},
 Mesh -> None,
 PlotPoints -> 120, 
 PlotStyle -> Directive[Orange, Specularity[Yellow, 12], Opacity[0.8]],
 Boxed -> False,
 Lighting -> {{"Directional", White, {{5, 5, 4}, {2, 2, 0}}}},
 BoundaryStyle -> None, 
 ImageSize -> 600,
 Axes -> False]

plot

RegionPlot3D plots always seem to have that 'home-made' look about them...

cormullion
  • 24,243
  • 4
  • 64
  • 133
  • (+1) That gave me another idea: Image3D... – Jens May 11 '13 at 21:51
  • It's also a bit slower than the other methods; it may be worth it to get the neat little "weld" seam, and that little seam might be really helpful if you want to tet-volume-mesh or other discretize this composite shape. – Reb.Cabin Jul 20 '15 at 12:26
3

ClipPlanes

In versions 10.0+, we can simply replace Sphere[...] with {ClipPlanes -> {0, 0, 1, -.5}, Sphere[...]} to get the desired output: :

Graphics3D[{SphereColor, Opacity[SphereOpacity],
  {ClipPlanes -> {0, 0, 1, -.5}, Sphere[{0, 0, 0.5}, 1]},
  CuboidColor, Opacity[CuboidOpacity], Cuboid[{-5, -5, 0}, {5, 5, 0.5}]},
 Boxed -> False, ImageSize -> Medium]

enter image description here

Grid[
 Table[
      Graphics3D[{ClipPlanes -> s p, Sphere[]}, 
        PlotLabel -> Style[s p, 16], ImageSize -> Small], 
    {s, {1, -1}}, {p, Append[0] /@ IdentityMatrix[3]}], 
 Dividers -> All]

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
2

Using whuber's method, we can generate a hemisphere with elevation $\alpha$ and horizon $\theta$ using ContourPlot as follows:

α = 0;
θ = 0;

normal = Cross[{Cos[θ], Sin[θ], 0}, {Cos[α] (-Sin[θ]), Cos[α] Cos[θ], Sin[α]}];

ContourPlot3D[x^2 + y^2 + z^2, {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
 Contours -> {1}, ContourStyle -> Opacity[0.5], Mesh -> None, 
 RegionFunction -> Function[{x, y, z}, normal.{x, y, z} >= 0]]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
QuadraticU
  • 421
  • 3
  • 9
2

I made a function out of Sjoerd's answer because I feel the need to make a hemisphere is something that more people experience.

hemisphere[n_, r_, origin_ : {0, 0, 0}, closed_ : False] := 
 Module[{R, defaultplotstyle},
  R = RotationTransform[{{0, 1, 0}, -n}];
  defaultplotstyle = ("DefaultPlotStyle" /. (Method /. 
         Charting`ResolvePlotTheme[Automatic, Plot3D]))[[1]];
  ParametricPlot3D[
   {
    R[r {Cos[\[Pi] u] Sin[\[Pi] v], Sin[\[Pi] u] Sin[\[Pi] v], 
       Cos[\[Pi] v]}],
    If[closed, R[r v {Cos[2 \[Pi] u], 0, Sin[2 \[Pi] u]}], 
     Sequence[{}]]
    },
   {u, 0, 1}, {v, 0, 1},
   Mesh -> None, PlotStyle -> {defaultplotstyle, defaultplotstyle}
   ]
  ]

Here n is a normal vector such that the open end of the hemisphere points in the direction of the normal, r is the radius, origin is the center of the hemisphere and closed can be set to true if you want the open end to be closed off.

Result:

enter image description here

Source for getting default plotstyle: https://mathematica.stackexchange.com/a/172149/45428

2

One could also make use of Region and ImplicitRegion:

Region[ImplicitRegion[x^2 + y^2 + z^2 <= 1 && z >= 0, {x, y, z}]]

The previous object can be used in the following way:

hemisphere = 
  Region[ImplicitRegion[x^2 + y^2 + z^2 <= 5 && z >= 0, {x, y, z}]];
Show[
 {
  hemisphere,
  Graphics3D[{Red, Opacity[0.5], Cuboid[{-5, -5, 0}, {5, 5, 0.5}]},
   Boxed -> False]
  }
 ]

Results look as shown on the next images; the first one is the actual hemisphere and the second one is the hemisphere on a cuboid.

This the hemisphere object This is the hemisphere on a cuboid Cheers,

Coti
  • 31
  • 5