# How to create and export a procedural planet texture with normal map

I would like to generate some earth-like/mars-like/giant-gas-like planets/moon/asteroid textures with normal map and specular map as 4k PNG files (4096 X 2048 pixels), to be mapped on a sphere with some 3D software.

I really know nothing about generating textures using Mathematica, so I'm starting from scratch here, and need help to write a full code to do this.

The exported textures need to look realistic, with random mountains/valleys, craters, turbulence in the gas-giant, etc. The files need to be of resolution 4096 X 2048 pixels (or better), and have the standard mapping on a sphere (I think this is the Mercator projection, but I'm not sure).

How to start this project with Mathematica ? Is this too ambitious to be done with Mathematica ?

(I suspect that the generation process may be too slow with Mathematica, at that resolution, and it may be better to learn to use another specific software to generate planet textures)

I'm thinking about textures a bit like this one (this is just an example) :

EDIT 1 :

If possible, codes should be compatible with older versions of Mathematica. Personaly, I'm still using version 7.0. But the questions above are applying to all versions. Please, if you post some code, specify to which version it is applying.

• This question is very wide. Maybe you can add some example images, what the generated images should look like? In general, processing 8 megapixel images shouldn't be a performance problem, as long as you can use image processing functions or vectorized array operations. Sep 1 '16 at 15:03
• @nikie It is a very broad question, but I guess it's reasonable and it can have a useful equally broad answer. An important part of the question is: "Is this too ambitious to be done with Mathematica?" I imagine an answer which addresses feasibility first and then breaks down the solution to parts, with rough guidelines on how each part may work. A question this broad doesn't necessarily have to have a detailed answer with ready-to-use code. Sep 1 '16 at 15:12
• @Cham Last time I looked at one of your questions you mentioned that you only had Mathematica 7. That would make a huge difference. The current version is 11, and much more capable than 7 was. Please indicate your version if it's an old one. Sep 1 '16 at 15:13
• @Szabolcs, yes, I still use Mathematica 7. One of these days, I'll try upgrading. I'm not sure yet that I need to impose the old version to my question, since I may get no answers at all to the questions ! Also, the questions may be usefull to others too, with more recent versions. I've edited the question to add a few comments on the version.
– Cham
Sep 1 '16 at 15:25
• One interesting part of the question is dealing with the spherical shape. Generating a texture for a flat world is one thing. Making it work on a sphere is another challenge. @Cham You are right: restricting to 7 would kill motivation for many people. But since this is more about the method than the implementation, a v11 answer could be backported too. Sep 1 '16 at 15:29

Here is something to get you started. Go to Help > Compile > Neat Examples to get code for Perlin noise. Make an image with, for example,

amplitude = 1.5;
frequency = 1.0;
gain = 0.5;
lacunarity = 2.0;
increment = 7.0;
scale = 150.0;
sphereImage = ReliefImage[perlin[512, 512]]


Several answers here have described how to map an image to a sphere. For example, here and here. Unfortunately, artefacts seem unavoidable; perhaps someone can suggest a better way.

ParametricPlot3D[
{Cos[u] Sin[v], Sin[u] Sin[v], Cos[v]},
{u, 0, 2 Pi}, {v, 0, Pi},
Mesh -> None, PlotPoints -> 100, TextureCoordinateFunction -> ({#4, 1 - #5} &),
Boxed -> False, PlotStyle -> Texture[Show[sphereImage, ImageSize -> 400]],
Lighting -> "Neutral", Axes -> False]


SphericalPlot3D[1, {theta, 0, Pi}, {phi, 0, 2 Pi},
Mesh -> None,
TextureCoordinateFunction -> ({1 - #4, #5} &),
PlotStyle -> Directive[Texture[sphereImage]], Lighting -> "Neutral",
Axes -> False, Boxed -> False]


POVRay uses 3D Perlin noise, and generates much more realistic planets than my examples here. Plus, there are no artefacts.

• Please, state the versions of Mathematica to which your code applies.
– Cham
Sep 1 '16 at 15:51
• Using version 10.4.1 Sep 1 '16 at 21:17

One way to approach the generation of a planetary surface is to start with something that is "like" what you want and then extrapolate beyond the boundaries. With images, this is sometimes called "inpainting" and Mathematica has the function Inpaint (which, according to the documentation, was introduced in version 8). For instance, here is an imaginary Earth (downloaded from google images). A small portion of this is selected and then a larger map is extraplated from the selection:

img = Import["http://www.geocurrents.info/wp-content/uploads/2012/01/Map_of_\
Earth_2.jpg"];
imgSmall = ImageCrop[img, {150, 150}]
dims = ImageDimensions[imgSmall];
canvas = ImageCrop[imgSmall, 2*dims, Padding -> White];
Method -> {"TextureSynthesis", "NeighborCount" -> 20, "MaxSamples" -> 1000}]


And here is the same using the picture of Mars in the OPs link:

For mapping to the sphere, you can:

colorfun = BSplineFunction[ImageData[extrapolated], SplineDegree -> 1];
ParametricPlot3D[{Sin[u] Cos[v], Cos[u] Cos[v], Sin[v]}, {u, 0, Pi}, {v, -Pi, Pi},
ColorFunction -> {colorfun[1 - #5, #4] &}, ViewPoint -> {Pi/2, Pi, 1},
PlotPoints -> 200, MaxRecursion -> 0, Mesh -> None, Axes -> None, Boxed -> False,
BoundaryStyle -> None, ImageSize -> {500}]


Being a 3D plot, you can rotate the planet at will. There is an unfortunate stitching artifact using this mapping, but for this image it's on the other side of the planet.

I'm fairly certain that the OP has move on to other projects. That said, the other answers don't address one part of the question, which is the normal map generation for inclusion in 3D software.

Let's take an example texture and use the following function to generate a normal map.

imgd = ExampleData[{"ColorTexture", "WhiteMarble"}];
makeNormalMap[i_Image] :=
Module[{grayscale, norm, didx, didy, nx, ny, nz},
grayscale = ColorConvert[i, "Grayscale"];
didx = ImageData@DerivativeFilter[grayscale, {0, 1}];
didy = ImageData@DerivativeFilter[grayscale, {1, 0}];
norm = Sqrt[didx^2 + didy^2 + 1];
nx = Rescale[-didx/norm];
ny = Rescale[-didy/norm];
nz = 1/norm;
Image[{nx, ny, nz}, Interleaving -> False]
]


The process for making the normal map is adapted from a similar question at Blender Stackexchange. Note: I would be interested in some code-review here, since I suspect my hackish implementation of Norming ImageData can be improved.

The two images from Mathematica:

For a 3D material example, I am using Unreal Engine to create a material, applying the left-hand image as the base-color texture and the right-hand image as the normal map. Assigning arbitrary specular and roughness parameters (very specular and very smooth), I get the following:

And just for comparison, here is the same material, but without using the normal map.