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}
  • 1
    See tex.stackexchange.com/a/319222/121799 and the other answers to the corresponding question as well as tex.stackexchange.com/a/447120/121799. And the last of your references, tex.stackexchange.com/questions/447114/…, doesn't fake perspectives at all. Rather it allows you to set the vanishing point(s). – marmot Mar 5 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 5 at 14:39
  • 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, tex.stackexchange.com/questions/447114/…. Some letters that can be transformed can be found at tex.stackexchange.com/a/475168/121799 but they are not really good quality. (I used them to transform text nonlinearly on surfaces of spheres. – marmot Mar 5 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 5 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). – marmot Mar 5 at 14:50
9
+100

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}

  • 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 at 2: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 at 3: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 at 4:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.