I am working on a heat map made by Perlin Noise with the next result:

Figure 1 (Figure 1)

                  *(Red means really hot and light blue is colder)* 

The algorithm identifies that mountains are colder at their top and plains vary between warm and hot(randomly, there is no physics behind).


How can i do so that heat map i generated with Perlin Noise looks like this example:

enter image description here (Figure 2)

where the temperature variations follows something like Earths equator.

My Ideas:

I thought about divide the map manually (from height to height2 is hot and so on...) but i do not like that idea as i want something more dynamic (temperatures may vary so does the heat map)

What i am asking?

Is there any better solution to this idea i had?

Thanks for your interest in this question.


With the code below i made possible the next thing:

public static Texture2D GetAirTemperature(int width, int height, Tiles[,] tiles)
    var texture = new Texture2D(width, height);
    var pixels = new Color[width * height];

    for (var x = 0; x < width; x++)
        for (var y = 0; y < height; y++)
            if (y <= 5 || y >= 95)
                pixels[x + y * width] = Coldest;
            else if (y <= 15 || y >= 85)
                pixels[x + y * width] = Colder;
            else if (y <= 30 || y >= 70)
                pixels[x + y * width] = Warm;
            else if (y <= 45 || y >= 55)
                pixels[x + y * width] = Warmer;
            else { pixels[x + y * width] = Warmest; }

    texture.wrapMode = TextureWrapMode.Clamp;
    return texture;

and obtaining the next result:

enter image description here (Figure 3)

How i could multiply/modulate/something it by my Perlin noise so i get something irregular but looks a like Earths Equator?

Because you cannot do like Texture2D * Texture2D (multiply textures)


What if, instead of using noise, i create my own 2D air temperature map as a starting point? I mean, my own matrix [width*height].

Temperature will have the input given at the center of matrix (equator) and then, when update the temperature map (a cycle).

A cycle will go once in a while (periodically) to simulate temperature changes.

The input from the sun at the equator [(width/2)x(height/2)] will move outwards from the center into "north and south the matrix" (North is x, y < 50 && south is x,y > 50)

That means i have to check each row and number above and under the equator while maintaining energy conservation and other factors.

It is nice on paper but a hell in coding. Do you have any other idea to accomplish something similar to figure 3?

  • 1
    \$\begingroup\$ I have trouble understanding you, as the answer seems too obvious? Just multiply your noise value with a factor that ranges from 0.8 to 1.2 to 0.8 going from pole to equator to pole. v = noise(x,y); v = v * ( 1.2 - 0.4 * abs(y) ) \$\endgroup\$ – Bram Feb 10 '18 at 20:23
  • \$\begingroup\$ Could you please further explain me? \$\endgroup\$ – WhiteGlove Feb 10 '18 at 20:25
  • \$\begingroup\$ I really depends on the coordinate system you are using. Is it a 2d or 3d map? At which coordinates are the cold and hot regions supposed to be? \$\endgroup\$ – Olivier Jacot-Descombes Feb 10 '18 at 20:38
  • \$\begingroup\$ it is a 2D map [x,y] (width, height) the Hot region should be at the center (equator) and gradually colder till the poles (top and bottom map) \$\endgroup\$ – WhiteGlove Feb 10 '18 at 20:58
  • 1
    \$\begingroup\$ You can also think of your noise map as a domain warp when sampling from your latitude gradient (or a wider-scale noise pattern...) \$\endgroup\$ – DMGregory Feb 10 '18 at 21:00

Here are two different ways I might approach this problem, showing how they change as the effect intensity is cranked up & down.

Animated gif of noise-influenced gratients

The outermost column on each side is just my gradient, computed as a function of the vertical position y, from 0 to 1:

gradient(y) = 1 - 2 * abs(y - 0.5);

The next column inward is my noise sample, varying with intensity from a medium grey at zero to maybe somewhere around +-0.4. Here I'm using a scrolling texture as my noise source, but you can sample one or more octaves of procedural noise for a similar effect.

The innermost grey columns show the gradient & noise combined, using two different strategies.

  • On the left: Weighted Average output = lerp(noise, gradient(y), intensity)

    Nothing fancy here. We have two signals in the range 0..1, so we add them together and multiply the result so it has the same range, equivalent to a linear interpolation between the two.

  • On the right: Domain Warping output = gradient(y + intensity * (noise - 0.5))

    Here we're using the noise to change the input to the gradient function, making it behave as though it were running for a point higher or lower on the image.

The innermost columns are the same two strategies, visualized in colour by sampling from a texture ramp. A series of if bands as in your example would work too for hard-edged contours.

One thing to notice is that, because the left strategy uses averaging, it tends to weaken the effect of each input, softening them toward mid-greys. In the colour map, you can see the effect of this as the green mid-temperature band expanding as the intensity ramps up, and we have fewer high reds or low blues.

The domain warping strategy, on the other hand, keeps the sharpness of the features and the average positions of each colour band roughly the same. But it does have the ability to fall off the edges of the domain at the top & bottom, sampling gradient values for inputs below 0 and above 1, which is why the deep blues & reds get more prominent there.

An effect that's a bit tougher to see in this gif is that the gradient function I used has a sharp fold in the middle where it changes from brightening to darkening, which our eyes tend to exaggerate and perceive as a faint line. In the weighted average case, this fold line is preserved, just made a little shallower. When the red is pushed in toward the middle, you briefly see sort of a "burned in" line across the middle on the left. On the right, the domain warping tends to bend and distort this fold line so it's less visible.

  • \$\begingroup\$ This is just what i wanted!. But, could the gradient be modified? i.e. The CO2 from industry accumulates so this is an increment in the gradient (Greenhouse) thus making the center more red and spread across? Cause these days i been playing with matrix and too difficult to implement stuff... \$\endgroup\$ – WhiteGlove Feb 13 '18 at 12:55
  • \$\begingroup\$ You are the MVP! \$\endgroup\$ – WhiteGlove Feb 13 '18 at 12:55
  • 1
    \$\begingroup\$ You can use any gradient function you want. For instance, you could scale the whole thing like gradient(y) = warming * (1 - abs(y - 0.5)) or you could replace the sharp absolute value function with a bell curve and tune how sharply it bulges in the middle. This is a great context to play with different math functions and see what they give you. :) \$\endgroup\$ – DMGregory Feb 13 '18 at 13:05

Just because you use noise as your data, doesn't mean you can "modulate" the result.

To get a gradient overlay on top of noise, just multiply it with a factor that ranges from 0.8 at north pole, to 1.2 at equator, to 0.8 at south pole.

This code would do the trick:

// x and y range from -1 to 1
v = noise( x, y );
s = 1.2 - 0.4 * abs(y);
result = s * v;

That would result in a noise field, that is skewed to hot at equator. The equator still has streams of hot and cold running through it, but on a whole, is hotter than the poles.

Reminder: Not shown in my example code, but: don't forget to mix multiple octaves to make the noise look good. You do this like so.

  • \$\begingroup\$ on my heatNoise i should loop through it and do that math s = 1.2 - 0.4 * abs(y); ? \$\endgroup\$ – WhiteGlove Feb 10 '18 at 22:15
  • \$\begingroup\$ What programming language are you using, are you using a noise library, or wrote your own perlin noise code? When you create your noise image, just multiply the value you get, before converting it with your colour scale. \$\endgroup\$ – Bram Feb 10 '18 at 22:25
  • \$\begingroup\$ i program in C# and i am just using the Perlin noise from Unity. I tried what you said but it does not work for my code. \$\endgroup\$ – WhiteGlove Feb 10 '18 at 22:29
  • \$\begingroup\$ I wanted to do something like this but with Perlin noise jgallant.com/… \$\endgroup\$ – WhiteGlove Feb 10 '18 at 22:30

You could take a linear gradient between equator and poles ranging from min at the poles (y = 0 and y = 100) to max at the equator (y=50). The factor then becomes

f =  Math.Abs(y / 50 - 1) * (min - max) + max;

multiply the noise with this factor

pixels[x + y * width] = GetColorFromTemperature(GetTemperatureFromNoise(x, y) * f);

As an example with min = 0.2 and max = 1.2:

Plot made with: www.wolframalpha.com (with x-axis as your latitude (y) and y-axis as the factor.

enter image description here

You could also make a flat top at the equator with Math.Min(top, f).

  • \$\begingroup\$ I was working on that a few minutes ago. If i can implement it, I will validate your answer. Merci! \$\endgroup\$ – WhiteGlove Feb 11 '18 at 15:36
  • \$\begingroup\$ Is that formula correct f = Math.Abs(y / 50 - 1) * (min - max) + max;? Cause i plotted it in matlab and it is a straight line. I even thought to convolute two square signals but that's too much to obtain a triangular function. \$\endgroup\$ – WhiteGlove Feb 11 '18 at 18:10
  • 1
    \$\begingroup\$ Make sure the horizontal axis goes from 0 to 100. If you plot between 0 and 1 you will see only a straight line. \$\endgroup\$ – Olivier Jacot-Descombes Feb 12 '18 at 13:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.