25

This question led to a new library in TikZ:
perspective (PGF manual, chapter 63)

I have a 3d object created with inkscape as shown below:

enter image description here

Now I am trying to place a text in the same orientation as the light-blue colored area. However, I want to insert the text with latex instead of directly embedding it in the pdf (hence, I save it with pdf+Latex option in inkscape).

But when I try to insert the text in the 3d area, I get:

![enter image description here

How can I get OMEAG aligned parallely to the light-blue region.

I could not attach the pdf of it, however the MWE is below:

%&lualatex
% !TeX program = lualatex
\documentclass[11pt,a4paper]{article}
%\usepackage[latin1]{inputenc}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{xcolor}
\usepackage{pgfplots}
\usepackage{pstricks}    %for embedding pspicture.
\pgfplotsset{compat=newest}
\usepackage{tikz}
\begin{document}
    \begin{figure}[h]
    \centering{
        \input{drawing4.pdf_tex}
        \caption{Top view.}
        \label{fig:aktomnpView}
    }
\end{figure}
\end{document}

and \input{drawing4.pdf_tex} is below:

\begingroup%
  \makeatletter%
  \providecommand\color[2][]{%
    \errmessage{(Inkscape) Color is used for the text in Inkscape, but the package 'color.sty' is not loaded}%
    \renewcommand\color[2][]{}%
  }%
  \providecommand\transparent[1]{%
    \errmessage{(Inkscape) Transparency is used (non-zero) for the text in Inkscape, but the package 'transparent.sty' is not loaded}%
    \renewcommand\transparent[1]{}%
  }%
  \providecommand\rotatebox[2]{#2}%
  \newcommand*\fsize{\dimexpr\f@size pt\relax}%
  \newcommand*\lineheight[1]{\fontsize{\fsize}{#1\fsize}\selectfont}%
  \ifx\svgwidth\undefined%
    \setlength{\unitlength}{303.69978591bp}%
    \ifx\svgscale\undefined%
      \relax%
    \else%
      \setlength{\unitlength}{\unitlength * \real{\svgscale}}%
    \fi%
  \else%
    \setlength{\unitlength}{\svgwidth}%
  \fi%
  \global\let\svgwidth\undefined%
  \global\let\svgscale\undefined%
  \makeatother%
  \begin{picture}(1,1.35089637)%
    \lineheight{1}%
    \setlength\tabcolsep{0pt}%
    \put(0,0){\includegraphics[width=\unitlength,page=1]{drawing4.pdf}}%
    \put(0.54334545,0.71256022){\color[rgb]{0,0,0}\makebox(0,0)[lt]{\lineheight{1.25}\smash{\begin{tabular}[t]{l}OMEAG\end{tabular}}}}%
  \end{picture}%
\endgroup%
3
  • 1
    Do you want it only rotated as if written on the right 'wall', or really perspective-ish with the first letters bigger than the last letters?
    – Max
    Aug 22, 2018 at 6:52
  • @Max I would prefer it to have it written on the wall :) Aug 22, 2018 at 6:53
  • Please see my edit, it may be more applicable for your use now.
    – Max
    Aug 22, 2018 at 11:47

3 Answers 3

40
+1000

Edit 3

I'm happy to announce that some of the code of this answer is now included in the Tikz package (v3.1.2) as the perspective library.

Edit 2

Using this awesome answer in combination with my tpp coordinate system, I managed to get an approximation of a nonlinear mapping to the side of the block.

enter image description here

Or without help lines:

enter image description here

Stationary image:

enter image description here

MWE:

\documentclass[tikz]{standalone}

\usepackage{tikz}
\usepackage{tikz-3dplot}

\usepgfmodule{nonlineartransformations}

\usepackage{mathtools}

\makeatletter

\def\tikz@scan@transform@one@point#1{%
  \tikz@scan@one@point\pgf@process#1%
  \pgf@pos@transform{\pgf@x}{\pgf@y}}
\tikzset{%
  grid source opposite corners/.code args={#1and#2}{%
   \pgfextract@process\tikz@transform@source@southwest{%
     \tikz@scan@transform@one@point{#1}}%
   \pgfextract@process\tikz@transform@source@northeast{%
     \tikz@scan@transform@one@point{#2}}%
  },
  grid target corners/.code args={#1--#2--#3--#4}{%
   \pgfextract@process\tikz@transform@target@southwest{%
     \tikz@scan@transform@one@point{#1}}%
   \pgfextract@process\tikz@transform@target@southeast{%
     \tikz@scan@transform@one@point{#2}}%
   \pgfextract@process\tikz@transform@target@northeast{%
     \tikz@scan@transform@one@point{#3}}%
   \pgfextract@process\tikz@transform@target@northwest{%
     \tikz@scan@transform@one@point{#4}}%
  }
}

\def\tikzgridtransform{%
  \pgfextract@process\tikz@current@point{}%
  \pgf@process{%
    \pgfpointdiff{\tikz@transform@source@southwest}%
      {\tikz@transform@source@northeast}%
  }%
  \pgf@xc=\pgf@x\pgf@yc=\pgf@y%
  \pgf@process{%
    \pgfpointdiff{\tikz@transform@source@southwest}{\tikz@current@point}%
  }%
  \pgfmathparse{\pgf@x/\pgf@xc}\let\tikz@tx=\pgfmathresult%
  \pgfmathparse{\pgf@y/\pgf@yc}\let\tikz@ty=\pgfmathresult%
  %
  \pgfpointlineattime{\tikz@ty}{%
    \pgfpointlineattime{\tikz@tx}{\tikz@transform@target@southwest}%
      {\tikz@transform@target@southeast}}{%
    \pgfpointlineattime{\tikz@tx}{\tikz@transform@target@northwest}%
      {\tikz@transform@target@northeast}}%
}

% Initialize H matrix for perspective view
\pgfmathsetmacro\H@tpp@aa{1}\pgfmathsetmacro\H@tpp@ab{0}\pgfmathsetmacro\H@tpp@ac{0}%\pgfmathsetmacro\H@tpp@ad{0}
\pgfmathsetmacro\H@tpp@ba{0}\pgfmathsetmacro\H@tpp@bb{1}\pgfmathsetmacro\H@tpp@bc{0}%\pgfmathsetmacro\H@tpp@bd{0}
\pgfmathsetmacro\H@tpp@ca{0}\pgfmathsetmacro\H@tpp@cb{0}\pgfmathsetmacro\H@tpp@cc{1}%\pgfmathsetmacro\H@tpp@cd{0}
\pgfmathsetmacro\H@tpp@da{0}\pgfmathsetmacro\H@tpp@db{0}\pgfmathsetmacro\H@tpp@dc{0}%\pgfmathsetmacro\H@tpp@dd{1}

%Initialize H matrix for main rotation
\pgfmathsetmacro\H@rot@aa{1}\pgfmathsetmacro\H@rot@ab{0}\pgfmathsetmacro\H@rot@ac{0}%\pgfmathsetmacro\H@rot@ad{0}
\pgfmathsetmacro\H@rot@ba{0}\pgfmathsetmacro\H@rot@bb{1}\pgfmathsetmacro\H@rot@bc{0}%\pgfmathsetmacro\H@rot@bd{0}
\pgfmathsetmacro\H@rot@ca{0}\pgfmathsetmacro\H@rot@cb{0}\pgfmathsetmacro\H@rot@cc{1}%\pgfmathsetmacro\H@rot@cd{0}
%\pgfmathsetmacro\H@rot@da{0}\pgfmathsetmacro\H@rot@db{0}\pgfmathsetmacro\H@rot@dc{0}\pgfmathsetmacro\H@rot@dd{1}

\pgfkeys{
    /three point perspective/.cd,
        p/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#1))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ba{#2/#1}
                \pgfmathsetmacro\H@tpp@ca{#3/#1}
                \pgfmathsetmacro\H@tpp@da{ 1/#1}
                \coordinate (vp-p) at (#1,#2,#3);
            \fi
        },
        q/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#2))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ab{#1/#2}
                \pgfmathsetmacro\H@tpp@cb{#3/#2}
                \pgfmathsetmacro\H@tpp@db{ 1/#2}
                \coordinate (vp-q) at (#1,#2,#3);
            \fi
        },
        r/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#3))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ac{#1/#3}
                \pgfmathsetmacro\H@tpp@bc{#2/#3}
                \pgfmathsetmacro\H@tpp@dc{ 1/#3}
                \coordinate (vp-r) at (#1,#2,#3);
            \fi
        },
        coordinate/.code args={#1,#2,#3}{
            \def\tpp@x{#1}
            \def\tpp@y{#2}
            \def\tpp@z{#3}
        },
}

\tikzset{
    view/.code 2 args={
        \pgfmathsetmacro\rot@main@theta{#1}
        \pgfmathsetmacro\rot@main@phi{#2}
        % Row 1
        \pgfmathsetmacro\H@rot@aa{cos(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ab{sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ac{0}
        % Row 2
        \pgfmathsetmacro\H@rot@ba{-cos(\rot@main@theta)*sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@bb{cos(\rot@main@phi)*cos(\rot@main@theta)}
        \pgfmathsetmacro\H@rot@bc{sin(\rot@main@theta)}
        % Row 3
        \pgfmathsetmacro\H@m@ca{sin(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cb{-cos(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cc{cos(\rot@main@theta)}
        % Set vector values
        \pgfmathsetmacro\vec@x@x{\H@rot@aa}
        \pgfmathsetmacro\vec@y@x{\H@rot@ab}
        \pgfmathsetmacro\vec@z@x{\H@rot@ac}
        \pgfmathsetmacro\vec@x@y{\H@rot@ba}
        \pgfmathsetmacro\vec@y@y{\H@rot@bb}
        \pgfmathsetmacro\vec@z@y{\H@rot@bc}
        % Set pgf vectors
        \pgfsetxvec{\pgfpoint{\vec@x@x cm}{\vec@x@y cm}}
        \pgfsetyvec{\pgfpoint{\vec@y@x cm}{\vec@y@y cm}}
        \pgfsetzvec{\pgfpoint{\vec@z@x cm}{\vec@z@y cm}}
    },
}

\tikzset{
    perspective/.code={\pgfkeys{/three point perspective/.cd,#1}},
    perspective/.default={p={(15,0,0)},q={(0,15,0)},r={(0,0,50)}},
}

\tikzdeclarecoordinatesystem{three point perspective}{
    \pgfkeys{/three point perspective/.cd,coordinate={#1}}
    \pgfmathsetmacro\temp@p@w{\H@tpp@da*\tpp@x + \H@tpp@db*\tpp@y + \H@tpp@dc*\tpp@z + 1}
    \pgfmathsetmacro\temp@p@x{(\H@tpp@aa*\tpp@x + \H@tpp@ab*\tpp@y + \H@tpp@ac*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@y{(\H@tpp@ba*\tpp@x + \H@tpp@bb*\tpp@y + \H@tpp@bc*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@z{(\H@tpp@ca*\tpp@x + \H@tpp@cb*\tpp@y + \H@tpp@cc*\tpp@z)/\temp@p@w}
    \pgfpointxyz{\temp@p@x}{\temp@p@y}{\temp@p@z}
}
\tikzaliascoordinatesystem{tpp}{three point perspective}

\makeatother

\definecolor{mydarkbluishgray}{RGB}{134 134 191}
\definecolor{mylightbluishgray}{RGB}{215 215 255}

\begin{document}
    \foreach \vp in {10,12.5,...,50}{
%    \foreach \vp in {10}{
    \begin{tikzpicture}[line join=round]

        \clip (-12,0) rectangle (12,10);

        \begin{scope}[
            view={85}{-40},
            perspective={
                p = {(\vp,0,5.5)},
                q = {(0,\vp,5.5)},
            }
        ]
            \fill[mydarkbluishgray]  (tpp cs:0,0,0) -- (tpp cs:0,0,10) -- (tpp cs:0,5,10) -- (tpp cs:0,5,0) -- cycle;
            \fill[mylightbluishgray] (tpp cs:0,0,0) -- (tpp cs:0,0,10) -- (tpp cs:15,0,10) -- (tpp cs:15,0,0) -- cycle;

            \begin{scope}[
                grid source opposite corners={(0cm,0cm) and (15cm,10cm)},
                grid target corners={(tpp cs:0,0,0)--(tpp cs:15,0,0)--(tpp cs:15,0,10)--(tpp cs:0,0,10)}
            ]
                \pgftransformnonlinear\tikzgridtransform

%                \draw[dotted] (0cm,4.75cm) -- (15cm,4.75cm);
%                \draw[red]    (0cm,5.00cm) -- (15cm,5.00cm);
%                \draw[dotted] (0cm,5.25cm) -- (15cm,5.25cm);
%                
%                \draw[dotted] (6.1cm,0cm) -- (6.1cm,10cm);
%                \draw[red]    (7.5cm,0cm) -- (7.5cm,10cm);
%                \draw[dotted] (8.9cm,0cm) -- (8.9cm,10cm);

                \foreach \char [count=\i from -2] in {O,M,E,A,G}{
                    \pgftransformshift{\pgfpointadd{\pgfpoint{7.5cm}{5cm}}{\pgfpoint{\i *0.6cm}{0cm}}}
                    \pgftransformscale{2}
                    \pgfnode{rectangle}{center}{\char}{}{}
                }
            \end{scope}

%            \begin{scope}[dotted,line width=0.2pt]
%                \node[label=right:p,fill,circle,inner sep = 2pt] (p) at (vp-p){};
%
%                \draw (tpp cs:0,0,10) -- (p.center);
%                \draw (tpp cs:0,0,0) -- (p.center);
%                \draw (tpp cs:0,5,10) -- (p.center);
%                \draw (tpp cs:0,5,0) -- (p.center);
%
%                \node[label=left:q,fill,circle,inner sep = 2pt] (q) at (vp-q){};
%
%                \draw (tpp cs:0,0,10) -- (q.center);
%                \draw (tpp cs:0,0,0) -- (q.center);
%                \draw (tpp cs:15,0,10) -- (q.center);
%                \draw (tpp cs:15,0,0) -- (q.center);
%            \end{scope}
        \end{scope}
    \end{tikzpicture}
    }
\end{document}

Edit See previous edits for my former answer

I defined a new coordinate system three point perspective. It can be used as

\draw (three point perspective cs:0,0,0) -- (three point perspective cs:5,5,5);

Or slightly more convenient

\draw (tpp cs:0,0,0) -- (tpp cs:5,5,5);

To turn perspective view on, you can call the perspective={<options>} Tikz-key. The options are:

  • p={(p_x,p_y,p_z)} to set the vanishing point in x direction, to turn of set p_x to 0.
  • q={(q_x,q_y,q_z)} to set the vanishing point in y direction, to turn of set q_y to 0.
  • r={(r_x,r_y,r_z)} to set the vanishing point in z direction, to turn of set r_z to 0.

The default perspective is set to p={(15,0,0)},q={(0,15,0)},r={(0,0,50)}.

To change the viewing angle, I also added a view={<rotate about x>}{<rotate about z>} key. The latter ensures that I don't need the tikz-3dplot any longer.

enter image description here

The result is similar, but is easier to use.

\documentclass[tikz]{standalone}

\usepackage{tikz}
\usepackage{tikz-3dplot}

\usepackage{mathtools}

\makeatletter

% Initialize H matrix for perspective view
\pgfmathsetmacro\H@tpp@aa{1}\pgfmathsetmacro\H@tpp@ab{0}\pgfmathsetmacro\H@tpp@ac{0}%\pgfmathsetmacro\H@tpp@ad{0}
\pgfmathsetmacro\H@tpp@ba{0}\pgfmathsetmacro\H@tpp@bb{1}\pgfmathsetmacro\H@tpp@bc{0}%\pgfmathsetmacro\H@tpp@bd{0}
\pgfmathsetmacro\H@tpp@ca{0}\pgfmathsetmacro\H@tpp@cb{0}\pgfmathsetmacro\H@tpp@cc{1}%\pgfmathsetmacro\H@tpp@cd{0}
\pgfmathsetmacro\H@tpp@da{0}\pgfmathsetmacro\H@tpp@db{0}\pgfmathsetmacro\H@tpp@dc{0}%\pgfmathsetmacro\H@tpp@dd{1}

%Initialize H matrix for main rotation
\pgfmathsetmacro\H@rot@aa{1}\pgfmathsetmacro\H@rot@ab{0}\pgfmathsetmacro\H@rot@ac{0}%\pgfmathsetmacro\H@rot@ad{0}
\pgfmathsetmacro\H@rot@ba{0}\pgfmathsetmacro\H@rot@bb{1}\pgfmathsetmacro\H@rot@bc{0}%\pgfmathsetmacro\H@rot@bd{0}
\pgfmathsetmacro\H@rot@ca{0}\pgfmathsetmacro\H@rot@cb{0}\pgfmathsetmacro\H@rot@cc{1}%\pgfmathsetmacro\H@rot@cd{0}
%\pgfmathsetmacro\H@rot@da{0}\pgfmathsetmacro\H@rot@db{0}\pgfmathsetmacro\H@rot@dc{0}\pgfmathsetmacro\H@rot@dd{1}

\pgfkeys{
    /three point perspective/.cd,
        p/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#1))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ba{#2/#1}
                \pgfmathsetmacro\H@tpp@ca{#3/#1}
                \pgfmathsetmacro\H@tpp@da{ 1/#1}
                \coordinate (vp-p) at (#1,#2,#3);
            \fi
        },
        q/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#2))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ab{#1/#2}
                \pgfmathsetmacro\H@tpp@cb{#3/#2}
                \pgfmathsetmacro\H@tpp@db{ 1/#2}
                \coordinate (vp-q) at (#1,#2,#3);
            \fi
        },
        r/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#3))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ac{#1/#3}
                \pgfmathsetmacro\H@tpp@bc{#2/#3}
                \pgfmathsetmacro\H@tpp@dc{ 1/#3}
                \coordinate (vp-r) at (#1,#2,#3);
            \fi
        },
        coordinate/.code args={#1,#2,#3}{
            \def\tpp@x{#1}
            \def\tpp@y{#2}
            \def\tpp@z{#3}
        },
}

\tikzset{
    view/.code 2 args={
        \pgfmathsetmacro\rot@main@theta{#1}
        \pgfmathsetmacro\rot@main@phi{#2}
        % Row 1
        \pgfmathsetmacro\H@rot@aa{cos(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ab{sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ac{0}
        % Row 2
        \pgfmathsetmacro\H@rot@ba{-cos(\rot@main@theta)*sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@bb{cos(\rot@main@phi)*cos(\rot@main@theta)}
        \pgfmathsetmacro\H@rot@bc{sin(\rot@main@theta)}
        % Row 3
        \pgfmathsetmacro\H@m@ca{sin(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cb{-cos(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cc{cos(\rot@main@theta)}

        \pgfmathsetmacro\vec@x@x{\H@rot@aa}
        \pgfmathsetmacro\vec@y@x{\H@rot@ab}
        \pgfmathsetmacro\vec@z@x{\H@rot@ac}
        \pgfmathsetmacro\vec@x@y{\H@rot@ba}
        \pgfmathsetmacro\vec@y@y{\H@rot@bb}
        \pgfmathsetmacro\vec@z@y{\H@rot@bc}

        \pgfsetxvec{\pgfpoint{\vec@x@x cm}{\vec@x@y cm}}
        \pgfsetyvec{\pgfpoint{\vec@y@x cm}{\vec@y@y cm}}
        \pgfsetzvec{\pgfpoint{\vec@z@x cm}{\vec@z@y cm}}
    },
}

\tikzset{
    perspective/.code={\pgfkeys{/three point perspective/.cd,#1}},
    perspective/.default={p={(15,0,0)},q={(0,15,0)},r={(0,0,50)}},
}

\tikzdeclarecoordinatesystem{three point perspective}{
    \pgfkeys{/three point perspective/.cd,coordinate={#1}}
    \pgfmathsetmacro\temp@p@w{\H@tpp@da*\tpp@x + \H@tpp@db*\tpp@y + \H@tpp@dc*\tpp@z + 1}
    \pgfmathsetmacro\temp@p@x{(\H@tpp@aa*\tpp@x + \H@tpp@ab*\tpp@y + \H@tpp@ac*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@y{(\H@tpp@ba*\tpp@x + \H@tpp@bb*\tpp@y + \H@tpp@bc*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@z{(\H@tpp@ca*\tpp@x + \H@tpp@cb*\tpp@y + \H@tpp@cc*\tpp@z)/\temp@p@w}
    \pgfpointxyz{\temp@p@x}{\temp@p@y}{\temp@p@z}
}
\tikzaliascoordinatesystem{tpp}{three point perspective}

\makeatother

\definecolor{mydarkbluishgray}{RGB}{134 134 191}
\definecolor{mylightbluishgray}{RGB}{215 215 255}

\begin{document}
    \begin{tikzpicture}[line join=round]

        \begin{scope}[
            scale=10,
            view={85}{-40},
            perspective={
                p = {(1,0,0.55)},
                q = {(0,1,0.55)},
            }
        ]
            \fill[mydarkbluishgray]  (tpp cs:0,0,0) -- (tpp cs:0,0,1) -- (tpp cs:0,0.5,1) -- (tpp cs:0,0.5,0) -- cycle;
            \fill[mylightbluishgray] (tpp cs:0,0,0) -- (tpp cs:0,0,1) -- (tpp cs:1.5,0,1) -- (tpp cs:1.5,0,0) -- cycle;

            \path (tpp cs:0,0,0.5) -- node[sloped]{OMEAG} (tpp cs:1.5,0,0.5);

            \begin{scope}[dotted,line width=0.2pt]
                \node[label=right:p,fill,circle,inner sep = 2pt] (p) at (vp-p){};

                \draw (tpp cs:0,0,1) -- (p.center);
                \draw (tpp cs:0,0,0) -- (p.center);
                \draw (tpp cs:0,0.5,1) -- (p.center);
                \draw (tpp cs:0,0.5,0) -- (p.center);

                \node[label=left:q,fill,circle,inner sep = 2pt] (q) at (vp-q){};

                \draw (tpp cs:0,0,1) -- (q.center);
                \draw (tpp cs:0,0,0) -- (q.center);
                \draw (tpp cs:1.5,0,1) -- (q.center);
                \draw (tpp cs:1.5,0,0) -- (q.center);
            \end{scope}
        \end{scope}
    \end{tikzpicture}
\end{document}

Of course I had to make an animation to show different vanishing point distances:

enter image description here

MWE animation:

\documentclass[tikz]{standalone}

\usepackage{tikz}
\usepackage{tikz-3dplot}

\usepackage{mathtools}

\makeatletter

% Initialize H matrix for perspective view
\pgfmathsetmacro\H@tpp@aa{1}\pgfmathsetmacro\H@tpp@ab{0}\pgfmathsetmacro\H@tpp@ac{0}%\pgfmathsetmacro\H@tpp@ad{0}
\pgfmathsetmacro\H@tpp@ba{0}\pgfmathsetmacro\H@tpp@bb{1}\pgfmathsetmacro\H@tpp@bc{0}%\pgfmathsetmacro\H@tpp@bd{0}
\pgfmathsetmacro\H@tpp@ca{0}\pgfmathsetmacro\H@tpp@cb{0}\pgfmathsetmacro\H@tpp@cc{1}%\pgfmathsetmacro\H@tpp@cd{0}
\pgfmathsetmacro\H@tpp@da{0}\pgfmathsetmacro\H@tpp@db{0}\pgfmathsetmacro\H@tpp@dc{0}%\pgfmathsetmacro\H@tpp@dd{1}

%Initialize H matrix for main rotation
\pgfmathsetmacro\H@rot@aa{1}\pgfmathsetmacro\H@rot@ab{0}\pgfmathsetmacro\H@rot@ac{0}%\pgfmathsetmacro\H@rot@ad{0}
\pgfmathsetmacro\H@rot@ba{0}\pgfmathsetmacro\H@rot@bb{1}\pgfmathsetmacro\H@rot@bc{0}%\pgfmathsetmacro\H@rot@bd{0}
\pgfmathsetmacro\H@rot@ca{0}\pgfmathsetmacro\H@rot@cb{0}\pgfmathsetmacro\H@rot@cc{1}%\pgfmathsetmacro\H@rot@cd{0}
%\pgfmathsetmacro\H@rot@da{0}\pgfmathsetmacro\H@rot@db{0}\pgfmathsetmacro\H@rot@dc{0}\pgfmathsetmacro\H@rot@dd{1}

\pgfkeys{
    /three point perspective/.cd,
        p/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#1))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ba{#2/#1}
                \pgfmathsetmacro\H@tpp@ca{#3/#1}
                \pgfmathsetmacro\H@tpp@da{ 1/#1}
                \coordinate (vp-p) at (#1,#2,#3);
            \fi
        },
        q/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#2))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ab{#1/#2}
                \pgfmathsetmacro\H@tpp@cb{#3/#2}
                \pgfmathsetmacro\H@tpp@db{ 1/#2}
                \coordinate (vp-q) at (#1,#2,#3);
            \fi
        },
        r/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#3))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ac{#1/#3}
                \pgfmathsetmacro\H@tpp@bc{#2/#3}
                \pgfmathsetmacro\H@tpp@dc{ 1/#3}
                \coordinate (vp-r) at (#1,#2,#3);
            \fi
        },
        coordinate/.code args={#1,#2,#3}{
            \def\tpp@x{#1}
            \def\tpp@y{#2}
            \def\tpp@z{#3}
        },
}

\tikzset{
    view/.code 2 args={
        \pgfmathsetmacro\rot@main@theta{#1}
        \pgfmathsetmacro\rot@main@phi{#2}
        % Row 1
        \pgfmathsetmacro\H@rot@aa{cos(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ab{sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ac{0}
        % Row 2
        \pgfmathsetmacro\H@rot@ba{-cos(\rot@main@theta)*sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@bb{cos(\rot@main@phi)*cos(\rot@main@theta)}
        \pgfmathsetmacro\H@rot@bc{sin(\rot@main@theta)}
        % Row 3
        \pgfmathsetmacro\H@m@ca{sin(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cb{-cos(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cc{cos(\rot@main@theta)}
        % Set vector values
        \pgfmathsetmacro\vec@x@x{\H@rot@aa}
        \pgfmathsetmacro\vec@y@x{\H@rot@ab}
        \pgfmathsetmacro\vec@z@x{\H@rot@ac}
        \pgfmathsetmacro\vec@x@y{\H@rot@ba}
        \pgfmathsetmacro\vec@y@y{\H@rot@bb}
        \pgfmathsetmacro\vec@z@y{\H@rot@bc}
        % Set pgf vectors
        \pgfsetxvec{\pgfpoint{\vec@x@x cm}{\vec@x@y cm}}
        \pgfsetyvec{\pgfpoint{\vec@y@x cm}{\vec@y@y cm}}
        \pgfsetzvec{\pgfpoint{\vec@z@x cm}{\vec@z@y cm}}
    },
}

\tikzset{
    perspective/.code={\pgfkeys{/three point perspective/.cd,#1}},
    perspective/.default={p={(15,0,0)},q={(0,15,0)},r={(0,0,50)}},
}

\tikzdeclarecoordinatesystem{three point perspective}{
    \pgfkeys{/three point perspective/.cd,coordinate={#1}}
    \pgfmathsetmacro\temp@p@w{\H@tpp@da*\tpp@x + \H@tpp@db*\tpp@y + \H@tpp@dc*\tpp@z + 1}
    \pgfmathsetmacro\temp@p@x{(\H@tpp@aa*\tpp@x + \H@tpp@ab*\tpp@y + \H@tpp@ac*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@y{(\H@tpp@ba*\tpp@x + \H@tpp@bb*\tpp@y + \H@tpp@bc*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@z{(\H@tpp@ca*\tpp@x + \H@tpp@cb*\tpp@y + \H@tpp@cc*\tpp@z)/\temp@p@w}
    \pgfpointxyz{\temp@p@x}{\temp@p@y}{\temp@p@z}
}
\tikzaliascoordinatesystem{tpp}{three point perspective}

\makeatother

\definecolor{mydarkbluishgray}{RGB}{134 134 191}
\definecolor{mylightbluishgray}{RGB}{215 215 255}

\begin{document}
    \foreach \vp in {1,1.1,...,5}{
%    \foreach \vp in {1}{
    \begin{tikzpicture}[line join=round]

        \clip (-12,0) rectangle (12,10);

        \begin{scope}[
            scale=10,
            view={85}{-40},
            perspective={
                p = {(\vp,0,0.55)},
                q = {(0,\vp,0.55)},
            }
        ]
            \fill[mydarkbluishgray]  (tpp cs:0,0,0) -- (tpp cs:0,0,1) -- (tpp cs:0,0.5,1) -- (tpp cs:0,0.5,0) -- cycle;
            \fill[mylightbluishgray] (tpp cs:0,0,0) -- (tpp cs:0,0,1) -- (tpp cs:1.5,0,1) -- (tpp cs:1.5,0,0) -- cycle;

            \path[dotted] (tpp cs:0,0,0.5) -- node[sloped]{OMEAG} (tpp cs:1.5,0,0.5);

            \begin{scope}[dotted,line width=0.2pt]
                \node[label=right:p,fill,circle,inner sep = 2pt] (p) at (vp-p){};

                \draw (tpp cs:0,0,1) -- (p.center);
                \draw (tpp cs:0,0,0) -- (p.center);
                \draw (tpp cs:0,0.5,1) -- (p.center);
                \draw (tpp cs:0,0.5,0) -- (p.center);

                \node[label=left:q,fill,circle,inner sep = 2pt] (q) at (vp-q){};

                \draw (tpp cs:0,0,1) -- (q.center);
                \draw (tpp cs:0,0,0) -- (q.center);
                \draw (tpp cs:1.5,0,1) -- (q.center);
                \draw (tpp cs:1.5,0,0) -- (q.center);
            \end{scope}
        \end{scope}
    \end{tikzpicture}
    }
\end{document}

Appendix: Two point perspective theory

A perspective transformation with two vanishing points can be described with a four by four transformation matrix H which is a function of the two vanishing points p with p_x <> 0, and r with r_y <> 0.

enter image description here

You can build H as follows

enter image description here

To be able to transform a point x expressed in 3D with H, it must be expressed in a projected space, which can be written as

enter image description here

Any multiplication (elongation of the 4D vector) of a vector in projected space with a non-zero scalar alpha, still maps to the same point in 3D space. E.g., the following two points map to the same point in 3D space:

enter image description here

So to get the three coordinates of the 3D point, you can divide all entries by the fourth entry (we need this after multiplication with a transformation matrix as H).

29
  • 1
    I liked your matlab workaround, hence +1. However, this is just a small piece of big story, where I will be creating a 3d design of a system, so creating it with matlab will be too-much-to-do in that case. Aug 22, 2018 at 8:03
  • 2
    @AndréC True but I had to leave some work for marmot. More seriously, I'm still trying to get a nonlinear transformation to work for that, but I also have to put some time in my thesis.
    – Max
    Aug 22, 2018 at 17:18
  • 4
    Congratulations! That's truly outstanding! Just looking forward to the day when this answer starts with the lines "This answer has lead to a new package". ;-)
    – user121799
    Aug 23, 2018 at 1:44
  • 1
    @marmot I found the error. It was not really in the way how the parser accepted its arguments, but I used \def instead of \pgfmathsetmacro. The latter is a bit more lenient towards spaces. So it does work when changing all \defs to \pgfmathsetmacros in the coordinate/.code
    – Max
    Sep 5, 2018 at 7:08
  • 1
    Yes, that works!
    – user121799
    Sep 5, 2018 at 7:11
14

When I saw Max's nice answer I could not resist to add some decorations.text effects. @Max : if you want to append this to your answer, I will be happy to delete this. The result is also not quite perfect since the individual characters do get rescaled, but not the different sides of the characters.

EDIT: Even though the rescaling of the heights was OK (I think) in my previous version, I did not properly stretch the widths of the characters. Therefore, the effect was weaker than it should be. Big thanks to AndreC for bringing me on the right (?) track!

\documentclass[tikz]{standalone}

\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{decorations.text,calc,math}

\usepackage{mathtools}

\makeatletter

% Initialize H matrix for perspective view
\pgfmathsetmacro\H@tpp@aa{1}\pgfmathsetmacro\H@tpp@ab{0}\pgfmathsetmacro\H@tpp@ac{0}%\pgfmathsetmacro\H@tpp@ad{0}
\pgfmathsetmacro\H@tpp@ba{0}\pgfmathsetmacro\H@tpp@bb{1}\pgfmathsetmacro\H@tpp@bc{0}%\pgfmathsetmacro\H@tpp@bd{0}
\pgfmathsetmacro\H@tpp@ca{0}\pgfmathsetmacro\H@tpp@cb{0}\pgfmathsetmacro\H@tpp@cc{1}%\pgfmathsetmacro\H@tpp@cd{0}
\pgfmathsetmacro\H@tpp@da{0}\pgfmathsetmacro\H@tpp@db{0}\pgfmathsetmacro\H@tpp@dc{0}%\pgfmathsetmacro\H@tpp@dd{1}

%Initialize H matrix for main rotation
\pgfmathsetmacro\H@rot@aa{1}\pgfmathsetmacro\H@rot@ab{0}\pgfmathsetmacro\H@rot@ac{0}%\pgfmathsetmacro\H@rot@ad{0}
\pgfmathsetmacro\H@rot@ba{0}\pgfmathsetmacro\H@rot@bb{1}\pgfmathsetmacro\H@rot@bc{0}%\pgfmathsetmacro\H@rot@bd{0}
\pgfmathsetmacro\H@rot@ca{0}\pgfmathsetmacro\H@rot@cb{0}\pgfmathsetmacro\H@rot@cc{1}%\pgfmathsetmacro\H@rot@cd{0}
%\pgfmathsetmacro\H@rot@da{0}\pgfmathsetmacro\H@rot@db{0}\pgfmathsetmacro\H@rot@dc{0}\pgfmathsetmacro\H@rot@dd{1}

\pgfkeys{
    /three point perspective/.cd,
        p/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#1))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ba{#2/#1}
                \pgfmathsetmacro\H@tpp@ca{#3/#1}
                \pgfmathsetmacro\H@tpp@da{ 1/#1}
                \coordinate (vp-p) at (#1,#2,#3);
            \fi
        },
        q/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#2))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ab{#1/#2}
                \pgfmathsetmacro\H@tpp@cb{#3/#2}
                \pgfmathsetmacro\H@tpp@db{ 1/#2}
                \coordinate (vp-q) at (#1,#2,#3);
            \fi
        },
        r/.code args={(#1,#2,#3)}{
            \pgfmathparse{int(round(#3))}
            \ifnum\pgfmathresult=0\else
                \pgfmathsetmacro\H@tpp@ac{#1/#3}
                \pgfmathsetmacro\H@tpp@bc{#2/#3}
                \pgfmathsetmacro\H@tpp@dc{ 1/#3}
                \coordinate (vp-r) at (#1,#2,#3);
            \fi
        },
        coordinate/.code args={#1,#2,#3}{
            \def\tpp@x{#1}
            \def\tpp@y{#2}
            \def\tpp@z{#3}
        },
}

\tikzset{
    view/.code 2 args={
        \pgfmathsetmacro\rot@main@theta{#1}
        \pgfmathsetmacro\rot@main@phi{#2}
        % Row 1
        \pgfmathsetmacro\H@rot@aa{cos(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ab{sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@ac{0}
        % Row 2
        \pgfmathsetmacro\H@rot@ba{-cos(\rot@main@theta)*sin(\rot@main@phi)}
        \pgfmathsetmacro\H@rot@bb{cos(\rot@main@phi)*cos(\rot@main@theta)}
        \pgfmathsetmacro\H@rot@bc{sin(\rot@main@theta)}
        % Row 3
        \pgfmathsetmacro\H@m@ca{sin(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cb{-cos(\rot@main@phi)*sin(\rot@main@theta)}
        \pgfmathsetmacro\H@m@cc{cos(\rot@main@theta)}
        % Set vector values
        \pgfmathsetmacro\vec@x@x{\H@rot@aa}
        \pgfmathsetmacro\vec@y@x{\H@rot@ab}
        \pgfmathsetmacro\vec@z@x{\H@rot@ac}
        \pgfmathsetmacro\vec@x@y{\H@rot@ba}
        \pgfmathsetmacro\vec@y@y{\H@rot@bb}
        \pgfmathsetmacro\vec@z@y{\H@rot@bc}
        % Set pgf vectors
        \pgfsetxvec{\pgfpoint{\vec@x@x cm}{\vec@x@y cm}}
        \pgfsetyvec{\pgfpoint{\vec@y@x cm}{\vec@y@y cm}}
        \pgfsetzvec{\pgfpoint{\vec@z@x cm}{\vec@z@y cm}}
    },
}

\tikzset{
    perspective/.code={\pgfkeys{/three point perspective/.cd,#1}},
    perspective/.default={p={(15,0,0)},q={(0,15,0)},r={(0,0,50)}},
}

\tikzdeclarecoordinatesystem{three point perspective}{
    \pgfkeys{/three point perspective/.cd,coordinate={#1}}
    \pgfmathsetmacro\temp@p@w{\H@tpp@da*\tpp@x + \H@tpp@db*\tpp@y + \H@tpp@dc*\tpp@z + 1}
    \pgfmathsetmacro\temp@p@x{(\H@tpp@aa*\tpp@x + \H@tpp@ab*\tpp@y + \H@tpp@ac*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@y{(\H@tpp@ba*\tpp@x + \H@tpp@bb*\tpp@y + \H@tpp@bc*\tpp@z)/\temp@p@w}
    \pgfmathsetmacro\temp@p@z{(\H@tpp@ca*\tpp@x + \H@tpp@cb*\tpp@y + \H@tpp@cc*\tpp@z)/\temp@p@w}
    \pgfpointxyz{\temp@p@x}{\temp@p@y}{\temp@p@z}
}
\tikzaliascoordinatesystem{tpp}{three point perspective}

\makeatother

\definecolor{mydarkbluishgray}{RGB}{134 134 191}
\definecolor{mylightbluishgray}{RGB}{215 215 255}

\begin{document}
    \foreach \vp in {1,1.1,...,5}{
%    \foreach \vp in {1}{
    \begin{tikzpicture}[line join=round]

        \clip (-12,0) rectangle (12,10);

        \begin{scope}[
            scale=10,
            view={85}{-40},
            perspective={
                p = {(\vp,0,0.55)},
                q = {(0,\vp,0.55)},
            }
        ]
            \fill[mydarkbluishgray]  (tpp cs:0,0,0) -- (tpp cs:0,0,1) -- (tpp cs:0,0.5,1) -- (tpp cs:0,0.5,0) -- cycle;
            \fill[mylightbluishgray] (tpp cs:0,0,0) -- (tpp cs:0,0,1) -- (tpp cs:1.5,0,1) -- (tpp cs:1.5,0,0) -- cycle;

            \path[dotted] (tpp cs:0,0,0.5) -- (tpp cs:1.5,0,0.5)
            node[sloped,midway,opacity=0](TEXT){~~Ducks, marmots and koala bears!~} ;
            % text effects1
            \draw let \p1=($(tpp cs:1.5,0,0.5)-(tpp cs:0,0,0.5)$), % x
            \p2=($(tpp cs:0,0,1)-(tpp cs:0,0,0)$), % z @ x=0
            \p3=($(tpp cs:1.5,0,1)-(tpp cs:1.5,0,0)$), % z @ x=1.5
            \n1={\y3/\y2},\n2={\x1/\y2} % n1 : decrease in z
            in
            \pgfextra{\pgfmathsetmacro{\RatioOne}{\n1}\xdef\RatioOne{\RatioOne}
            \pgfmathsetmacro{\RatioTwo}{\n2}\xdef\RatioTwo{\RatioTwo}
            \typeout{\RatioOne,\RatioTwo}}
            [decorate,decoration={text effects along path, text={Ducks, marmots and koala bears!},raise=-3pt,
            text effects/.cd,
                character count=\i, character total=\n,
                characters={text along path, 
            xscale=\RatioOne*1.15,
            yscale=1.15*((1.5-0.5*\RatioTwo)-(\i/\n)*(1-\RatioTwo))}}] 
            (tpp cs:0.2,0,0.5) -- (tpp cs:1.5,0,0.5);
            \draw (tpp cs:1,0,1) -- (tpp cs:1,0,0);
            %
            \begin{scope}[dotted,line width=0.2pt]
                \node[label=right:p,fill,circle,inner sep = 2pt] (p) at (vp-p){};

                \draw (tpp cs:0,0,1) -- (p.center);
                \draw (tpp cs:0,0,0) -- (p.center);
                \draw (tpp cs:0,0.5,1) -- (p.center);
                \draw (tpp cs:0,0.5,0) -- (p.center);

                \node[label=left:q,fill,circle,inner sep = 2pt] (q) at (vp-q){};

                \draw (tpp cs:0,0,1) -- (q.center);
                \draw (tpp cs:0,0,0) -- (q.center);
                \draw (tpp cs:1.5,0,1) -- (q.center);
                \draw (tpp cs:1.5,0,0) -- (q.center);
            \end{scope}
        \end{scope}
    \end{tikzpicture}
    }
\end{document}

enter image description here

10
  • Nice work but the text remains in a rectangle whereas the 3d effect should draw it in a trapeze.
    – AndréC
    Aug 22, 2018 at 16:27
  • @AndréC What one really would have to do is to use this answer or this answer, or do you have a better idea?
    – user121799
    Aug 22, 2018 at 16:42
  • 2
    Nice! This is a good start, maybe the OP can work with this.
    – Max
    Aug 22, 2018 at 17:18
  • 2
    @Raaja First marmot has to finish "Advanced hibernation techniques", I'm really looking forward to that one :)
    – Max
    Aug 23, 2018 at 10:55
  • 2
    @Max Writing this book is tough. Whenever I do field work, i.e. hibernate, the progress gets delayed very much. ;-)
    – user121799
    Aug 23, 2018 at 11:38
6
\documentclass{article}
\usepackage{pst-solides3d}

\begin{document}
\psset{viewpoint=50 20 30 rtp2xyz,Decran=50}
\begin{pspicture}(-4,-4)(4,5)
\psset{unit=0.5,solidmemory,lightsrc=viewpoint}
\psSolid[object=cube,a=8,action=draw**,name=A,linecolor=red]%
\psset{fontsize=80}
\psSolid[object=plan,action=none, definition=solidface,args=A 0,name=P0]
\psProjection[object=texte,linecolor=red,text=Side A,plan=P0]%
\psSolid[object=plan,action=none,definition=solidface,args=A 1,name=P1]
\psProjection[object=texte,linecolor=red,text=Side B,plan=P1]%
\psSolid[object=plan,action=none,definition=solidface,args=A 4,name=P4]
\psProjection[object=texte,linecolor=red,text=Side E,plan=P4]%
\axesIIID(4,4,4)(6,6,6)
\end{pspicture}
\end{document}

enter image description here

2
  • Is it possible to get the projected text in the LaTeX font? Jul 23, 2022 at 20:38
  • No, only PostScript fonts are available, default is Helvetica
    – user187802
    Jul 24, 2022 at 15:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .