17
$\begingroup$

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?

$\endgroup$
4
  • $\begingroup$ One method (using RegionFunction) is shown here. $\endgroup$
    – whuber
    Commented May 10, 2013 at 22:11
  • $\begingroup$ If you're interested in this type of geometry, you might enjoy Yu-sung Chang's presentation. $\endgroup$
    – cormullion
    Commented May 10, 2013 at 23:04
  • $\begingroup$ @cormullion Thanks, I'd love to take a look but your link doesn't quite work? $\endgroup$
    – QuadraticU
    Commented May 10, 2013 at 23:15
  • $\begingroup$ This seems related: mathematica.stackexchange.com/q/3186/121 $\endgroup$
    – Mr.Wizard
    Commented May 11, 2013 at 9:28

9 Answers 9

9
$\begingroup$
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

$\endgroup$
6
  • $\begingroup$ +1 -- but it's a little bit harder to use this technique to draw an arbitrary hemisphere. :-) $\endgroup$
    – whuber
    Commented May 10, 2013 at 22:50
  • $\begingroup$ @whuber Not with help of GeometricTransformation, I'd say. $\endgroup$ Commented May 10, 2013 at 22:55
  • $\begingroup$ @SjoerdC.deVries Just for the sake of future readers, you mean GeometricTransformation right? In any case this is great! $\endgroup$
    – QuadraticU
    Commented May 10, 2013 at 23:14
  • $\begingroup$ @QuadraticU Roger that $\endgroup$ Commented May 10, 2013 at 23:30
  • $\begingroup$ I took the liberty to make this into a function, see my edit $\endgroup$ Commented Jun 1, 2022 at 14:25
12
$\begingroup$

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]]
$\endgroup$
8
  • $\begingroup$ No, it doesn't work in v9... $\endgroup$
    – rm -rf
    Commented May 11, 2013 at 2:29
  • $\begingroup$ What does the result look like, then? $\endgroup$ Commented May 11, 2013 at 2:30
  • 2
    $\begingroup$ Well, it just doesn't work with two identical points... but using e.g. Tube[{{0, 0, 0}, {10^(-10), 0, 0}}, {0, 1}] one can get the right shape even in v9 $\endgroup$
    – C. E.
    Commented May 11, 2013 at 11:24
  • 1
    $\begingroup$ @J.M. Yes, they all give a blank image. The perturbation works though, except for "Butt", which gives a blank image. $\endgroup$
    – rm -rf
    Commented May 11, 2013 at 13:30
  • 1
    $\begingroup$ Confirmed that everything in this answer and its comments is still true in V10.2.0.0, i.e., the original doesn't show anything and the workarounds do. $\endgroup$
    – Reb.Cabin
    Commented Jul 20, 2015 at 12:18
12
$\begingroup$

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.

$\endgroup$
7
  • $\begingroup$ Is there a way to get rid of the blemish? $\endgroup$
    – Mr.Wizard
    Commented May 12, 2013 at 19:26
  • $\begingroup$ I haven't figured out how. Weirdly, if I use B-splines for the full sphere, I don't see nasty spots at the poles. $\endgroup$ Commented May 12, 2013 at 19:28
  • $\begingroup$ Too bad; this method is smoother than the Tube method which shows facets. $\endgroup$
    – Mr.Wizard
    Commented May 12, 2013 at 19:32
  • $\begingroup$ Okay, I found an alternative; the (antipodal) blemishes are now at the rim, but that might be more acceptable to some. $\endgroup$ Commented May 13, 2013 at 2:07
  • 1
    $\begingroup$ @Mr.Wizard, it took more than two years, but I finally got rid of those blemishes. ;) $\endgroup$ Commented Feb 26, 2016 at 2:59
7
$\begingroup$

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.

$\endgroup$
6
$\begingroup$

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...

$\endgroup$
2
  • $\begingroup$ (+1) That gave me another idea: Image3D... $\endgroup$
    – Jens
    Commented May 11, 2013 at 21:51
  • $\begingroup$ 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. $\endgroup$
    – Reb.Cabin
    Commented Jul 20, 2015 at 12:26
3
$\begingroup$

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

$\endgroup$
2
$\begingroup$

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]]
$\endgroup$
1
  • $\begingroup$ This was a bit too long to leave as a comment. $\endgroup$
    – QuadraticU
    Commented May 10, 2013 at 23:11
2
$\begingroup$

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

$\endgroup$
2
$\begingroup$

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,

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.