[Tex/LaTex] Simulating paintbrush strokes in TikZ

tikz-pgf

I am wondering if there exists a way to simulate paintbrush strokes in TikZ when filling in a shape. So given the following:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\tikz{
\draw[fill=red](0,0)rectangle(10,10);
}
\end{tikzpicture}
\end{document}

Instead of a solid red shape I was hoping to make it look like the red part was painted on with a paintbrush. I'm not exactly sure how what that would look like but I'm guessing maybe some randomly wavy lines that are a little darker and some maybe that are a little lighter? And I guess one would want for the paintbrush to have a thickness so that you'd be able to see the difference between one stroke and the one next to it.

Looking at examples of actual paintbrush strokes online it looks like the light/dark parts vary a little on each line but that might be a complication not worth pursuing.

Having all the strokes go down would be fine but being able to indicate a directions would be cool.

And while I'm sure something like this is possible in various image editing programs, I need to do this in TeX/LaTeX as part of an automated file generating process.

Edit: I do not believe this is a duplicate of the chalkboard solution as that one appears to use a bunch of small dots whereas a paintbrush involves long wavy lines of varying shades of the root color. The results would look very different. It could be that the chalkboard question provides an idea for an approach but using it as-is would not be a solution to my question.

Update 1: I have done some experimentation with using TikZ decorations with wavy, random lines with rounded corners and it seems like this could be a way forward but I haven't made anything that looks close to convincing.

Update 2: As per below, here is a link to a picture of close-up of brush strokes. This is pretty exaggerated but gets the point across. Here is an attempt at using wavy random lines:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
\tikz[line width=.1mm]{
\draw[fill=red](0,0)rectangle(10,10);
\draw[line width = .5mm,decorate,decoration={random steps,segment length=12pt,amplitude=1pt},rounded corners=.1pt, color=red!50!brown] (1.5,0) -- (1.5,10);
\draw[line width = .5mm,decorate,decoration={random steps,segment length=12pt,amplitude=1pt},rounded corners=.1pt, color=red!50!brown] (1.65,0) -- (1.65,10);
\draw[line width = .5mm,decorate,decoration={random steps,segment length=12pt,amplitude=1pt},rounded corners=.1pt, color=red!50!brown] (1.8,0) -- (1.8,10);
\draw[line width = .5mm,decorate,decoration={random steps,segment length=12pt,amplitude=1pt},rounded corners=.1pt, color=red!50!brown] (1.95,0) -- (1.95,10);
}
\end{tikzpicture}
\end{document}

As you can see it looks terrible.

Red with brush strokes attempt

Update 3: Let me give a bit more detail about what I'm looking for. I am looking for something to fill large geometric shapes like squares, rectangles, and circles with sizes from half a page to almost a full page with one color. I have a program that generates music in many different styles (I'm a composer) but have decided to add artwork to it as well. So far I'm sticking with 20th century Modernist stuff as a lot of it seems simpler to do. I did a Mondrian one already (the squares and rectangles on thick crossing lines). And what inspired this question was the works of Kazimir Malevich, specifically his Black Square, Black Cross, Red Square and a few others of a similar style. My software randomly generates "paintings" that look similar but not exactly the same (for example, the black square varies in size but is still large, the red square uses different random dimensions for the quadrilateral, the black circle has different random dimensions and placed at random, etc). I had thought that since these are so simple that my users would appreciate having it be a bit more interesting to look at with the simulated brush strokes. Unfortunately I don't have any specific examples of paintings/painters in mind, just some vague notion that brush marks could be seen on paintings like those if you look closely enough(though I have no idea if you can see the brush strokes in Malevich's paintings). But then making it too subtle might get lost on the user when looking at it on their computer or phone so being a bit exaggerated might be better? It also occurs to me that maybe the bumps of the canvas underneath might help with the illusion?

Best Answer

This is a quickly written proposal based on this answer, which makes use of this answer. I plan to improve it later. (I am really not sure if understand the efforts to close the question. The chalk board post is IMHO related, but this question is IMHO not a duplicate thereof.)

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations,arrows.meta,bending}
\begin{document}
\pgfdeclarearrow{
  name=ink,
  parameters= {\the\pgfarrowlength},  
  setup code={
   \pgfarrowssettipend{0pt}
   \pgfarrowssetlineend{-\pgfarrowlength}
   \pgfarrowlinewidth=\pgflinewidth
   \pgfarrowssavethe\pgfarrowlength
  },
  drawing code={
   \pgfpathmoveto{\pgfpoint{-\pgfarrowlength}{0.5\pgflinewidth}}
   \pgfpathcurveto{\pgfpoint{-0.75\pgfarrowlength}{0.6\pgflinewidth}}{%
   \pgfpoint{-0.01\pgfarrowlength}{0.6\pgflinewidth}}{%
   \pgfpoint{0pt}{0pt}}
   \pgfpathcurveto{\pgfpoint{-0.01\pgfarrowlength}{-0.5\pgflinewidth}}{%
   \pgfpoint{-0.2\pgfarrowlength}{-(1+0.3*rnd)*\pgflinewidth}}{%
   \pgfpoint{-0.3\pgfarrowlength}{-0.8*(1+0.3*rnd)*\pgflinewidth}}
   \pgfpathcurveto{\pgfpoint{-0.4\pgfarrowlength}{-0.6*(1+0.3*rnd)*\pgflinewidth}}{%
   \pgfpoint{-0.6\pgfarrowlength}{-0.3*(1+0.3*rnd)*\pgflinewidth}}{%
   \pgfpoint{-1\pgfarrowlength}{-0.5\pgflinewidth}}
   \pgfusepathqfill
  },
  defaults = { length = 12pt }
}
\pgfkeys{/pgf/decoration/.cd,
         start color/.store in=\startcolor,
         start color=black,
         end color/.store in=\endcolor,
         end color=black,
         varying line width steps/.initial=100
}
\pgfdeclaredecoration{width and color change}{initial}{
 \state{initial}[width=0pt, next state=line, persistent precomputation={%
   \pgfmathparse{\pgfdecoratedpathlength/\pgfkeysvalueof{/pgf/decoration/varying line width steps}}%
   \let\increment=\pgfmathresult%
   \def\x{0}%
 }]{}
 \state{line}[width=\increment pt,   persistent postcomputation={%
   \pgfmathsetmacro{\x}{\x+\increment}
   },next state=line]{%
   \pgfmathparse{ifthenelse(\x<\pgfdecoratedpathlength-5mm,varyinglw(100*(\x/\pgfdecoratedpathlength)),
    varyinglw(100*((\pgfdecoratedpathlength-5mm)/\pgfdecoratedpathlength))*(\pgfdecoratedpathlength-\x)/14) )}
   \pgfmathparse{varyinglw(100*(\x/\pgfdecoratedpathlength))} %<-changed
   \pgfsetlinewidth{\pgfmathresult pt}%
   \pgfpathmoveto{\pgfpointorigin}%
   \pgfmathsetmacro{\steplength}{1.4*\increment}
   \pgfpathlineto{\pgfqpoint{\steplength pt}{0pt}}%
   \pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
   \pgfsetstrokecolor{\endcolor!\y!\startcolor}%
   \pgfusepath{stroke}%
 }
 \state{final}{%
   \pgfsetlinewidth{\pgflinewidth}%
   \pgfpathmoveto{\pgfpointorigin}%
   \pgfmathsetmacro{\y}{100*(\x/\pgfdecoratedpathlength)}
   \color{\endcolor!\y!\startcolor}%
   \pgfusepath{stroke}% 
 }
}


\begin{tikzpicture}[varying arrow/.style={-{ink[length=5mm,width=3.2mm]},color=\endcolor,
postaction={/utils/exec=\pgfsetarrows{-},decorate,decoration={width and color change}}
}]
\begin{scope}[declare function={varyinglw(\x)=12+5*rnd;}]
\foreach \X in {0,...,5}
{\draw[%/pgf/decoration/start color=red,/pgf/decoration/end color=red,
decorate,decoration={width and color change,start color=red,end color=red}] 
(0,-\X*0.7-0.1+0.2*rnd) to[bend left=10-20*rnd] ++ (3,0);}
\end{scope}

\end{tikzpicture}
\end{document} 

enter image description here

UPDATE: Something that goes a little bit into the direction of the picture under the link that you added in your update. Takes rather long to compile and is far from satisfying. I am posting this merely as a report on where I went, hoping that others may find some of this useful.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations,decorations.pathreplacing,calc,positioning}
\begin{document}

\pgfkeys{/brush pars/.cd,
lines/.initial=16,
color/.code={\colorlet{brushcolor}{#1}},
color=red,
distance/.initial=0.4pt
}
\tikzset{
    brush/.style={
        decorate,
        decoration={
            show path construction,
            lineto code={
                \foreach\Xbrush in{1,...,\pgfkeysvalueof{/brush pars/lines}}{
                 \pgfmathrandomitem{\c}{color}
                 \pgfmathtruncatemacro{\mix}{100-24*rnd}
                 \draw[color=brushcolor!\mix!\c,
                 shorten >={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}},
                 shorten <={(3-4*rnd)*1pt
                 -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}}]
                 let \p1=($(\tikzinputsegmentlast)-(\tikzinputsegmentfirst)$),
                 \n1={90+atan2(\y1,\x1)} in
                 ($(\tikzinputsegmentfirst)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                 --
                ($(\tikzinputsegmentlast)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$);
                }
            },
            curveto code={
                \foreach\Xbrush in{1,...,\pgfkeysvalueof{/brush pars/lines}}{
                 \pgfmathrandomitem{\c}{color}
                 \pgfmathtruncatemacro{\mix}{100-24*rnd}
                 \draw[color=brushcolor!\mix!\c,shorten >={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}},
                 shorten <={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}}]
                 let \p1=($(\tikzinputsegmentsupporta)-(\tikzinputsegmentfirst)$),
                 \p2=($(\tikzinputsegmentsupportb)-(\tikzinputsegmentsupporta)$),
                 \p3=($(\tikzinputsegmentlast)-(\tikzinputsegmentsupportb)$),
                 \n1={90+atan2(\y1,\x1)}, \n2={90+atan2(\y2,\x2)}, 
                 \n3={90+atan2(\y3,\x3)} in
                 ($(\tikzinputsegmentfirst)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                 .. controls ($(\tikzinputsegmentsupporta)+(\n2:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                  and ($(\tikzinputsegmentsupportb)+(\n3:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$) ..
                ($(\tikzinputsegmentlast)+(\n3:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$);
                }
            },
        }
    }
}
\tikzset{pics/.cd,
  A/.style={code={\draw[brush] 
  (0,-0.55) -- (0.3,0.4) -- (0.6,-0.55);
  \draw[brush](0.1,1/3-0.45) --
  (0.5,1/3-0.45);
  \path (0.7,0);}},
  B/.style={code={\draw[brush] (0,-0.45) -- (0,0.45)
  to[out=0,in=0,looseness=2.5]  (0,0)  to[out=0,in=0,looseness=3] cycle;}},
  C/.style={code={\draw[brush]
   (0,0) to[out=90,in=110,looseness=2]  (0.5,0.25);
   \draw[brush](0,0) to[out=-90,in=-110,looseness=2]  (0.5,-0.25);
   \path (0.7,0);}},
  D/.style={code={\draw[brush] (0,-0.45) -- (0,0.45) 
  to[out=0,in=0,looseness=2.25]   cycle;
  \path (0.7,0);}},
  E/.style={code={\draw[brush] 
  (0.5,-0.45) --(0,-0.45) -- (0,0.45)  -- (0.5,0.45);
  \draw[brush] (0,0) -- (0.5,0);
  \path (0.7,0);}},
  F/.style={code={\draw[brush] 
  (0,-0.45) -- (0,0.45)  -- (0.5,0.45);
  \draw[brush] (0,0) -- (0.5,0);
  \path (0.7,0);}},
  G/.style={code={\draw[brush]
   (0,0) to[out=90,in=110,looseness=2]  (0.5,0.25);
   \draw[brush] (0,0) to[out=-90,in=-110,looseness=2]  
   (0.5,-0.25);
   \draw[brush] (0.54,-0.25) to (0.3,-0.25);
   \path (0.7,0);}},
  H/.style={code={\draw[brush] 
  (0,-0.5) -- (0,0.5);  
  \draw[brush] (0.5,-0.5) -- (0.5,0.5);
  \draw[brush] (0,0) -- (0.5,0);
  \path (0.7,0);}},
  I/.style={code={\draw[brush] (0,-0.45) -- (0,0.45);
  \path (0.25,0);}},
  J/.style={code={\draw[brush] (0.2,0.45) -- (0.2,-0.35) to[out=-90,in=0]
  (0.1,-0.45) to[out=180,in=-90] (0,-0.35);
  \path (0.45,0);}},
  K/.style={code={\draw[brush] 
  (0,-0.45) -- (0,0.45); 
  \draw[brush] (0.4,0.45) -- (0.02,0) --  (0.4,-0.45);
  \path (0.6,0);}},
  L/.style={code={\draw[brush] 
  (0,0.5) -- (0,-0.45) -- (0.4,-0.45);
  \path (0.6,0);}},
  M/.style={code={\draw[brush] (0,-0.45) -- (0,0.45) -- 
  (0.3,0.25) -- (0.6,0.45) -- (0.6,-0.45);
  \path (0.8,0);}},
  N/.style={code={\draw[brush] (0,-0.45) -- (0,0.45) -- (0.6,-0.4) --
  (0.6,0.45);
  \path (0.8,0);}},
  O/.style={code={\draw[brush] (0.3,0) circle(0.3 and 0.48);
  \path (0.8,0);}},
  P/.style={code={\draw[brush] (0,-0.45) -- (0,0.45) 
  to[out=0,in=0,looseness=2.5]  (0,0);
  \path (0.6,0);}},
  Q/.style={code={\draw[brush] 
  (0.3,0) circle(0.3 and 0.48);
  \draw[brush](0.35,-0.25) -- (0.6,-0.45);
  \path (0.8,0);}},
  R/.style={code={\draw[brush] 
  (0,-0.45) -- (0,0.45) 
  to[out=0,in=0,looseness=2.5]  (0.05,0) -- (0.4,-0.45);
  \path (0.6,0);}},
  S/.style={code={\draw[brush] (0.5,0.4)  
  to[out=160,in=165,looseness=2]  (0.3,0)  
  to[out=-15,in=-20,looseness=2] (0.1,-0.4);
  \path (0.65,0);}},
  T/.style={code={\draw[brush] (0.35,-0.45) -- (0.35,0.45) (0,0.45) -- (0.7,0.45);
  \path (0.85,0);}},
  U/.style={code={\draw[brush] (0,0.5) -- (0,0) to[out=-90,in=-90,looseness=2.5]
  (0.6,0) -- (0.6,0.5);
  \path (0.8,0);}},
  V/.style={code={\draw[brush] (0,0.5) -- (0.3,-0.4) -- (0.6,0.5);
  \path (0.8,0);}},
  W/.style={code={\draw[brush] (0,0.45) -- (0.3,-0.4) -- (0.45,-0.1)
  -- (0.6,-0.4) -- (0.9,0.45);
  \path (1.1,0);}},
  X/.style={code={\draw[brush] 
  (0,0.45) -- (0.6,-0.45);
   \draw[brush] (0.6,0.45)
  -- (0,-0.45);
  \path (0.8,0);}},
  Y/.style={code={\draw[brush] 
  (0,0.45) -- (0.3,0);  
  \draw[brush] (0.6,0.45)
  -- (0,-0.45);
  \path (0.8,0);}},
  Z/.style={code={\draw[brush] (0,0.45) --(0.6,0.45) -- (0,-0.45)  
  -- (0.6,-0.45);
  \path (0.8,0);}},
  space/.style={code={\path (0,0) (0.2,0);}},
}
\pgfmathdeclarerandomlist{color}{{black}{white}}
\begin{tikzpicture}
 \pic[local bounding box=box1,scale=2] at (0,0) {A};
 \foreach \X [count=\Y,evaluate=\Y as \Z using {int(\Y+1)}] in {B,...,Z}
  {\edef\temp{\noexpand\pic[right=0mm of box\Y,local bounding box=box\Z,scale=2]
  {\X};}
  \temp}
\end{tikzpicture}
\end{document}

enter image description here

enter image description here

Time needed to compile the full alphabet on my machine:

real    0m11.438s
user    0m10.758s
sys 0m0.622s

The letters are taken from this answer and really very quickly written. (They were meant to go into the Christmas extravaganza but didn't make it there for good reasons.)

And within less than 4 minutes (on my machine) you get

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations,decorations.pathreplacing,calc,positioning}
\pgfkeys{/brush pars/.cd,
lines/.initial=16,
color/.code={\colorlet{brushcolor}{#1}},
color=red,
distance/.initial=0.4pt
}
\tikzset{
    brush/.style={
        decorate,
        decoration={
            show path construction,
            lineto code={
                \foreach\Xbrush in{1,...,\pgfkeysvalueof{/brush pars/lines}}{
                 \pgfmathrandomitem{\c}{color}
                 \pgfmathtruncatemacro{\mix}{100-24*rnd}
                 \draw[color=brushcolor!\mix!\c,
                 shorten >={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}},
                 shorten <={(3-4*rnd)*1pt
                 -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}}]
                 let \p1=($(\tikzinputsegmentlast)-(\tikzinputsegmentfirst)$),
                 \n1={90+atan2(\y1,\x1)} in
                 ($(\tikzinputsegmentfirst)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                 --
                ($(\tikzinputsegmentlast)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$);
                }
            },
            curveto code={
                \foreach\Xbrush in{1,...,\pgfkeysvalueof{/brush pars/lines}}{
                 \pgfmathrandomitem{\c}{color}
                 \pgfmathtruncatemacro{\mix}{100-24*rnd}
                 \draw[color=brushcolor!\mix!\c,shorten >={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}},
                 shorten <={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}}]
                 let \p1=($(\tikzinputsegmentsupporta)-(\tikzinputsegmentfirst)$),
                 \p2=($(\tikzinputsegmentsupportb)-(\tikzinputsegmentsupporta)$),
                 \p3=($(\tikzinputsegmentlast)-(\tikzinputsegmentsupportb)$),
                 \n1={90+atan2(\y1,\x1)}, \n2={90+atan2(\y2,\x2)}, 
                 \n3={90+atan2(\y3,\x3)} in
                 ($(\tikzinputsegmentfirst)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                 .. controls ($(\tikzinputsegmentsupporta)+(\n2:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                  and ($(\tikzinputsegmentsupportb)+(\n3:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$) ..
                ($(\tikzinputsegmentlast)+(\n3:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$);
                }
            },
        }
    }
}
\pgfmathdeclarerandomlist{color}{{black}{white}}
\begin{document}
\begin{tikzpicture}
\draw[clip,postaction={fill=red}] (0,0) rectangle (10,10);
\foreach \X in {1,...,1000}
{\draw[brush] (-0.5+11*rnd,-0.5+11*rnd) to[bend left={30-60*rnd}]
++ (360*rnd:1+2*rnd);}

\end{tikzpicture}
\end{document}

enter image description here

And for more aligned strokes you may try

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{decorations,decorations.pathreplacing,calc,positioning}
\pgfkeys{/brush pars/.cd,
lines/.initial=16,
color/.code={\colorlet{brushcolor}{#1}},
color=red,
distance/.initial=0.4pt
}
\tikzset{
    brush/.style={
        decorate,
        decoration={
            show path construction,
            lineto code={
                \foreach\Xbrush in{1,...,\pgfkeysvalueof{/brush pars/lines}}{
                 \pgfmathrandomitem{\c}{color}
                 \pgfmathtruncatemacro{\mix}{100-24*rnd}
                 \draw[color=brushcolor!\mix!\c,
                 shorten >={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}},
                 shorten <={(3-4*rnd)*1pt
                 -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}}]
                 let \p1=($(\tikzinputsegmentlast)-(\tikzinputsegmentfirst)$),
                 \n1={90+atan2(\y1,\x1)} in
                 ($(\tikzinputsegmentfirst)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                 --
                ($(\tikzinputsegmentlast)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$);
                }
            },
            curveto code={
                \foreach\Xbrush in{1,...,\pgfkeysvalueof{/brush pars/lines}}{
                 \pgfmathrandomitem{\c}{color}
                 \pgfmathtruncatemacro{\mix}{100-24*rnd}
                 \draw[color=brushcolor!\mix!\c,shorten >={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}},
                 shorten <={(3-4*rnd)*1pt
                    -0.5*\pgfkeysvalueof{/brush pars/lines}*\pgfkeysvalueof{/brush pars/distance}}]
                 let \p1=($(\tikzinputsegmentsupporta)-(\tikzinputsegmentfirst)$),
                 \p2=($(\tikzinputsegmentsupportb)-(\tikzinputsegmentsupporta)$),
                 \p3=($(\tikzinputsegmentlast)-(\tikzinputsegmentsupportb)$),
                 \n1={90+atan2(\y1,\x1)}, \n2={90+atan2(\y2,\x2)}, 
                 \n3={90+atan2(\y3,\x3)} in
                 ($(\tikzinputsegmentfirst)+(\n1:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                 .. controls ($(\tikzinputsegmentsupporta)+(\n2:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$)
                  and ($(\tikzinputsegmentsupportb)+(\n3:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$) ..
                ($(\tikzinputsegmentlast)+(\n3:{((1.02-0.04*rnd)*\Xbrush-\pgfkeysvalueof{/brush pars/lines}/2)*\pgfkeysvalueof{/brush pars/distance}})$);
                }
            },
        }
    }
}
\pgfmathdeclarerandomlist{color}{{black}{white}}
\begin{document}
\begin{tikzpicture}[declare function={VF(\x,\y)=10*\x-4*\y+2*\x*\y;}]
\draw[clip,postaction={fill=red}] (0,0) rectangle (10,10);
\foreach \X in {1,...,1000}
{\pgfmathsetmacro{\myx}{-0.5+11*rnd}
\pgfmathsetmacro{\myy}{-0.5+11*rnd}
\draw[brush] (\myx,\myy) to[bend left={30-60*rnd}]
++ ({VF(\myx,\myy)+10-20*rnd}:1+2*rnd);}
\end{tikzpicture}
\end{document}

enter image description here