share
TeX - LaTeXHow to draw a shaded sphere?
[+52] [4] Jake
[2012-05-03 07:57:11]
[ tikz-pgf shading ]
[ https://tex.stackexchange.com/questions/54193/how-to-draw-a-shaded-sphere ]

Andrew Stacey pointed out [1] that the Rosetta Code entry "Draw a Sphere" [2] doesn't have a TikZ entry yet.

Is there a way to draw a "properly" shaded sphere using TikZ? The ball shading would seem an obvious choice, but it uses a circular highlight, which is not what it would look like in reality. So: is there a way to make a sphere that would resemble a white, matte (i.e. non-shiny) ball that is illuminated by a single white light source?

This would mainly require getting a non-circular, correctly oriented highlight, I believe. Both Yori's and Altermundus' answer already do a great job at using a "softer" highlight, which looks more believable, but Altermundus' highlight is still circular, and while Yoris' is elliptic, it's not oriented correctly, I think.

Compare a circle with the ball shading to the example made with Perl 6 [3]:

\documentclass{article}

\usepackage{tikz}

\begin{document}

\begin{minipage}{2.5cm}\centering
\scriptsize That's not a sphere.

\tikz{
    \fill [black] (-1,-1) rectangle (1,1);
    \shade [ball color=white] (0,0) circle [radius=1cm];
}
\end{minipage}%
%
\begin{minipage}{2.5cm}\centering
\scriptsize \emph{That's} a sphere.

\includegraphics[width=2cm]{Sphere-perl6.png}
\end{minipage}
\end{document}
I think that the better sphere is the first one. The second example seems to be a white mushroom. I prefer this one : commons.wikimedia.org/wiki/… or this one webangel.fr/fr/tutaux/sphere.html - Alain Matthes
I would agree with Altermundus, there is a problem with the second one, he saw a mushroom and I am seeing a knob! - yannisl
Does this mushroom-y knob require the 3d tag? - Werner
@Altermundus, @ YiannisLazarides: To me, the first one looks like what you'd see when you're sitting at the bottom of a well looking up, and the sun is not directly overhead. And if I'm not mistaken, the left one can't be correct, because the highlight can't be circular: Think of the extreme case when the light is coming directly from the side: The edge of the highlight would be a straight line. So for light coming at an angle, the edge of the highlight has to be something between a circle and a straight line (an ellipsoid, presumably). - Jake
(1) I think the contrast is too high in the second picture. You want a sphere realistic ? hyperrealist ? with a impressionism style ? a billiard ball with a soft light ? the moon ? an eclipse ? The question should be more specific ! but it will not be easy to master all the effects. - Alain Matthes
@Altermundus: Yeah, the contrast is too high, but the shape of the highlight is more accurate. I'll edit the question to make it more specific. - Jake
[+43] [2012-10-09 13:38:51] Simon Byrne

If the light source is a long way away, the intensity at each point is the dot product between the position vector and light source vector (in R3), thresholded at 0.

This uses the \pgfdeclarefunctionalshading command from percusse's answer. Of course, we're only given two elements of each vector, so we need to first compute the third.

For some reason, shadings for circles need to be 50bp by 50bp, otherwise this doesn't work.

\documentclass[border=5mm]{standalone}
\usepackage{tikz}

\pgfdeclarefunctionalshading{sphere}{\pgfpoint{-25bp}{-25bp}}{\pgfpoint{25bp}{25bp}}{}{
%% calculate unit coordinates
25 div exch
25 div exch
%% copy stack
2 copy 
%% compute -z^2 of the current position 
dup mul exch
dup mul add
1.0 sub
%% and the -z^2 of the light source 
0.3 dup mul
-0.5 dup mul add
1.0 sub
%% now their sqrt product
mul abs sqrt
%% and the sum product of the rest
exch 0.3 mul add
exch -0.5 mul add
%% max(dotprod,0)
dup abs add 2.0 div 
%% matte-ify
0.6 mul 0.4 add
%% currently there is just one number in the stack.
%% we need three corresponding to the RGB values
dup
0.4
}

\begin{document}
\begin{tikzpicture}
  \shade[shading=sphere] (0,0) circle [radius=5cm];
\end{tikzpicture}
\end{document}

sphere


(1) Nice! I've also tried something similar but for some reason they (including this one) don't work on Sumatra PDF or a few others than Acrobat. That's why I didn't touch the previous answer. Regarding the 50bp case, it seems working if I increase all 25s to 50s too. - percusse
ImageMagick didn't like it too much either. Mac preview handled it fine though. - Simon Byrne
It seems that circles just use the centre 50bp x 50bp rendering. So if you make the bounding box larger in all dimensions, it won't change. However if you also change the 25 div to 50 div you end up with a zoomed in version. - Simon Byrne
(1) I've also tried to find which calculation starts to make it problematic but apparently none of them are causing any problems. Maybe the problem is about numerical sensitivity. I have no idea why my answer doesn't cause any problems and yours is only available in AR. Same thing happened with the fireworks question too. In that case only Sumatra managed to show the proper output. - percusse
(2) This looks really nice. And when I tried it today, SumatraPDF could display it correctly (Windows 7 64bit, SumatraPDF version 2.2.1). I'd like to use this shading in some pictures of molecular systems I want to create with pgf but I don't know anything about postscript. Is there an easy way to get this shading working with different colors or would this require a modification of the whole postscript calculation? - Philipp
(4) You only need to modify the last few lines to change the colour: at the comment %% matte-ify there is 1 number (between 0 and 1) in the stack: you need 3 (being the RGB values). Try playing around with the lines below this point and see how you go (if you get stuck, you can always ask another question...) - Simon Byrne
1
[+28] [2012-05-03 13:23:02] yori [ACCEPTED]

I'm following the earlier post Is there a way to tune ball shading in TikZ ? [1], particularly Stefan Kottwitz's answer. He showed how to use \pgfdeclareradialshading to change the radial shading. Changing the parameters for the radial and adding some clipping, I can produce this:

Is that sphere enough? Perhaps with some more tweaking it is possible to get an even better result. The code to produce this is:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\makeatletter
\pgfdeclareradialshading[tikz@ball]{ball}{\pgfqpoint{-20bp}{20bp}}{%
 color(0bp)=(tikz@ball!0!white);
 color(17bp)=(tikz@ball!0!white);
 color(21bp)=(tikz@ball!70!black);
 color(25bp)=(black!70);
 color(30bp)=(black!70)}
\makeatother

\begin{tikzpicture}
    \fill [black] (-1,-1) rectangle (1,1);
    \begin{scope}
        \clip (0,0) circle (1);
        \shade [ball color=white] (-0.1,0) ellipse (1.2 and 1);
    \end{scope}
\end{tikzpicture}

\end{document}

Or, with a more ellipsoidal shading, one can get this:

The for this is:

\documentclass{article}

\usepackage{tikz}

\begin{document}

\makeatletter
\pgfdeclareradialshading[tikz@ball]{ball}{\pgfqpoint{0bp}{0bp}}{%
 color(0bp)=(tikz@ball!0!white);
 color(10bp)=(tikz@ball!0!white);
 color(15bp)=(tikz@ball!70!black);
 color(20bp)=(black!70);
 color(30bp)=(black!70)}
\makeatother

\begin{tikzpicture}

    \fill [black] (-1,-1) rectangle (1,1);

    \begin{scope}
        \clip (0,0) circle (1);
        \draw [fill=black!70] (0, 0) circle (1);
        \begin{scope}[transform canvas={rotate=45}]
        \shade [ball color=white] (0,0.5) ellipse (1.8 and 1.6);
        \end{scope}
    \end{scope}

\end{tikzpicture}

\end{document}

It's a matter of experimenting and fiddling around with the parameters to see what looks best according to you (judging from the discussion above, this seems quite subjective matter). Notice that you need to specify transform canvas={rotate=45} in the inner scope, not rotate=45 because the latter does not rotate the fill.

[1] https://tex.stackexchange.com/questions/1947/is-there-a-way-to-tune-ball-shading-in-tikz

That looks great! However, is there a way of getting the orientation of the shading right? At the moment, the ellipse is oriented horizontally, but I guess it would need to be at a 45 degree angle? - Jake
@Jake: see my edit. As said, it's a matter of fiddling around a little bit to find what looks best. I think the second one looks okayish, although not that much different from the first one. - yori
2
[+25] [2012-05-04 04:02:38] percusse

To grease up PS gears, I modified the functional shading given in the PGF manual. I am pretty sure that PSTricks and its foot soldiers are ridiculously better at these type of drawings but Acrobat and Sumatra render pretty impressively.

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\pgfdeclarefunctionalshading{eightball}{\pgfpointorigin}{\pgfpoint{100bp}{100bp}}{}{
% Compute distance difference (horizontally weighted twice). (50bp,50bp) is the center
65 sub dup mul exch               %Change the coordinate to move vertically
40 sub dup mul 0.5 mul add sqrt   %Change the coordinate to move horizontally
% In MATLAB notation : d=distance diff
% x=1.003^(-d^2)
dup mul neg 1.003 exch exp
% x is the only variable in the stack now but we need 3 values at the top of the stack
% so we duplicate these values putting new values in the stack.
dup % Duplicates with the current value and pushes the stack down (value of green)
dup % Duplicates with the current value and pushes the stack down (value of blue)
}

\begin{document}
\begin{tikzpicture}
\shade[shading=eightball] (0,0) circle (5cm);
\end{tikzpicture}
\end{document}

You can play around with the last dup commands by replacing with values in the interval [0.0,1.0] from black to white. For example being a colorblind, if I make these values 0.3,0.2 respectively, my brain just quits rendering with a painful error code.

enter image description here


(1) Ooooh! I didn't know you could use PS code for the shadings. Looks really impressive! - Jake
The list of the ps operations are given in the pgfmanual (shading part). You can use the basic operations but you can't program. It's the big difference between ps and PDF. Very fine result from percusse !! - Alain Matthes
@Jake Indeed, it's quite surprising. As Altermundus commented it's quite laborious to make it flexible and some things are just not possible. I've experimented with the <init code> for colors and there is hope colorwise, not much though. As a side note, for some reason if I do the ->PS->PDF route, the pixelation is too visible. The sampling rate gets too low I suppose. - percusse
I recently saw this in the PGF manual and so when thinking about this question wondered if this would a way to get a right solution - I'm pleased to see someone figure it out! Really nice. I think I'd add some "ambient light" so that it doesn't shade to black. - Andrew Stacey
@AndrewStacey Indeed I did some experiments and many options regarding the colors are possible. If I can concentrate enough to keep track of the stack entries and permutations, I will introduce a fadeout color. This is very much like Assembly language. - percusse
Oh my ghost, tikz can accept RPN notation! - kiss my armpit
@GarbageCollector See also tex.stackexchange.com/questions/60778/… for the limitations of such use which is also documented in the manual. - percusse
There is no problem. :-) - kiss my armpit
3
[+19] [2012-05-03 18:50:13] Alain Matthes

Perhaps something like that

\documentclass[11pt]{scrartcl}
\usepackage{tikz}
\begin{document}

\pgfdeclareradialshading{ballshading}{\pgfpoint{-10bp}{10bp}}
 {color(0bp)=(gray!40!white); 
 color(9bp)=(gray!75!white);
 color(18bp)=(gray!70!black); 
 color(25bp)=(gray!50!black); 
 color(50bp)=(black)}

\begin{pgfpicture}
  \pgfpathcircle{\pgfpoint{0cm}{0cm}}{2cm}
  \pgfshadepath{ballshading}{20}
  \pgfusepath{}
\end{pgfpicture}  

\end{document}

enter image description here


Since I've unfamiliar with TikZ, here's a question: Does this ballshading scale depending on the size of the ball? I'm asking because you're using fixed measurements in setting colours. - Werner
Well ... I don't know ! I used an example from the pgfmanual and I played with the numbers. I changed the radius of the sphere from 1cm to 2cm. - Alain Matthes
(1) @Altermundus: Nice, the softness looks much better than the default! However, I still think that a circular highlight doesn't look right (and isn't correct physically, assuming your light source is circular). - Jake
4