[Tex/LaTex] How to draw a double napped cone with TikZ

tikz-3dplottikz-pgf

I would like to reproduce something like this in black and white using TikZ (just the figure not the writing) :
enter image description here

Here is the code I have so far, but I don't know how to draw the three planes properly :

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

%% style for surfaces
\tikzset{surface/.style={draw=black, fill=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]{-3}{2}{-10}
  \draw (0,0,-5) -- (O);
  \conefront[surface]{-3}{2}{-10}
  \draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
  \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
  \coneback[surface]{3}{2}{10}
  \draw[->] (O) -- (0,0,5) node[above] {$z$};
  \conefront[surface]{3}{2}{10}
\end{tikzpicture}
\end{document}

Update : Here is the result thanks to these two posts (@Schrödinger's cat's answer / The fix from another question). The code contains a fix to cope with outdated tikz 3d library.

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{110}

%This piece of code fixes the bug%
\usetikzlibrary{3d}
\makeatletter
\tikzoption{canvas is xy plane at z}[]{%
  \def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
  \def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}%
  \def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}%
  \tikz@canvas@is@plane
}
\makeatother
%%%%%%%%%%%%

%% style for surfaces
\tikzset{surface/.style={draw=black, left color=orange,right color=orange,middle
color=orange!60!#1, fill opacity=1},surface/.default=white}

%% 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] (\tdplotmainphi-#4:#3) 
  arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
  }
\newcommand{\conefront}[4][]{
  \draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
  (\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
  }

\newcommand{\conetruncback}[6][]{
  \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi+180+#4] 
  ({#3*cos(\t)},{#3*sin(\t)},#2)
  -- plot[variable=\t,domain=\tdplotmainphi+180-#4:\tdplotmainphi+#4] 
  ({#6*cos(\t)},{#6*sin(\t)},#5)
  --cycle;
  }

\newcommand{\conetruncfront}[6][]{
  \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4] 
  ({#3*cos(\t)},{#3*sin(\t)},#2)
  -- plot[variable=\t,domain=\tdplotmainphi-180-#4:\tdplotmainphi+#4] 
  ({#6*cos(\t)},{#6*sin(\t)},#5)
  --cycle;
  }

\begin{document}
\begin{tikzpicture}[tdplot_main_coords]
  \coordinate (O) at (0,0,0);
  \conetruncback[surface=black]{-2}{4/3}{0}{-3}{2}
  \draw (0,0,-5) -- (0,0,-2);
  \conetruncfront[surface]{-2}{4/3}{0}{-3}{2}
  \draw[canvas is xy plane at z=-2,fill=green!40!black,fill opacity=1] (-3,-3) rectangle (3,3);
  \coneback[surface=black]{-2}{4/3}{-10}
  \draw (0,0,-2) -- (O);
  \conefront[surface]{-2}{4/3}{-10}
  \draw[canvas is xy plane at z=0,fill=teal,fill opacity=1] (-3,-3) rectangle (3,3);
  \draw[->] (-6,0,0) -- (7,0,0) node[below] {$x$};
  \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
  \coneback[surface=white]{2}{4/3}{10}
  \draw[-] (O) -- (0,0,2);
  \conefront[surface=black]{2}{4/3}{10}
  \draw[canvas is xy plane at z=2,fill=pink,fill opacity=1] (-3,-3) rectangle (3,3);
  \conetruncback[surface=white]{2}{4/3}{0}{3}{2}
  \draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
  \conetruncfront[surface=black]{2}{4/3}{0}{3}{2}
\end{tikzpicture}
\end{document}

And the result :
enter image description here

Best Answer

You were almost there. Drawing a plane is as simple as saying

\draw[canvas is xy plane at z=2,fill=blue,fill opacity=0.6] (-4,-4) rectangle (4,4);

Other than that you need to draw the parts of the cone below and above the planes separately, which is why I added a macro for the truncated cone, \conetruncfront. I also replaced the hardcoded 45 with \tdplotmainphi.

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

%% style for surfaces
\tikzset{surface/.style={draw=black, fill=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] (\tdplotmainphi-#4:#3) 
  arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
  }
\newcommand{\conefront}[4][]{
  \draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
  (\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
  }

\newcommand{\conetruncfront}[6][]{
  \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4] 
  ({#3*cos(\t)},{#3*sin(\t)},#2)
  -- plot[variable=\t,domain=\tdplotmainphi-180-#4:\tdplotmainphi+#4] 
  ({#6*cos(\t)},{#6*sin(\t)},#5)
  --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]{-3}{2}{-10}
  \draw (0,0,-5) -- (O);
  \conefront[surface]{-3}{2}{-10}
  \draw[canvas is xy plane at z=-2,fill=green!60!black,fill opacity=0.6] (-4,-4) rectangle (4,4);
  \coneback[surface]{-2}{4/3}{-10}
  \draw (0,0,-2) -- (O);
  \conefront[surface]{-2}{4/3}{-10}
  \draw[canvas is xy plane at z=0,fill=blue,fill opacity=0.6] (-4,-4) rectangle (4,4);
  \draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
  \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
  \coneback[surface]{3}{2}{10}
  \draw[->] (O) -- (0,0,5) node[above] {$z$};
  \conefront[surface]{3}{2}{10}
  \draw[canvas is xy plane at z=2,fill=purple,fill opacity=0.6] (-4,-4) rectangle (4,4);
  \draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
  \conetruncfront[surface]{2}{4/3}{0}{3}{2}
\end{tikzpicture}
\end{document}

First cones, from the code of the asker.

However, I'd slightly change things to get

 \documentclass[tikz, border=3pt]{standalone}
    \usepackage{tikz,tikz-3dplot}
    \tdplotsetmaincoords{80}{45}
    
    %% style for surfaces
    \tikzset{surface/.style={draw=black, left color=yellow,right color=yellow,middle
    color=yellow!60!#1, fill opacity=.6},surface/.default=white}
    
    %% 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] (\tdplotmainphi-#4:#3) 
      arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
      }
    \newcommand{\conefront}[4][]{
      \draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
      (\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
      }
    
    \newcommand{\conetruncback}[6][]{
      \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi+180+#4] 
      ({#3*cos(\t)},{#3*sin(\t)},#2)
      -- plot[variable=\t,domain=\tdplotmainphi+180-#4:\tdplotmainphi+#4] 
      ({#6*cos(\t)},{#6*sin(\t)},#5)
      --cycle;
      }
    
    \newcommand{\conetruncfront}[6][]{
      \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4] 
      ({#3*cos(\t)},{#3*sin(\t)},#2)
      -- plot[variable=\t,domain=\tdplotmainphi-180-#4:\tdplotmainphi+#4] 
      ({#6*cos(\t)},{#6*sin(\t)},#5)
      --cycle;
      }
    
    \begin{document}
    \begin{tikzpicture}[tdplot_main_coords]
      \coordinate (O) at (0,0,0);
      \conetruncback[surface=black]{-2}{4/3}{0}{-3}{2}
      \draw (0,0,-5) -- (0,0,-2);
      \conetruncfront[surface]{-2}{4/3}{0}{-3}{2}
      \draw[canvas is xy plane at z=-2,fill=green!60!black,fill opacity=0.6] (-4,-4) rectangle (4,4);
      \coneback[surface=black]{-2}{4/3}{-10}
      \draw (0,0,-2) -- (O);
      \conefront[surface]{-2}{4/3}{-10}
      \draw[canvas is xy plane at z=0,fill=blue,fill opacity=0.6] (-4,-4) rectangle (4,4);
      \draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
      \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
      \coneback[surface=white]{2}{4/3}{10}
      \draw[-] (O) -- (0,0,2);
      \conefront[surface=black]{2}{4/3}{10}
      \draw[canvas is xy plane at z=2,fill=purple,fill opacity=0.6] (-4,-4) rectangle (4,4);
      \conetruncback[surface=white]{2}{4/3}{0}{3}{2}
      \draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
      \conetruncfront[surface=black]{2}{4/3}{0}{3}{2}
    \end{tikzpicture}
    \end{document}

Second cone, with darker planes

Or with slightly different view angles and opacity set to 1, and adjustments suggested by minhthien_2016.

\documentclass[tikz, border=3pt]{standalone}
\usepackage{tikz,tikz-3dplot}
\tdplotsetmaincoords{80}{60}

%% style for surfaces
\tikzset{surface/.style={draw=black, left color=yellow,right color=yellow,middle
        color=yellow!60!#1, fill opacity=1},surface/.default=white}

%% 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] (\tdplotmainphi-#4:#3) 
    arc(\tdplotmainphi-#4:\tdplotmainphi+180+#4:#3) -- (O) --cycle;
}
\newcommand{\conefront}[4][]{
    \draw[canvas is xy plane at z=#2, #1] (\tdplotmainphi-#4:#3) arc
    (\tdplotmainphi-#4:\tdplotmainphi-180+#4:#3) -- (O) --cycle;
}

\newcommand{\conetruncback}[7][]{
    \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi+180+#4] 
    ({#3*cos(\t)},{#3*sin(\t)},#2)
    -- plot[variable=\t,domain=\tdplotmainphi+180-#7:\tdplotmainphi+#7] 
    ({#6*cos(\t)},{#6*sin(\t)},#5)
    --cycle;
}

\newcommand{\conetruncfront}[7][]{
    \draw[line join=round,#1] plot[variable=\t,domain=\tdplotmainphi-#4:\tdplotmainphi-180+#4] 
    ({#3*cos(\t)},{#3*sin(\t)},#2)
    -- plot[variable=\t,domain=\tdplotmainphi-180-#7:\tdplotmainphi+#7] 
    ({#6*cos(\t)},{#6*sin(\t)},#5)
    --cycle;
}

\begin{document}
    \begin{tikzpicture}[tdplot_main_coords]
    \coordinate (O) at (0,0,0);
    \conetruncback[surface=black]{-2}{4/3}{-5}{-3}{2}{5}
    \draw (0,0,-5) -- (0,0,-2);
    \conetruncfront[surface]{-2}{4/3}{-5}{-3}{2}{5}
    \draw[canvas is xy plane at z=-2,fill=green!60!black,fill opacity=1] (-4,-4) rectangle (4,4);
    \coneback[surface=black]{-2}{4/3}{-10}
    \draw (0,0,-2) -- (O);
    \conefront[surface]{-2}{4/3}{-10}
    \draw[canvas is xy plane at z=0,fill=blue,fill opacity=1] (-4,-4) rectangle (4,4);
    \draw[->] (-6,0,0) -- (6,0,0) node[right] {$x$};
    \draw[->] (0,-6,0) -- (0,6,0) node[right] {$y$};
    \coneback[surface=white]{2}{4/3}{10}
    \draw[-] (O) -- (0,0,2);
    \conefront[surface=black]{2}{4/3}{10}
    \draw[canvas is xy plane at z=2,fill=purple,fill opacity=1] (-4,-4) rectangle (4,4);
    \conetruncback[surface=white]{2}{4/3}{5}{3}{2}{-5}
    \draw[->] (0,0,2) -- (0,0,5) node[above] {$z$};
    \conetruncfront[surface=black]{2}{4/3}{5}{3}{2}{-5}
    \end{tikzpicture}
\end{document}

Third cone image displaying requests from comments