[Tex/LaTex] Drawing Overlapping 3D cones

tikz-3dplottikz-pgf

I am trying to reconstruct something similar to the following using tikz:
enter image description here

So far, I can roughly produce the tops of each cone at various positions, but I have no idea how to complete the cone shape and furthermore produce the progressive shading with opacity (the cones overlapping each other).

MWE:

\documentclass[12pt,tikz]{standalone}

\usepackage[T1]{fontenc}
\usepackage{tikz,tikz-3dplot}

\tdplotsetmaincoords{80}{45}
\tdplotsetrotatedcoords{-90}{180}{-90}

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
    \coordinate (O) at (0,0,0);


    \draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
    \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
    \draw[->] (0,0,-5) -- (0,0,5) node[above] {$z$};

    \begin{scope} [canvas is xy plane at z=0]
      \draw[fill=blue, fill opacity=0.1] circle (3);
      \end{scope}

    \begin{scope} [canvas is xy plane at z=1.5]
      \draw[fill=blue, fill opacity=0.1] circle (2.5);
      \end{scope}


    \begin{scope} [canvas is xy plane at z=3]
      \draw[fill=blue, fill opacity=0.1] circle (2);
      \end{scope}


    \begin{scope} [canvas is xy plane at z=-1.5]
      \draw[fill=blue, fill opacity=0.1] circle (2.5);
      \end{scope}


    \begin{scope} [canvas is xy plane at z=-3]
      \draw[fill=blue, fill opacity=0.1] circle (2);
      \end{scope}

    \end{tikzpicture}
\end{document}

Result:
enter image description here

Best Answer

In order to get just a part of an ellipse as the border to your fill, you can use arc (start:stop:radius), which draws the arc of a circle of radius radius from start degrees to stop degrees (in the plane of the drawing, with the x axis being 0 degrees and the y axis 90 degrees). Since you want the circle centered at the origin you'll want to start the path at the polar coordinate (start:radius) (again in the plane of the drawing).

You'll want to fill two regions for each cone: one for the back of the cone, and then another for the front. Both regions will have borders which traverse an arc of the circle, go to the origin of the diagram (which you have helpfully saved so you don't need to know where it is in the current plane coordinates), and then close the path. Because of your nice viewing angle, the points on the ellipse connecting to the origin of the diagram will be around 45 degrees and 225 degrees. You could probably calculate the offset automatically (probably someone else will give an answer which does this), but in the code below I just let you specify an offset which looks okay for each cone.

If you care about the lines being obscured correctly, you also have to make sure that everything's drawn in the correct order, from back to front. (If the cones are all the same color and you just care about the fill being the right darkness then the order won't matter.) I've also done the order manually, which might come in handy if there's other stuff that needs to go into the diagram on the correct layer.

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{45}
\tdplotsetrotatedcoords{-90}{180}{-90}

%% style for surfaces
\tikzset{surface/.style={draw=blue!70!black, fill=blue!40!white, fill opacity=.6}}

%% macros to draw back and front of cones
%% optional first argument is styling; others are z, radius, side offset (in degrees)
\newcommand{\coneback}[4][]{
  %% start at the correct point on the circle, draw the arc, then draw to the origin of the diagram, then close the path
  \draw[canvas is xy plane at z=#2, #1] (45-#4:#3) arc (45-#4:225+#4:#3) -- (O) --cycle;
  }
\newcommand{\conefront}[4][]{
  \draw[canvas is xy plane at z=#2, #1] (45-#4:#3) arc (45-#4:-135+#4:#3) -- (O) --cycle;
  }

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
  \coordinate (O) at (0,0,0);

  %% make sure to draw everything from back to front
  \coneback[surface]{-1.5}{2.5}{-15}
  \coneback[surface]{-3}{2}{-10}
  \draw (0,0,-5) -- (O);
  \conefront[surface]{-3}{2}{-10}
  \conefront[surface]{-1.5}{2.5}{-15}
  \filldraw[surface] circle (3);
  \draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
  \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
  \coneback[surface]{1.5}{2.5}{15}
  \coneback[surface]{3}{2}{10}
  \draw[->] (O) -- (0,0,5) node[above] {$z$};
  \conefront[surface]{3}{2}{10}
  \conefront[surface]{1.5}{2.5}{15}
\end{tikzpicture}
\end{document}

nested cones