8

I want to display text in TikZ that is perspectively distorted, like so:

enter image description here
(checkered pattern added for illustration only)

There are many similar solutions on TeX.SE (here, here, or here), but all of the ones I found are faking perspective merely by using slant and tilt.

The solution should transform the text to:

  1. have a horizontal vanishing point to which all usually horizontally parallel lines are noticeably converging
  2. have a vertical vanishing point to which all usually vertically parallel lines are converging or keep them strictly parallel (like in my example above)

  • Bonus if your solution allows the user to explicitly define the vanishing point.

You may use this as a starting point:

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\node[draw,align=left] at (0,0) {some text\\maybe with line breaks};
\end{tikzpicture}
\end{document}
sheß
  • 3,622
  • 1
    See https://tex.stackexchange.com/a/319222/121799 and the other answers to the corresponding question as well as https://tex.stackexchange.com/a/447120/121799. And the last of your references, https://tex.stackexchange.com/questions/447114/aligning-a-text-in-3d-diagram/447201#447201, doesn't fake perspectives at all. Rather it allows you to set the vanishing point(s). –  Mar 05 '19 at 14:32
  • So in short: With text, we can only get slant/tilt, with images more is possible but only at significant costs. – sheß Mar 05 '19 at 14:39
  • https://tex.stackexchange.com/a/319222/121799 does it to texts, doesn't it? A very crazy thing you can do is to draw the letters with TikZ and then they can get transformed with Max great routines, https://tex.stackexchange.com/questions/447114/aligning-a-text-in-3d-diagram/447201#447201. Some letters that can be transformed can be found at https://tex.stackexchange.com/a/475168/121799 but they are not really good quality. (I used them to transform text nonlinearly on surfaces of spheres. –  Mar 05 '19 at 14:40
  • It's basically treating the text as as image and slicing it up, no? so there is nothing copy-and-pasteable/searchable afterwards. So it seems I have to give up on that idea. – sheß Mar 05 '19 at 14:45
  • 2
    I would use asymptote for that. The problem is that you need, AFAIK, the outlines of glyphs to be able to transform them. Asymptote knows how to get them, TikZ doesn't. I do not know how asymptote does it.Here is some way to get something of that sort with TikZ. And yes, by itself the text won't be searchable (but I guess you could make it searchable). –  Mar 05 '19 at 14:50
  • Great, thanks, I'll look at it – sheß Mar 05 '19 at 14:51
  • @sheß Any news? I am still waiting an answer! A very good question. –  Mar 11 '19 at 15:37
  • No news, I more or less accepted @marmot 's comment that this is beyond TikZ capabilities :( – sheß Mar 12 '19 at 08:32
  • @JouleV These are, in a way, two questions: 1. How can I get the outlines of glyphs in TikZ. 2. How can I do the perspective projection. 2. is a solved problem, and there will be a library soon. So the main task is 1. This has been asked here. What I don't know is whether or not there is a more automatic solution that does not require external programs. If you are willing to use external programs, then you may just use asymptote. –  Mar 12 '19 at 16:59

1 Answers1

11

This approach divides the word into small triangles and apply slant and tilt to each triangle. This works for projections as well as general nonlinear transformations.

It has appeared before


\documentclass[border=9,tikz]{standalone}
\begin{document}
\fontsize{188pt}{0}\bfseries

\pgfmathdeclarefunction{fxx}{2}{\pgfmathparse{fx(#1+1,#2)-fx(#1,#2)}}
\pgfmathdeclarefunction{fxy}{2}{\pgfmathparse{fy(#1+1,#2)-fy(#1,#2)}}
\pgfmathdeclarefunction{fyx}{2}{\pgfmathparse{fx(#1,#2+1)-fx(#1,#2)}}
\pgfmathdeclarefunction{fyy}{2}{\pgfmathparse{fy(#1,#2+1)-fy(#1,#2)}}

\begin{tikzpicture}
    \pgfmathdeclarefunction{gx}{2}{\pgfmathparse{3*#1-20}}
    \pgfmathdeclarefunction{gy}{2}{\pgfmathparse{3.1622*#2}}
    \pgfmathdeclarefunction{gz}{2}{\pgfmathparse{#1+10}}
    \pgfmathdeclarefunction{fx}{2}{\pgfmathparse{gx(#1,#2)*6/gz(#1,#2)}}
    \pgfmathdeclarefunction{fy}{2}{\pgfmathparse{gy(#1,#2)*6/gz(#1,#2)}}
    \clip(-15,-9)rectangle(15,10);
    \foreach\i in{0,...,40}{
        \foreach\j in{-3,...,3}{
            \pgfmathsetmacro\aa{fxx(\i,\j)}
            \pgfmathsetmacro\ab{fxy(\i,\j)}
            \pgfmathsetmacro\ba{fyx(\i,\j)}
            \pgfmathsetmacro\bb{fyy(\i,\j)}
            \pgfmathsetmacro\xx{fx (\i,\j)}
            \pgfmathsetmacro\yy{fy (\i,\j)}
            \pgflowlevelobj{
                \pgfsettransformentries{\aa}{\ab}{\ba}{\bb}{\xx cm}{\yy cm}
            }{
                \clip(1,0)--(0,0)--(0,1)--cycle;
                \draw(1,0)--(0,0)--(0,1)--cycle;
                \tikzset{shift={(-\i,-\j)}}
                \path(20,.5)node{WORDART};
            }
            \pgfmathsetmacro\aa{fxx(\i  ,\j+1)}
            \pgfmathsetmacro\ab{fxy(\i  ,\j+1)}
            \pgfmathsetmacro\ba{fyx(\i+1,\j  )}
            \pgfmathsetmacro\bb{fyy(\i+1,\j  )}
            \pgfmathsetmacro\xx{fx (\i+1,\j+1)}
            \pgfmathsetmacro\yy{fy (\i+1,\j+1)}
            \pgflowlevelobj{
                \pgfsettransformentries{\aa}{\ab}{\ba}{\bb}{\xx cm}{\yy cm}
            }{
                \clip(0,0)--(-1,0)--(0,-1)--cycle;
                \draw(0,0)--(-1,0)--(0,-1)--cycle;
                \tikzset{shift={(-\i-1,-\j-1)}}
                \path(20,.5)node{WORDART};
            }
        }
    }
\end{tikzpicture}

\end{document}

Symbol 1
  • 36,855
  • 1
    @marmot With \usepackage{lmodern} in the preamble, I obtain the same output as the screenshot with pdflatex, and the warning Font shape \OT1/cmr/bx/n' in size <188> not available (Font) size <24.88> substituted on input line 3.` is gone (with the warning, the text in the output is tiny.) Tested with this configuration : This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018). – quark67 Mar 13 '19 at 02:27
  • 1
    @marmot Sorry I did not notice that I set the compiler to XeLaTeX. But yeah as quark67 said this is a font issue. The tikz part is portable. – Symbol 1 Mar 13 '19 at 03:34
  • @JouleV Do you use pdflatex ? If yes, I obtain a very same output as you, but with a "gray" grid like Symbol1, it's a antialiasing effect in my pdf viewer (perhap's your PDF viewer is different with antialiasing?). But as I wrote earlier, if you add \usepackage{lmodern} in the preamble, you probably give the same output as Symbol1. – quark67 Mar 13 '19 at 04:33