# Automatically generate graphics which shows light diffusion on a rough surface

I just want to make an image like this (using tikz or pstricks) of light reflexion and diffusion:

What I am interested in is, how this can be done (semi)-automatically via tikz or pstricks:

• specify number (and spacing) of equi-distant incoming light rays and their angle
• draw the surface with a parameter r which controls the "roughness" r=0 is like the picture above, for larger r's the sourface becomes more and more rough (like the graph of a piecewiese linear continous function with more and more parts if r becomse larger)
• draw the reflected part such that the law reflexion (equal angles) is satisfied "locally"

Here's an attempt in Metapost. Using the direction x of y macro to find the required angle of reflection.

Here's what you get with r=0:

And with r=0.33:

prologues := 3;
outputtemplate := "%j%c.eps";

beginfig(1);

path base, ray[]; u = 5mm;

r=0.33;

base = (-6u,0) for x=-5.8u step 0.2u until 5.8u: -- (x,r*normaldeviate) endfor -- (6u,0);
draw base
-- point infinity of base shifted (0,-u)
-- point 0        of base shifted (0,-u) -- cycle
withcolor .67 red;

theta = -45;

for i=-2 upto 2:
ray[i] = (left--right) scaled 6u rotated theta shifted (i*u,0);
b := ypart(ray[i] intersectiontimes base);
drawarrow point 0 of ray[i]
-- point b of base
-- point 0 of ray[i] reflectedabout(point b of base, direction b of base
shifted point b of base
endfor

label.urt("r=" & decimal r, point 0 of base);

endfig;
end.


If you want to do something fancier with the reflected ray, then you can save it as a path instead of just drawing it. This lets you draw parts of it in different colours, or draw arrows part of the way along it. Like this:

To get this effect, you can change the inner loop like this:

for i=-2 upto 2:
ray[i] = (left--right) scaled 6u rotated theta shifted (i*u,0);
b := ypart(ray[i] intersectiontimes base);
ray[i] := point 0 of ray[i]
-- point b of base
-- point 0 of ray[i] reflectedabout(point b of base, direction b of base
shifted point b of base
drawarrow subpath(0,0.3) of ray[i];
drawarrow subpath(0.3,1.7) of ray[i];
draw      subpath(1.7,infinity) of ray[i];
endfor


So instead of just drawing the reflected ray, this time I have stored it back in ray[i] (notice that I've used the assignment operator := to overwrite the previous value of the variable), and then drawn it afterwards in three segments to get the arrow heads in nice places.

Note: Since this solution depends on Metapost's normaldeviate function to generate random numbers, I recommend that you stick to the default number system. There is currently (MP version 1.902) a horrible bug in the way that the new number systems double and decimal implement the constants required for normaldeviate. As a result you will get rather wild results if you use either of these new number systems. I have raised an issue for this on the MP bug tracker.

• Amazing! Thank you very much. Just a little detail: How can it, such that the arrow tips are in the middle of the incoming and outcoming lines (and not at the end of the outcoming ones)? Sep 28, 2014 at 18:22

Our TikZers getting lazy I guess. This can't get away without a TikZ answer :P Same idea but using decorations (over and over again).

\documentclass[tikz]{standalone}
\usetikzlibrary{decorations.pathmorphing,decorations.markings,calc}
\begin{document}
\begin{tikzpicture}
postaction=decorate,
decoration={markings,
mark= between positions 1cm and 3cm step 5mm with {% Places five of them
\node[transform shape,inner sep=1pt]
(mark-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) {};
}
}
]{
decorate[decoration={random steps,segment length=1.5mm,amplitude=1pt}]%Roughness is amplitude
{
(0,0) -- ++(4,0)
}
} -- ++(0,-5mm) -- ++(-4cm,0) -- cycle;
\foreach \x in {1,2,...,5}{
\draw[postaction=decorate,
decoration={markings,
mark=between positions 0.25 and 0.75 step 0.5 with{\arrow{latex}}
}]
(mark-\x.center)+(135:2cm)  --(mark-\x.center)
--($(mark-\x.north west)!2cm!45:(mark-\x.north east)$);
}
\end{tikzpicture}
\end{document}


I've just seen that there is still missing a PSTricks solution ;)

Using at least version 5.0 of the pst-optexp package allows to use arbitrary paths as refractive or reflective surfaces.

Here is how you can simulate a rough surface. Basically you must use \pssavepath (from pst-intersect) to save some path to be used later as reflective surface:

\documentclass[margin=5pt, pstricks]{standalone}
\usepackage{pst-optexp}
\makeatletter
\newOptexpTripole{roughsurface}
\def\roughsurface@nodes{%
\pssavepath[linestyle=none, arrows=-,ArrowInside=-]{\oenode@Path{A}}{%
\code{0 srand}% provides reproducable results
\moveto(!-3 Rand 0.5 sub 0.1 mul)
\multido{\r=-2.7+0.3}{20}{%
\lineto(!\r\space Rand 0.5 sub 0.1 mul)}%
}%
\newOptexpComp{%
{0 0} tx@IntersectDict /\PIT@name{\oenode@Path{A}} get 0 0 refl {PathIfc}
1 }%
}%
\def\roughsurface@comp{%
\pstracecurve{\oenode@Path{A}}
}%
\makeatother
\begin{document}
\begin{pspicture}(10,3)
\optplane[angle=90](1,3)
\roughsurface(0,3)(5,0)(10,3)