如何使用 TikZ 绘制 3D 圣诞礼物盒?

如何使用 TikZ 绘制 3D 圣诞礼物盒?

本着如何使用 TikZ 绘制带装饰的圣诞树?

你能画一个带有尽可能多细节的 3D 圣诞礼物盒吗(领结、凸起的盖子/蝴蝶结、有图案的包装纸)?

当盒子打开时,通过动画展示盒子的打开状态,可以获得奖励积分(500 点赏金)。

MWE(由 HK 添加)

\documentclass[varwidth,tikz]{standalone}
\begin{document}

\begin{tikzpicture}
\draw[fill=red] (0,0) rectangle (1,1);
\draw[fill=red] (1,0) -- ++(50:0.75cm) -- ++(90:1cm) -- (1,1) -- cycle;
\draw[fill=magenta] (0,1) -- ++(50:0.75cm) -- ++(0:1cm) -- (1,1) --  cycle;
\draw (0,0.8) -- (1,0.8) -- +(50:0.75cm);
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案1

只是为了让事情进展顺利……

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}


\tikzset{gift box/.cd,
  x/.store in=\gbx,
  y/.store in=\gby,
  z/.store in=\gbz,
  x=0,y=0,z=0
}
\tikzdeclarecoordinatesystem{gift box}{%
  \tikzset{x=(-20:1cm),y=(200:1cm),z=(90:1cm)}%
  \tikzset{gift box/.cd, #1}%
  \pgfpointxyz{\gbx*(.9+\gbz/20)}{\gby*(.9+\gbz/20)}{\gbz*(1+\gbx/10+\gby/10)}%
}

\tikzset{wrapping paper/.style={
    bottom color=red!75!black, top color=red!50!black,
  },
  ribbon/.style={
    bottom color=yellow!75!orange, top color=yellow!50!orange,
  },
  sheen/.style={
    left color=black, right color=white, opacity=0.25
  },
  highlight/.style={
    draw=white,
    opacity=1/100,
    line width=#1,
    line cap=round
  },
  lowlight/.style={
    draw=black,
    opacity=1/80,
    line width=#1,
    line cap=round,
    line join=round
  }
}



\begin{document}

\begin{tikzpicture}

\foreach \l in {1,...,20}
  \path [lowlight=\l/3] 
       (gift box cs:x=-1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=-1)
    -- cycle;



\path [wrapping paper]
     (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=1)
  -- (gift box cs:x= 1, y= 1, z=1)
  -- (gift box cs:x= 1, y=-1, z=1)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- (gift box cs:x= 1, y= 1, z=-1)
  -- cycle;


\foreach \n/\o in {.25/1, .33/.5}
  \path [ribbon, opacity=\o] 
       (gift box cs:x=1, y=-\n, z=-1)
    -- (gift box cs:x=1, y=-\n, z=1)
    -- (gift box cs:x=1, y= \n, z=1)
    -- (gift box cs:x=1, y= \n, z=-1)
    -- cycle
       (gift box cs:x=-\n, y=1, z=-1)
    -- (gift box cs:x=-\n, y=1, z=1)
    -- (gift box cs:x= \n, y=1, z=1)
    -- (gift box cs:x= \n, y=1, z=-1)
    -- cycle;

\path [sheen]
     (gift box cs:x=1,y=-1,z=-1)
  -- (gift box cs:x=1,y=-1,z=1)
  -- (gift box cs:x=1, y=1,z=1)
  -- (gift box cs:x=1, y=1,z=-1)
  -- cycle;

\path  [sheen]
     (gift box cs:x=-1,y=1,z=-1)
  -- (gift box cs:x=-1,y=1,z=1)
  -- (gift box cs:x=1, y=1,z=1)
  -- (gift box cs:x=1, y=1,z=-1)
  -- cycle;

\begin{scope}

\path [clip]
     (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z= 1)
  -- (gift box cs:x= 1, y= 1, z= 1)
  -- (gift box cs:x= 1, y=-1, z= 1)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- (gift box cs:x= 1, y= 1, z=-1)
  -- cycle;

\foreach \l in {1,...,10}{
  \path [lowlight=\l/3] 
       (gift box cs:x=-1, y= 1, z=1) 
    -- (gift box cs:x=-1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=1)
       (gift box cs:x=1, y=1,z=-1) 
    -- (gift box cs:x=1, y=1,z= 1);

  \path [lowlight=\l/2]
       (gift box cs:x=-1.05, y= 1.05, z=1) 
    -- (gift box cs:x=-1.05, y= 1.05, z=.5)
    -- (gift box cs:x= 1.05, y= 1.05, z=.5)
    -- (gift box cs:x= 1.05, y=-1.05, z=.5)
    -- (gift box cs:x= 1.05, y=-1.05, z=1);
}
\end{scope}


\path [wrapping paper]
     (gift box cs:x=-1.05, y=-1.05, z=1)
  -- (gift box cs:x=-1.05, y= 1.05, z=1)
  -- (gift box cs:x=-1.05, y= 1.05, z=.5)
  -- (gift box cs:x= 1.05, y= 1.05, z=.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=1)
  -- cycle;



\foreach \n/\o in {.33/.5, .25/1}{
  \path [ribbon, opacity=\o]
       (gift box cs:x= 1.05, y=-\n, z=0.5)
    -- (gift box cs:x= 1.05, y=-\n, z=1)
    -- (gift box cs:x=-1.05, y=-\n, z=1)
    -- (gift box cs:x=-1.05, y= \n, z=1)
    -- (gift box cs:x= 1.05, y= \n, z=1)
    -- (gift box cs:x= 1.05, y= \n, z=.5)
    -- cycle;

  \path [ribbon, opacity=\o]
       (gift box cs:y= 1.05, x=-\n, z=0.5)
    -- (gift box cs:y= 1.05, x=-\n, z=1)
    -- (gift box cs:y=-1.05, x=-\n, z=1)
    -- (gift box cs:y=-1.05, x= \n,  z=1)
    -- (gift box cs:y= 1.05, x= \n, z=1)
    -- (gift box cs:y= 1.05, x= \n, z=.5)
    -- cycle;
}


\path [sheen]
     (gift box cs:x=-1.05, y=1.05, z=1)
  -- (gift box cs:x=-1.05, y=1.05, z=0.5)
  -- (gift box cs:x= 1.05, y=1.05, z=0.5)
  -- (gift box cs:x= 1.05, y=1.05, z=1)
  -- cycle;

\path [sheen]
     (gift box cs:x=1.05, y=-1.05, z=1)
  -- (gift box cs:x=1.05, y=-1.05, z=0.5)
  -- (gift box cs:x=1.05, y= 1.05, z=0.5)
  -- (gift box cs:x=1.05, y= 1.05, z=1)
  -- cycle;

\path [sheen]
     (gift box cs:x=-1.05, y=-1.05, z=1)
  -- (gift box cs:x=-1.05, y= 1.05, z=1)
  -- (gift box cs:x= 1.05, y= 1.05, z=1)
  -- (gift box cs:x= 1.05, y=-1.05, z=1)
  -- cycle;

\begin{scope}
\path [clip]
     (gift box cs:x=-1.05, y=-1.05, z=1)
  -- (gift box cs:x=-1.05, y= 1.05, z=1)
  -- (gift box cs:x=-1.05, y= 1.05, z=.5)
  -- (gift box cs:x= 1.05, y= 1.05, z=.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=1)
  -- cycle;

\foreach \l in {1,...,10}{
  \path [highlight=\l/3] 
       (gift box cs:x= 1.05, y= 1.05, z=1) 
    -- (gift box cs:x= 1.05, y=-1.05, z=1) 
    -- (gift box cs:x=-1.05, y=-1.05, z=1) 
    -- (gift box cs:x=-1.05, y= 1.05, z=1)
    -- cycle 
       (gift box cs:x=1.05, y=1.05, z=1) 
    -- (gift box cs:x=1.05, y=1.05, z=0.5);

  \path [lowlight=\l/3]
       (gift box cs:x=-1.05, y= 1.05, z=1) 
    -- (gift box cs:x=-1.05, y= 1.05, z=.5)
    -- (gift box cs:x= 1.05, y= 1.05, z=.5)
    -- (gift box cs:x= 1.05, y=-1.05, z=.5)
    -- (gift box cs:x= 1.05, y=-1.05, z=1);
}
\end{scope}
\end{tikzpicture}

\end{document}

在此处输入图片描述

而且,只需很少的额外工作:

在此处输入图片描述

不幸的是,这个礼盒是空的。满脸悲伤。

(除非它包含一些尚看不见的小东西)。

gif包装似乎具有的(相当令人愉悦的)“纹理”是减小尺寸和优化上传色彩空间的结果。

代码(编译需要一些时间)如下所示。pdf然后处理结果以gimp生成上面的图像:

\documentclass[tikz,border=0.125cm]{standalone}

\tikzset{gift box/.cd,
  x/.store in=\gbx,
  y/.store in=\gby,
  z/.store in=\gbz,
  rotate around z axis/.store in=\gbzaxisrotate,
  x=0,y=0,z=0,  
  rotate around z axis=0
}
\tikzdeclarecoordinatesystem{gift box}{%
  \tikzset{x=(-20:1cm),y=(200:1cm),z=(90:1cm)}%
  \tikzset{gift box/.cd, #1}%
  \pgfmathsin{\gbzaxisrotate}\let\gbsin=\pgfmathresult%
  \pgfmathcos{\gbzaxisrotate}\let\gbcos=\pgfmathresult%
  \pgfmathparse{cos(\gbzaxisrotate)*(\gbx)-sin(\gbzaxisrotate)*(\gby)}\let\gbxa=\pgfmathresult%
  \pgfmathparse{sin(\gbzaxisrotate)*(\gbx)+cos(\gbzaxisrotate)*(\gby)}\let\gbya=\pgfmathresult%
  \pgfpointxyz{\gbxa*(.9+(\gbz)/20)}{\gbya*(.9+(\gbz)/20)}{(\gbz)*(1+\gbxa/10+\gbya/10)}%
}

\tikzset{wrapping paper/.style={
    bottom color=red!75!black, top color=red!50!black,
  },
  ribbon/.style={
    bottom color=yellow!75!orange, top color=yellow!50!orange,
  },
  sheen/.style={
    left color=black, right color=white, opacity=0.25
  },
  sheen inside/.style={
    left color=black, right color=black!50, opacity=0.25
  },
  highlight/.style={
    draw=white,
    opacity=1/100,
    line width=#1,
    line cap=round
  },
  lowlight/.style={
    draw=black,
    opacity=1/80,
    line width=#1,
    line cap=round,
    line join=round
  }
}



\begin{document}


\foreach \i [evaluate={\zangle=-45+mod(\i,18)*5; \lidz=1.25+min(\i,18)*.1;}] in {0,...,35}{
\begin{tikzpicture}[gift box/rotate around z axis=\zangle]

\useasboundingbox [gift box/rotate around z axis=0] 
     (gift box cs:x= 1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=3)
  -- (gift box cs:x=-1, y=-1, z=3)
  -- (gift box cs:x= 1, y=-1, z=3)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- cycle;

\foreach \l in {1,...,20}
  \path [lowlight=\l/3] 
       (gift box cs:x=-1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=-1)
    -- cycle;

\path [wrapping paper]
     (gift box cs:x= 1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=1)
  -- (gift box cs:x=-1, y=-1, z=1)
  -- (gift box cs:x= 1, y=-1, z=1)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- cycle;


\path [sheen inside]
     (gift box cs:x= 1, y=-1, z=-1)
  -- (gift box cs:x= 1, y=-1, z=1)
  -- (gift box cs:x=-1, y=-1, z=1)
  -- (gift box cs:x=-1, y=-1, z=-1)
  -- cycle;

\path  [sheen inside]
     (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=1)
  -- (gift box cs:x=-1, y=-1, z=1)
  -- (gift box cs:x=-1, y=-1, z=-1)
  -- cycle;

\begin{scope}

\path [clip]
     (gift box cs:x= 1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=1)
  -- (gift box cs:x=-1, y=-1, z=1)
  -- (gift box cs:x= 1, y=-1, z=1)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- cycle;

\foreach \l in {1,...,20}
  \path [lowlight=\l/3] 
       (gift box cs:x=-1, y= 1, z=1) 
    -- (gift box cs:x=-1, y=-1, z=1) 
    -- (gift box cs:x= 1, y=-1, z=1);
\end{scope}

\path [wrapping paper]
     (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z=1)
  -- (gift box cs:x= 1, y= 1, z=1)
  -- (gift box cs:x= 1, y=-1, z=1)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- (gift box cs:x= 1, y= 1, z=-1)
  -- cycle;


\foreach \n/\o in {.25/1, .33/.5}
  \path [ribbon, opacity=\o] 
       (gift box cs:x=1, y=-\n, z=-1)
    -- (gift box cs:x=1, y=-\n, z=1)
    -- (gift box cs:x=1, y= \n, z=1)
    -- (gift box cs:x=1, y= \n, z=-1)
    -- cycle
       (gift box cs:x=-\n, y=1, z=-1)
    -- (gift box cs:x=-\n, y=1, z=1)
    -- (gift box cs:x= \n, y=1, z=1)
    -- (gift box cs:x= \n, y=1, z=-1)
    -- cycle;

\path [sheen]
     (gift box cs:x=1, y=-1, z=-1)
  -- (gift box cs:x=1, y=-1, z=1)
  -- (gift box cs:x=1, y= 1, z=1)
  -- (gift box cs:x=1, y= 1, z=-1)
  -- cycle;

\path  [sheen]
     (gift box cs:x=-1,y=1,z=-1)
  -- (gift box cs:x=-1,y=1,z=1)
  -- (gift box cs:x=1, y=1,z=1)
  -- (gift box cs:x=1, y=1,z=-1)
  -- cycle;

\begin{scope}

\path [clip]
     (gift box cs:x=-1, y= 1, z=-1)
  -- (gift box cs:x=-1, y= 1, z= 1)
  -- (gift box cs:x= 1, y= 1, z= 1)
  -- (gift box cs:x= 1, y=-1, z= 1)
  -- (gift box cs:x= 1, y=-1, z=-1)
  -- (gift box cs:x= 1, y= 1, z=-1)
  -- cycle;

\foreach \l in {1,...,10}{
  \path [lowlight=\l/3] 
       (gift box cs:x=-1, y= 1, z=1) 
    -- (gift box cs:x=-1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y= 1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=-1) 
    -- (gift box cs:x= 1, y=-1, z=1)
       (gift box cs:x=1, y=1,z=-1) 
    -- (gift box cs:x=1, y=1,z= 1);

   \path [highlight=\l/3]
        (gift box cs:x=-1, y= 1, z=1) 
     -- (gift box cs:x= 1, y= 1, z=1)
     -- (gift box cs:x= 1, y=-1, z=1);

    \path [lowlight=\l/2]
        (gift box cs:x=-1.05, y= 1.05, z=\lidz-.5) 
     -- (gift box cs:x= 1.05, y= 1.05, z=\lidz-.5)
     -- (gift box cs:x= 1.05, y=-1.05, z=\lidz-.5);
}
\end{scope}

\path [wrapping paper]
     (gift box cs:x=-1.05, y=-1.05, z=\lidz)
  -- (gift box cs:x=-1.05, y= 1.05, z=\lidz)
  -- (gift box cs:x=-1.05, y= 1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y= 1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=\lidz)
  -- cycle;



\foreach \n/\o in {.33/.5, .25/1}{
  \path [ribbon, opacity=\o]
       (gift box cs:x= 1.05, y=-\n, z=\lidz-.5)
    -- (gift box cs:x= 1.05, y=-\n, z=\lidz)
    -- (gift box cs:x=-1.05, y=-\n, z=\lidz)
    -- (gift box cs:x=-1.05, y= \n, z=\lidz)
    -- (gift box cs:x= 1.05, y= \n, z=\lidz)
    -- (gift box cs:x= 1.05, y= \n, z=\lidz-.5)
    -- cycle;

  \path [ribbon, opacity=\o]
       (gift box cs:y= 1.05, x=-\n, z=\lidz-.5)
    -- (gift box cs:y= 1.05, x=-\n, z=\lidz)
    -- (gift box cs:y=-1.05, x=-\n, z=\lidz)
    -- (gift box cs:y=-1.05, x= \n,  z=\lidz)
    -- (gift box cs:y= 1.05, x= \n, z=\lidz)
    -- (gift box cs:y= 1.05, x= \n, z=\lidz-.5)
    -- cycle;
}


\path [sheen]
     (gift box cs:x=-1.05, y=1.05, z=\lidz)
  -- (gift box cs:x=-1.05, y=1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y=1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y=1.05, z=\lidz)
  -- cycle;

\path [sheen]
     (gift box cs:x=1.05, y=-1.05, z=\lidz)
  -- (gift box cs:x=1.05, y=-1.05, z=\lidz-.5)
  -- (gift box cs:x=1.05, y= 1.05, z=\lidz-.5)
  -- (gift box cs:x=1.05, y= 1.05, z=\lidz)
  -- cycle;

\path [sheen]
     (gift box cs:x=-1.05, y=-1.05, z=\lidz)
  -- (gift box cs:x=-1.05, y= 1.05, z=\lidz)
  -- (gift box cs:x= 1.05, y= 1.05, z=\lidz)
  -- (gift box cs:x= 1.05, y=-1.05, z=\lidz)
  -- cycle;

\begin{scope}
\path [clip]
     (gift box cs:x=-1.05, y=-1.05, z=\lidz)
  -- (gift box cs:x=-1.05, y= 1.05, z=\lidz)
  -- (gift box cs:x=-1.05, y= 1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y= 1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=\lidz-.5)
  -- (gift box cs:x= 1.05, y=-1.05, z=\lidz)
  -- cycle;

\foreach \l in {1,...,10}{
  \path [highlight=\l/3] 
       (gift box cs:x= 1.05, y= 1.05, z=\lidz) 
    -- (gift box cs:x= 1.05, y=-1.05, z=\lidz) 
    -- (gift box cs:x=-1.05, y=-1.05, z=\lidz) 
    -- (gift box cs:x=-1.05, y= 1.05, z=\lidz)
    -- cycle 
       (gift box cs:x=1.05, y=1.05, z=\lidz) 
    -- (gift box cs:x=1.05, y=1.05, z=\lidz-.5);

  \path [lowlight=\l/3]
       (gift box cs:x=-1.05, y= 1.05, z=\lidz) 
    -- (gift box cs:x=-1.05, y= 1.05, z=\lidz-.5)
    -- (gift box cs:x= 1.05, y= 1.05, z=\lidz-.5)
    -- (gift box cs:x= 1.05, y=-1.05, z=\lidz-.5)
    -- (gift box cs:x= 1.05, y=-1.05, z=\lidz);
}
\end{scope}
\ifnum\i>17
\path [fill=white,opacity=(\i-17)/7]
     (gift box cs:x=-1.1, y=-1.1, z=\lidz)
  -- (gift box cs:x=-1.1, y= 1.1, z=\lidz)
  -- (gift box cs:x=-1.1, y= 1.1, z=\lidz-.5)
  -- (gift box cs:x= 1.1, y= 1.1, z=\lidz-.5)
  -- (gift box cs:x= 1.1, y=-1.1, z=\lidz-.5)
  -- (gift box cs:x= 1.1, y=-1.1, z=\lidz)
  -- cycle;
\fi
\end{tikzpicture}
}
\end{document}

答案2

这与其他答案中的 3D 努力完全不同,但这里有一个数学努力元帖子

在此处输入图片描述

它是半规则平铺以圣诞色彩绘制(来自metapost-colorbrewer),以及其双重平铺叠加在一起,看起来有点像金色丝带缠绕在方形包裹上。

圣诞节快乐!

\documentclass{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
input colorbrewer-cmyk
% a polygon of n sides on a given path
vardef poly expr n of p = 
    save x, y;
    z0 = point 0 of p;
    z1 = point 1 of p;
    for i=2 upto n-1:
        z[i] = z[i-2] rotatedabout(z[i-1], 180(2/n-1));
    endfor
    for i=0 upto n-1: z[i] -- endfor cycle
enddef;
vardef median(expr P) = 
    (origin for i=1 upto length P: + point i of P endfor) / length P
enddef;
beginfig(1);
    path t[], s[];
    s1 = poly 4 of (origin -- 42 dir 15);
    t1 = poly 3 of subpath (2, 1) of s1;
    t2 = poly 3 of subpath (3, 2) of s1;
    t3 = poly 3 of subpath (2, 1) of t1;
    t4 = poly 3 of subpath (2, 1) of t2;
    s2 = poly 4 of subpath (2, 1) of t4;

    picture unit;
    unit = image(
        fill s1 withcolor Oranges 8 5;
        fill t1 withcolor Blues 8 4;
        fill t4 withcolor Blues 8 3;
        fill t3 withcolor Greens 8 4;
        fill t2 withcolor Greens 8 3;
        fill s2 withcolor Reds 8 5;
        forsuffixes $=s1, t1, s2, t2, t3, t4: 
            pair m; m = median($);
            for i=1 upto length $:
                draw point i - 1/2 of $ -- m 
                    withpen pencircle scaled 3/2 withcolor Spectral 3 2;
            endfor
        endfor
    );

    pair u, v;
    u = point 2 of t2 - point 0 of s1;
    v = point 2 of t3 - point 0 of s1;

    for i=0 upto 6:
        for j=0 upto 9:
            draw unit shifted (i*u + j*v);
        endfor
    endfor
endfig;
\end{mplibcode}
\end{document}

您将需要使用它来编译它lualatex

相关内容