5

I'm drawing pipes (like the Pipeline game), and I want them to be shaded to give the effect that the pipes are cylindrical.

A bit like the pipes below: the outer edges are black, the middle is white (I tried bottom color=black,middle color=white,bottom color=black but the pipes just showed up as black. Perhaps because I'm getting my pipe width from the line width instead of as a fill? I'm amenable to changing the way the pipes are defined, so long as I can still draw them easily, with the details abstracted away in the pipe style).

enter image description here
(image credit: "Plumber Game")

There are a number of questions (example) that deal with applying a gradient along a path (as in say green on one end of the path, red on the other); but I want the gradient to be perpendicular to that.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\tikzset{
  pipe/.style = {
    draw,
    rounded corners,
    line width=3mm
  }
}
\begin{tikzpicture}
  % a pipe.
  \draw [pipe] (0, 0) -- (0, 3) -- (1, 3);
\end{tikzpicture}
\end{document}

Update

@Symbol-1's suggestion of pgf-blur leads me to the following: I define the blur colour to be white (the centre colour of the pipe). Since the blur fades to transparent, I draw the solid colour of the pipe underneath, first, with preaction.

However in order for the blur to render appropriately I need to draw my right-angle pipe as two separate line segments, which then don't join smoothly. I can try separately drawing the underlying pipe (smoothly) and then the blur (nonsmoothly) but then you can see the blur doesn't quite meet in the corners (plus it is a small pain to redefine the pipe and shadow twice for each pipe, but I can live with this)::

enter image description here

\documentclass{standalone}
\usepackage{tikz}
  \usetikzlibrary{shadows.blur}
\makeatletter
\tikzset{
    /tikz/render blur shadow/.code={
        \pgfbs@savebb
        \pgfsyssoftpath@getcurrentpath{\pgfbs@input@path}%
        \pgfbs@compute@shadow@bbox
        \pgfbs@process@rounding{\pgfbs@input@path}{\pgfbs@fadepath}%
        \pgfbs@apply@canvas@transform
        \colorlet{pstb@shadow@color}{white!\pgfbs@opacity!black}%
        \pgfdeclarefading{shadowfading}{\pgfbs@paint@fading}%
        \pgfsetfillcolor{\blurcolor}%
        \pgfsetfading{shadowfading}%
            {\pgftransformshift{\pgfpoint{\pgfbs@midx}{\pgfbs@midy}}}%
        \pgfbs@usebbox{fill}%
        \pgfbs@restorebb
    }
}
\tikzset{
  basepipe/.style = {
    rounded corners,
    line width=3mm
  },
  pipe/.style = {
    basepipe,
    % shadow stuff
    blur shadow, shadow xshift=0, shadow yshift=0,
    shadow blur radius=1.5mm, shadow opacity=100, shadow blur steps=100,
  }
}
\def\blurcolor{white}
\begin{document}
\begin{tikzpicture}
  % a pipe.
  \path [preaction={draw,basepipe}][pipe] (0, 0) -- (0, 3) -- cycle (0,3) -- (1, 3);
  % another pipe, without cycle
  \begin{scope}[xshift=1.5cm]
  \path [preaction={draw,basepipe}][pipe] (0, 0) -- (0, 3) -- (1, 3);
  \end{scope}
  % another pipe
  \begin{scope}[xshift=3cm]
  \draw [basepipe] (0,0) -- (0,3) -- (1,3);
  \path [pipe] (0, 0) -- (0, 3) -- cycle (0,3) -- (1, 3);
  \end{scope}
\end{tikzpicture}
\end{document}

Can anyone help me get the last step?

8
  • 1
    Gradients are not path dependent. You see the gradient through the fill area instead. Hence you have to define gradients for each piece. So it needs a bit more work than you might have anticipated.
    – percusse
    Dec 8, 2016 at 0:22
  • Hmm. Can I somehow hack it? Say I define a little rectangle of line width that is the gradient I want, and then use it as a pattern to repeat along the line? (I'm not familiar with this sort of thing) Dec 8, 2016 at 0:35
  • Patterns are like fills - not for paths. Do you have to draw many of these? How patient would you be while letting them draw? The existing hacks for using gradients along 'paths' fake it and this is sloooooooooooow. You are better off outlining the pipes and filling them.
    – cfr
    Dec 8, 2016 at 0:45
  • Maybe TikZ isn't a good choice for this?
    – cfr
    Dec 8, 2016 at 0:48
  • 3

1 Answer 1

5

The reason why the blur doesn't get the rounded Corners is because, as stated in pfg-blur manual, it only works for closed paths, so if you want the joins to be smooth, you have to close the path with a cycle where the joins are. If you read carefully @Symbol1's answer you'll see that the drawing goes like

(a) -- (b) -- cycle (b) -- (c) -- cycle (c) ...

And wherever there's a cycle, there's an equivalent to a blurred rounded line cap, that's the catch. You're also using rounded corners when you actually want line join=round (the blurred path won't follow the rounded corners). So, I created a few styles to help with the drawing: pipe=<dim> (default is 15mm) which is for the pipe's background, pipe shading=<dim> (default is also 15mm) which sets the blurred foreground and pipe color=<color> sets the blur color. Let's got the MWE then.

I've set two examples, one with line cap=butt and one with line cap=round. There's only one trick to use the line cap=butt, your pipe has to have more than 2 segments, that is: \draw (0,0)--(0,3)--cycle (0,3)--(1,3); (which is the example in you MWE) won't work, instead you need to have an extra segment, even if it won't change the outcome, like this: \draw (0,0)--(0,1) (0,1)--(0,3)--cycle (0,3)--(1,3);.

MWE

\documentclass[tikz]{standalone}
\usetikzlibrary{shadows.blur}
\makeatletter
\tikzset{
    blur shadow color/.store in=\blurcolor,
    blur shadow color=black,
    render blur shadow/.code={
        \pgfbs@savebb
        \pgfsyssoftpath@getcurrentpath{\pgfbs@input@path}%
        \pgfbs@compute@shadow@bbox
        \pgfbs@process@rounding{\pgfbs@input@path}{\pgfbs@fadepath}%
        \pgfbs@apply@canvas@transform
        \colorlet{pstb@shadow@color}{white!\pgfbs@opacity!black}%
        \pgfdeclarefading{shadowfading}{\pgfbs@paint@fading}%
        \pgfsetfillcolor{\blurcolor}%
        \pgfsetfading{shadowfading}%
            {\pgftransformshift{\pgfpoint{\pgfbs@midx}{\pgfbs@midy}}}%
        \pgfbs@usebbox{fill}%
        \pgfbs@restorebb
    },
    pipe color/.style={blur shadow color=#1},
    pipe/.style={line cap=round, line join=round, line width=#1},pipe/.default={15mm},
    pipe shading/.style={blur shadow,shadow xshift=0,shadow yshift=0,shadow opacity=100,shadow blur steps=100, shadow blur radius=#1/2},pipe shading/.default={15mm}
}
\begin{document}
    \begin{tikzpicture}
        \draw[pipe, line cap=butt] (1,0)--(1,6)--(6,6)--(7,4)--(9,4);
        \path[pipe color=white, pipe shading]
        (1,0)--(1,6)
        (1,6)--(6,6)--cycle
        (6,6)--(7,4)--cycle
        (7,4)--(9,4);
        \begin{scope}[yshift=-7.5cm]
        \draw[pipe=10mm] (1,0)--(1,6)--(6,6)--(7,4)--(9,4);
        \path[pipe color=gray, pipe shading=10mm]
        (1,0)--(1,6)--cycle
        (1,6)--(6,6)--cycle
        (6,6)--(7,4)--cycle
        (7,4)--(9,4)--cycle;
        \end{scope}
    \end{tikzpicture}
\end{document}

Note how the drawing with line cap=butt has the blurred path start and end segments without cycle, because the use of cycle introduces the equivalent of a rounded blurred line cap, which is also responsible for the joining visual effect.

enter image description here

4
  • Oh my, this black magic is genius! TikZ has soo much to learn that my general philosophy is just to mash together a frankenstein-picture from bits of tikz-manual and stackexchange examples, and I often get in far beyond my understanding (which is very rudimentary). Thanks so much! My pipe dream is, in fact, not! ;) Dec 8, 2016 at 13:25
  • Oh no, that's absolutely pure white magic. We have some dark wizards here, like Mark Wibrow and Loop Space, but I'm not amongst them, not by far. And you're welcome, I've made an attempt to automate things using decorations but, unfortunately, there seems to be some sort of bug with pgf-blur (or just my lack of understanding it, which is most likely). Dec 8, 2016 at 13:43
  • I want my rounded corners to be of a specific radius, which means I'll manually draw them using arc. However, I can't cycle an arc because it closes it. Do you know if there is a way to get this shading to follow an arc (a quarter-circle "corner"), or is that different enough to merit a new question? Dec 9, 2016 at 0:05
  • Nevermind re rounded corners: Ended up drawing them with clipped circles that had been shaded radially... modification of tex.stackexchange.com/questions/82425/… Dec 9, 2016 at 3:20

You must log in to answer this question.

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