实现相同相机透视投影模型的更优雅的方法是什么?

实现相同相机透视投影模型的更优雅的方法是什么?

我刚刚用 TikZ 完成了一个相机透视投影模型。虽然我对结果很满意,但我花了很长时间很多的时间来完成它。从下面的代码很容易看出,我不太习惯 Latex,更不用说 TikZ 了。所以,我相信有更好的方法来绘制同样的图片。

我确实找到了一个支持使用 TikZ 进行 3D 绘图的软件包(tikz-3dplot),但乍一看,我认为它对我没什么帮助。所以我没有费心去学习另一个包。也许还有其他我不知道的替代方案。

我的代码的基本思想是为图片的坐标系定义三个向量(x_c、y_c 和 z_c)。然后基于这些向量绘制所有内容。因此,例如,如果我想在 x 方向上移动 3 个单位,我只需执行类似 的操作\draw (0,0) -- (3*\xOne, 3*\xTwo),其中\xOne\xTwo分别是定义的 x 向量的第一个值和第二个值(因此在绝对 TikZ x 和 y 方向上分解该向量)。

我认为也许我可以通过向更有经验的人寻求不同的解决方案来学习。虽然我更喜欢 PGF/TikZ 解决方案,因为这是我唯一了解的解决方案,但其他替代方案,如 PSTricks 和 Metapost 也受到欢迎(也许这是我学习它们的机会)。

这是我的图片:

在此处输入图片描述

这是我的代码:

\documentclass{article}

\usepackage{tikz}

\begin{document}
\begin{tikzpicture}

\usetikzlibrary{calc}

% Picture's vectors definition
\def\xOne{1}
\def\xTwo{0.5}
\def\yOne{0}
\def\yTwo{-1.3}
\def\zOne{-1}
\def\zTwo{0.5}

% CAMERA COORDINATE SYSTEM
%\draw[thick,->] (0,0) -- (\xOne,\xTwo) node[anchor=north]{$x$};
%\draw[thick,->] (0,0) -- (\yOne,\yTwo) node[anchor=west]{$y$};
%\draw[thick,->] (0,0) -- (\zOne,\zTwo) node[anchor=north,yshift=-2pt,xshift=3pt]{$z$};
\draw[very thick,->] (-\zOne/2,-\zTwo/2) -- (-\zOne/2+\xOne,-\zTwo/2+\xTwo) node[anchor=north west, xshift=-3pt,font=\footnotesize]{$x_c$};
\draw[very thick,->] (-\zOne/2,-\zTwo/2) -- (-\zOne/2+\yOne,-\zTwo/2+\yTwo) node[anchor=west,font=\footnotesize]{$y_c$};
\draw[very thick,->] (-\zOne/2,-\zTwo/2) -- (\zOne/2,\zTwo/2) node[anchor=north,yshift=-2pt,xshift=3pt,font=\footnotesize]{$z_c$};
\draw (-\zOne/2,-\zTwo/2) node[anchor=north west,font=\footnotesize]{$\mathcal{F}_c$};

% CAMERA AXIS ELONGATION
\draw[very thin,solid] (-\zOne/2-2*\xOne,-\zTwo/2-2*\xTwo) -- (-\zOne/2+2*\xOne,-\zTwo/2+2*\xTwo); % x elongation
\draw[very thin,solid] (3*\zOne,3*\zTwo) -- (6*\zOne,6*\zTwo); % optical axis behind projection plane

% REFERENCE LINES
%\draw[thin,dashed] (1.4*\xOne-\zOne/2,1.4*\xTwo-\zTwo/2) -- (6*\zOne+1.4*\xOne,6*\zTwo+1.4*\xTwo); % object x position
\draw[very thin,solid] (6*\zOne-2*\xOne,6*\zTwo-2*\xTwo) -- (6*\zOne+2*\xOne,6*\zTwo+2*\xTwo) node[anchor=west]{}; %object z position

% WORLD OBJECT
\draw[-latex,line width=3pt,blue,line cap=round] (6*\zOne+1.4*\xOne,6*\zTwo+1.4*\xTwo) -- (6*\zOne+1.4*\xOne,6*\zTwo+1.4*\xTwo+1.1) node[anchor=south,font=\footnotesize]{$ P = (X,Y,Z) $};
\node[circle,inner sep=0pt,minimum size=0.2cm,fill=blue] (object) at (6*\zOne+1.4*\xOne,6*\zTwo+1.4*\xTwo+1.1) {};

% PROJECTION LINE BEHIND PROJECTION PLANE
\draw[thick,solid,red] (3*\zOne+0.69*\xOne,3*\zTwo+0.7*\xTwo+0.69) -- (6*\zOne+1.4*\xOne,6*\zTwo+1.4*\xTwo+1.1);

%% PROJECTION PLANE
\filldraw[fill=gray!20,draw=gray!70,opacity=0.8] (3*\zOne-1.5*\xOne-1.5*\yOne,3*\zTwo-1.5*\xTwo-1.5*\yTwo) -- (3*\zOne+1.5*\xOne-1.5*\yOne,3*\zTwo+1.5*\xTwo-1.5*\yTwo) -- (3*\zOne+1.5*\xOne+1.5*\yOne,3*\zTwo+1.5*\xTwo+1.5*\yTwo) -- (3*\zOne-1.5*\xOne+1.5*\yOne,3*\zTwo-1.5*\xTwo+1.5*\yTwo) -- (3*\zOne-1.5*\xOne-1.5*\yOne,3*\zTwo-1.5*\xTwo-1.5*\yTwo);

% PLOJECTION PLANE COORDINATE SYSTEM u,v
\draw[->,thick,green!70!black,dashed] (3*\zOne-1.5*\xOne-1.5*\yOne,3*\zTwo-1.5*\xTwo-1.5*\yTwo) -- (3*\zOne+2*\xOne-1.5*\yOne,3*\zTwo+2*\xTwo-1.5*\yTwo)
     node[anchor=north west, xshift=-3pt,font=\footnotesize]{$u$};
\draw[->,thick,green!70!black,dashed] (3*\zOne-1.5*\xOne-1.5*\yOne,3*\zTwo-1.5*\xTwo-1.5*\yTwo) -- (3*\zOne-1.5*\xOne-1.5*\yOne,3*\zTwo-1.5*\xTwo+2*\yTwo)
     node[anchor=west,font=\footnotesize]{$v$};

% PROJECTION PLANE COORDINATE SYSTEM x,y
\draw[->,thick,cyan,dashed] (3*\zOne-2*\xOne,3*\zTwo-2*\xTwo) -- (3*\zOne+2*\xOne,3*\zTwo+2*\xTwo)
     node[anchor=north west, xshift=-3pt,font=\footnotesize]{$x$};
\draw[->,thick,cyan,dashed] (3*\zOne-2*\yOne,3*\zTwo-2*\yTwo) -- (3*\zOne+2*\yOne,3*\zTwo+2*\yTwo)
     node[anchor=west,font=\footnotesize]{$y$};

% PROJECTION  OBJECT
\draw[-latex,line width=1.5pt,blue,line cap=round] (3*\zOne+0.69*\xOne,3*\zTwo+0.69*\xTwo) -- (3*\zOne+0.69*\xOne,3*\zTwo+0.69*\xTwo+0.69);
\node[circle,inner sep=0pt,minimum size=0.1cm,fill=blue] (object) at (3*\zOne+0.69*\xOne,3*\zTwo+0.7*\xTwo+0.69) {};

% PIXEL OBJECT
\filldraw[red,opacity=0.6] (3*\zOne+6*0.105*\xOne,3*\zTwo+0.75+6*0.105*\xTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo);

% PROJECTION LINE IN FRONT OF PROJECTION PLANE
\draw[thick,solid,red] (-\zOne/2,-\zTwo/2) -- (3*\zOne+0.69*\xOne,3*\zTwo+0.7*\xTwo+0.69);

% OPTICAL AXIS IN FRONT OF PROJECTION PLANE
\draw[thin,solid] (0,0) -- (3*\zOne,3*\zTwo);

% ANNOTATIONS
% z = f
\draw (3*\zOne-1*\xOne+1.3*\yOne,3*\zTwo-1*\xTwo+1.3*\yTwo) node[gray!70,rotate=28] {$ z = f $};
% bar(u)
\draw[to-to, green!70!black] (3*\zOne+0.13*\xOne+0.08*\yOne,3*\zTwo+0.13*\xTwo+0.08*\yTwo) -- (3*\zOne+0.7*\xOne+0.08*\yOne,3*\zTwo+0.7*\xTwo+0.08*\yTwo) node[midway,anchor=north west,xshift=-2pt,yshift=2pt,font=\scriptsize] {$ \bar{u} $};
% bar(v)
\draw[to-to, green!70!black] (3*\zOne-0.1*\xOne-0.04*\yOne,3*\zTwo-0.1*\xTwo-0.04*\yTwo) -- (3*\zOne-0.1*\xOne,3*\zTwo-0.1*\xTwo+0.75) node[midway,anchor=east,xshift=2pt,font=\scriptsize] {$ \bar{v} $};
% (u,v)
\node[green!70!black,anchor=west,font=\scriptsize] at (3*\zOne+0.69*\xOne,3*\zTwo+0.7*\xTwo+0.69) {$ (u,v) $};
% principal point
\draw[very thin] (3*\zOne-0.02*\xOne+0.02*\yOne,3*\zTwo-0.02*\xTwo+0.02*\yTwo) .. controls (3*\zOne-0.1*\xOne+0.3*\yOne,3*\zTwo-0.1*\xTwo+0.3*\yTwo) and (3*\zOne-0.3*\xOne+0.1*\yOne,3*\zTwo-0.3*\xTwo+0.1*\yTwo) ..  (3*\zOne-0.6*\xOne+0.4*\yOne,3*\zTwo-0.6*\xTwo+0.4*\yTwo) node[anchor=north,align=center,font=\sffamily\scriptsize] {ponto \\ principal};
% optical axis
\draw[very thin] (5.5*\zOne-0.02*\xOne+0.02*\yOne,5.5*\zTwo-0.02*\xOne+0.02*\yOne) .. controls (5.5*\zOne-0.1*\xOne+0.3*\yOne,5.5*\zTwo-0.1*\xTwo+0.3*\yTwo) and (5.5*\zOne-0.3*\xOne+0.1*\yOne,5.5*\zTwo-0.3*\xTwo+0.1*\yTwo) ..  (5.5*\zOne-0.6*\xOne+0.4*\yOne,5.5*\zTwo-0.6*\xTwo+0.4*\yTwo) node[anchor=north,align=center,font=\sffamily\scriptsize] {eixo \\ \'otico};

% PIXEL POSITION
\draw[thin,gray!70] (3*\zOne,3*\zTwo+0.75) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo) -- ++(0.21*\xOne,0.21*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo) -- ++(0.21*\xOne,0.21*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo) -- ++(0.21*\xOne,0.21*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo) -- ++(0.21*\xOne,0.21*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo) -- ++(0.21*\xOne,0.21*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.105*\yOne,-0.105*\yTwo) -- ++(0.21*\xOne,0.21*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.21*\yOne,-0.21*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo) -- ++(-0.105*\xOne,-0.105*\xTwo) -- ++(-0.19*\yOne,-0.19*\yTwo) -- ++(0.105*\xOne,0.105*\xTwo) -- ++(0.105*\yOne,0.105*\yTwo);

\end{tikzpicture}
\end{document}

答案1

哇!这真的很优雅。
不过,如果你使用 TikZ 3D 坐标系(定义为\draw (0,1,2)--(2,3,4);),你的生活就会轻松很多,如果需要,可以用或类似的东西调整 x、y 和 z 坐标\begin{tikzpicture}[x={(1cm,0cm)},y={(0cm,1cm)},z={(0.73cm,0.73cm)}]。这会改变 x、y 和 z 投影到 x 和 y 上的长度。

另外,你也可以使用该tikz-3dplot包来旋转相机视角的方位角和仰角。其实只有两行代码:

\tdplotsetmaincoords{70}{110}
\begin{tikzpicture}[tdplot_main_coords]

方位角为 70 度,仰角为 110 度。

但是,在旋转时,您必须记住,TikZ 没有真正的 3D 支持,例如:
z 缓冲尚未支持。因此,您可能必须在旋转后调整一些颜色。这是因为,随着旋转,绘制顺序可能会发生变化。然后,由于计算时间的原因,事物会位于其他事物的前面,而不是它们在 3D 中的位置。这在tikz3dplot 示例手册,第 3.3 章。

此外,使用相对坐标有助于将注意力集中在内容上,而不是图形的创建。\draw (2,3,4)--++(0,0,1);从您原来的位置带您向 z 方向移动一步。

顺便提一下,你应该在序言中加载 TikZ 包,否则你必须在每个范围内重新加载它们。对于较大的文档,这会降低编译速度。

答案2

我不确定这是否是严重重复,但我重新绘制了它,以便提供该图表的修改版本这个答案Catree 的问题并认为在这里提供未修改版本的代码可能会有用。我本来打算只是留下一条评论,但后来意识到需要更改几件事才能生成原始图表,而评论太多了。因此,我希望大家能原谅我的重复。(如果不行,我可以删除它。)

该方法tikz-3dplot使用DennisH 的回答

% ail-wneud y llun o gwestiwn perr0: https://tex.stackexchange.com/q/96074/
% côd newydd
\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{calc,arrows.meta,positioning,backgrounds}
\begin{document}
\tdplotsetmaincoords{-60}{-35}
\begin{tikzpicture}
  [
    tdplot_main_coords,
    >=Stealth,
    my dashed/.style={dashed, thick, ->, shorten >=-15pt, shorten <=-15pt, every node/.append style={font=\footnotesize}},
    my box/.style={thin, gray!70},
    my blue/.style={blue, line cap=round, -{Triangle[width=3*#1]}, line width=#1, shorten >=#1*1.75pt, every node/.append style={fill, circle, inner sep=0pt, minimum size=#1*3.5pt, anchor=center, outer sep=0pt}},
    my label/.append style={midway, font=\scriptsize},
    my vectors/.style={green!50!black, {Stealth[scale=.75]}-{Stealth[scale=.75]}},
    my red/.style={thick, red, line cap=round},
    my grey/.style={gray!70},
    description/.style={draw=gray!70, thick, line cap=round, every node/.style={align=center, font=\scriptsize\sffamily, anchor=north}},
  ]
%   \draw [help lines] (-2,0,0) -- (2,0,0) node[anchor=north west]{$x$} (0,0,0) -- (0,7,0) node[anchor=north east]{$y$} (0,0,0) -- (0,0,2) node[anchor=north]{$z$} (-2,7,0) -- (2,7,0);
  \draw [my grey] (0,4,0) -- (0,7,0) (-2,7,0) -- (2,7,0);
  \coordinate (o) at (0,0,0);
  \path [draw=gray!70, text=gray, fill=gray!20, opacity=0.8, text opacity=1] (-1.5,4,1.75) coordinate (a) -- ++(0,0,-3.5) coordinate (b) -- ++(3,0,0) coordinate (c) -- ++(0,0,3.5) coordinate (d) -- cycle node [pos=.95, above, sloped, anchor=south west] {$z=f$} ;
%   \foreach \i in {a,b,c,d} \node [red, font=\scriptsize] at (\i) {\i};
  \draw [my grey] (-2,0,0) -- (2,0,0) (0,0,0) -- (0,4,0) (0,0,0) -- (0,0,2);
  \draw [thick, ->, every node/.style={font=\footnotesize, inner sep=0pt}] (o) node [anchor=north west] {$F_c$} (o) edge node [pos=1, anchor=north east] {$z_c$} ++(0,1,0) edge node [pos=1, anchor=north] {$y_c$} ++(0,0,1) -- ++(1,0,0) node [anchor=north west] {$x_c$};
  \draw [my box] (o) ++(0,4,-.5) coordinate (p1) -- ++(1,0,0) coordinate (p2) -- ++(0,0,-1.25) coordinate (p3);
  \foreach \i in {0,1,...,4} \draw [my box] (p1) ++(\i*.25,0,0) -- ++(0,0,-.25);
  \foreach \i in {0,1,...,5} \draw [my box] (p2) ++(0,0,-\i*.25) -- ++(-.25,0,0);
  \draw [my box] (p1) ++(0,0,-.25) -- ++(.75,0,0) -- ++(0,0,-1);
  \draw [my dashed, cyan] ($(b)!1/2!(c)$) -- ($(d)!1/2!(a)$) node [below=15pt, anchor=north] {$y$};
  \draw [my dashed, cyan] ($(b)!1/2!(a)$) -- ($(d)!1/2!(c)$) node [above right=17pt, anchor=north west] {$x$};
  \draw [my dashed, green!50!black, <->] (a) node [below=15pt, anchor=north] {$v$} -- (b) -- (c) node [above right=17pt, anchor=north west] {$u$};
  \path [green!50!black, every node/.style={font=\scriptsize, inner sep=0pt}] (p2) node [above right, anchor=south west] {$(u,v)$};
  \path (p2) ++(-.125,0,0) coordinate (q2) ++(0,0,-.125) coordinate (r2);
  \draw [my blue=1] ($(0,4,0)+($(q2)-(p1)$)$) coordinate (s2) -- (r2) node (d1) {};
  \scoped[on background layer]{\draw [my blue=1.75] ($($1.75*($(s2)-(0,4,0)$)$)+(0,7,0)$) -- ++($1.75*($(r2)-(s2)$)$) node (d2) [label={[label distance=-20pt]above:{$P=(X,Y,Z)$}}] {};}
  \draw [my vectors] (0,4,.1) -- ($(s2)+(0,0,.1)$) node [below, my label, sloped] {$\vec{u}$};
  \draw [my vectors] (-.1,4,0) -- ($(q2)-(s2)+(-.1,4,0)$) node [left, my label] {$\vec{v}$};
  \draw [my red] (o) -- (d1.center);
  \scoped[on background layer]{\draw [my red] (d1.center) -- (d2.center);}
  \path [description] (0,4,0) [out=-95, in=95] to (-.75,4,.25) node {ponto\\principal} (0,6.5,0) [out=-95, in=95] to (-.75,6.5,.25) node {eixo\\\'otico};
\end{tikzpicture}
\end{document}

带有 <code>tikz-3dplot</code> 的针孔相机

相关内容