# How to make a noise gradient?

Introduction:

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

                  *(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).

QUESTION:

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

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)

Is there any better solution to this idea i had?

Thanks for your interest in this question.

EDIT:

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.SetPixels(pixels);
texture.wrapMode = TextureWrapMode.Clamp;
texture.Apply();
return texture;
}


and obtaining the next result:

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)

EDIT2:

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?

• 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) )
– Bram
Feb 10, 2018 at 20:23
• Could you please further explain me? Feb 10, 2018 at 20:25
• 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? Feb 10, 2018 at 20:38
• 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) Feb 10, 2018 at 20:58
• You can also think of your noise map as a domain warp when sampling from your latitude gradient (or a wider-scale noise pattern...) Feb 10, 2018 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. 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 0.5 to 0/1 at the darkest/brightest extremes. 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(gradient(y), noise, 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.

• 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... Feb 13, 2018 at 12:55
• You are the MVP! Feb 13, 2018 at 12:55
• 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. :) Feb 13, 2018 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.

• on my heatNoise i should loop through it and do that math s = 1.2 - 0.4 * abs(y); ? Feb 10, 2018 at 22:15
• 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.
– Bram
Feb 10, 2018 at 22:25
• 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. Feb 10, 2018 at 22:29
• I wanted to do something like this but with Perlin noise jgallant.com/… Feb 10, 2018 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. You could also make a flat top at the equator with Math.Min(top, f).

• I was working on that a few minutes ago. If i can implement it, I will validate your answer. Merci! Feb 11, 2018 at 15:36
• 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. Feb 11, 2018 at 18:10
• Make sure the horizontal axis goes from 0 to 100. If you plot between 0 and 1 you will see only a straight line. Feb 12, 2018 at 13:17