I do not know if this will make you happy, but yes, a kind of Lindenmayer system can work for your problem, using the fact that the cube is made of 20 copies of a 3-times-smaller itself, who themselves are made of a 3-times-smaller cube, and so on. Here is a way you can do it; I let you make the needed adaptations to get a better picture.
First generate a .tex file level0.tex
with no \documentclass
, \begin{document}
or so, whose content just would be:
\fill[yellow] (1, 1, 1) -- (1, -1, 1) -- (-1, -1, 1) -- (-1, 1, 1) -- cycle;
\fill[cyan] (1, 1, 1) -- (1, 1, -1) -- (1, -1, -1) -- (1, -1, 1) -- cycle;
\fill[magenta] (1, 1, 1) -- (1, 1, -1) -- (-1, 1, -1) -- (-1, 1, 1) -- cycle;
Now you create a file level1.tex
(again, no \documentclass
or so) in which you use the content of level0
twenty times as if you were putting several small cubes near each other. Beware that you have to draw the cubes in a correct order, so that a cube hiding another one will only be drawn after it. Your file level1.tex
would be the following:
\begin{scope}[scale=.3333333333]
\begin{scope}[shift={(-2, -2, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(0, -2, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, -2, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, 0, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, 0, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, 2, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(0, 2, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, 2, -2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, -2, 0)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, -2, 0)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, 2, 0)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, 2, 0)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, -2, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(0, -2, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, -2, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, 0, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, 0, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(-2, 2, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(0, 2, 2)}]
\input{level0}
\end{scope}
\begin{scope}[shift={(2, 2, 2)}]
\input{level0}
\end{scope}
\end{scope}
Next you create a file level2.tex
which is the same as level1.tex
, except that \input{level0}
is replaced by \input{level1}
. And finally your final drawing (inside a real .tex
source file with \documentclass
and so on) will be
\begin{tikzpicture}
\input{level2}
\end{tikzpicture}
Below is the rendering I get. Of course you can go up to level 3, 4 or so, at least theoretically, but do not forget that the amount of computation and memory used will be multiplied by a factor 20 at each further level!

Kind regards,
/Nancy-N
EDIT: Paul Gaborit has quite nicely improved my solution by coding a command \mengersponge
taking one argument, so that you do not have to create one file per level. Here is his code (where he also chose more relevant colours ;-)):
\documentclass[tikz]{standalone}
\usepackage{luatex85}
\newcommand\mengersponge[1]{
\pgfmathsetmacro\level{int(#1 - 1)}
\ifnum \level = 0 \relax
\filldraw[gray!50!black,line width=0] (1, 1, 1) -- (1, 1, -1) -- (1, -1, -1) -- (1, -1, 1) -- cycle;
\filldraw[gray,line width=0] (1, 1, 1) -- (1, 1, -1) -- (-1, 1, -1) -- (-1, 1, 1) -- cycle;
\filldraw[gray!50,line width=0] (1, 1, 1) -- (1, -1, 1) -- (-1, -1, 1) -- (-1, 1, 1) -- cycle;
\else
\begin{scope}[scale=.3333333333]
\begin{scope}[shift={(-2, -2, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(0, -2, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, -2, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, 0, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, 0, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, 2, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(0, 2, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, 2, -2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, -2, 0)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, -2, 0)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, 2, 0)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, 2, 0)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, -2, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(0, -2, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, -2, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, 0, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, 0, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(-2, 2, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(0, 2, 2)}]
\mengersponge{\level}
\end{scope}
\begin{scope}[shift={(2, 2, 2)}]
\mengersponge{\level}
\end{scope}
\end{scope}
\fi
}
\begin{document}
\begin{tikzpicture}
\mengersponge{4}
\end{tikzpicture}
\end{document}
With pdflatex
, Paul Gaborit could only perform the computations up to level 3 (corresponding to \mengersponge{4}
in his code), which took 40 seconds to compilate; but with lualatex
he could compile level 4 (corresponding to \mengersponge{5}
). Below are his pictures :-)
For level 3:

For level 4:

Regards,
/Nancy-N