# How to protrude a 2D image wrapped on a 3D surface

There are a few posts on this theme:

How to make a 3D globe?

How to render a 3D tubular graphics from a 2D image path

How to extrude a 3D image from a binary 2D image

However I can't quite piece them together. I am looking to take a 2D image wrapped on a 3D surface and protrude the markings.

For example: Given an image such as

and wrap around an ellipsoid protrude the lines and circles such that half a sphere is present

It would be ideal for the text to be clearly visible as well. EDIT If the text could be engraved that would be amazing!

Thanks if anyone fancies having a go! :)

• Can you show an example of something similar for clarity? I'm not sure how to interprete "half a sphere is present". – Kuba Jun 17 '18 at 8:49
• @Kuba I interpret it as the outer surface of a half-sphere: Plot3D[Sqrt[1 - x^2 - y^2], {x, -1, 1}, {y, -1, 1}, Mesh -> None, BoxRatios -> {1, 1, 1/2}], i.e. one hemisphere is mapped onto the circular plot from the OP. – corey979 Jun 17 '18 at 10:11
• Apologies for the confusion @Kuba I would like to wrap the first image around a 3D shape and protrude each dot/pixel/star - ideally with the shapes still overlapping. As in i.stack.imgur.com/XfQi6.png – Awkward Panda Jun 17 '18 at 18:55

I'm absolutely unsure if I got right what you want, but I'll give it a try.

The general steps are the fowllowing:

1. Take your image (which is of too low quality for a good texture) and create from it a gray-image that you can use as bump-map. Bright spots are higher and black is flat. Additionally, we use the original image as texture
2. Create an interpolation function from the pixel-data of the bump-map where you take care that it does the transformation from image coordinates to ellipsoid parameters
3. Create a custom parametric function for the ellipsoid that includes the bump-map that can be scaled with a factor. When the factor is zero, it would give a normal ellipsoid and the higher the factor, the more visible the bumps get.
4. Use ParametricPlot3D to plot your custom ellipsoid and use your image as a texture.

Most of the fiddling is to get the coordinate-system of interpolating function and the texture right and I didn't try hard to clean this up. First, I import your image and I use a combination of the brightness and the saturation channel as bump-map. Additionally, I smooth the bump-map a bit to prevent pixel artifacts.

img = Import["https://i.stack.imgur.com/m7YSX.png"];
{h, s, b} = ColorSeparate[img, "HSB"];
height = GaussianFilter[
Image[height]


Now we turn the height data into a function that can be used with the parametric form of an ellipsoid. The transformations are necessary because you probably want the center of the image at one end of the ellipse.

With[{ip =
ListInterpolation[height, {{-Pi/2, Pi/2}, {-Pi/2, Pi/2}}]},
bumpMap[theta_?NumericQ, phi_?NumericQ] :=
ip @@ ((Pi/2 - theta)*{Cos[phi], Sin[phi]}) /; 0 <= theta <= Pi/2 && 0 <= phi <= 2 Pi;
bumpMap[___] := 0.0
]


The parametric function of the ellipsoid takes the two angles and the ratios a, b, and c as defined on the wiki page. In addition, we make the bump-map stick out normal to the surface of the ellipsoid.

ellipsiod[theta_, phi_, a_, b_, c_, factor_] :=
With[{pt = {a Cos[theta]*Cos[phi], b Cos[theta] Sin[phi],
c Sin[theta]}},
pt + bumpMap[theta, phi]*factor*pt/Norm[pt]
]


Finally, you can make a parametric plot and grab a tea in the meantime because this takes long if you want a bit of quality

ParametricPlot3D[
ellipsiod[theta, phi, 1, 1, 2, 0.07],  {theta, 0, Pi/2}, {phi, 0, 2 Pi},
PlotPoints -> 100,
MaxRecursion -> 5,
PlotStyle -> Texture[img],
TextureCoordinateFunction ->
Function[{x, y, z, u, v}, ((Pi/2 - u)/(Pi))*{Cos[v - Pi/2], Sin[v - Pi/2]} + 1/2],
TextureCoordinateScaling -> False, Mesh -> None, Ticks -> None,
Lighting -> "Neutral"
]

• Spot on! Thanks a lot for taking the time to explain the steps, niceone. Any estimate on time taken for final step? – Awkward Panda Jun 21 '18 at 22:06
• @AwkwardPanda Some minutes on my machine. You can tune down MaxRecursion to 0 and PlotPoints to 50 and you'll note that you need much more resolution to see the small details. – halirutan Jun 21 '18 at 22:20