Update
I used the basis of this article in the tool you can find : https://sites.google.com/site/noiselab15/
Introduction
For some stuff I get involved concerning run time planets generation I faced procedural seamless texture generation. To create a planet at run time is foundamental to manage seamless texture. A seamless texture can work as greyscale highmap and/or landscape texture and/or atmosferic effects.
Searching the web I found some well known tecniques like perlin noise (http://en.wikipedia.org/wiki/Perlin_noise) or fractal noise.
So I decided to arrange a c# "sandbox" small project to experiment some texture generation algorithms, to test performance , and so on. In particular I implemented a Perlin noise generator using resources from web (references will follow), after that I've created some recoursive algoritms that can reach, in my opinon, sadisfactory effects compared to Perlin, at a good performance cost. Here I'm going to share some stuff.
Background
I implemented Perlin noise studing these web sources : http://www.sepcot.com/blog/2006/08/PDN-PerlinNoise2d and http://freespace.virgin.net/hugo.elias/models/m_perlin.htm . I'm not going to explain Perlin noise , first reason I'm not so smart to explain something I merely understand better than the links above.
Another (this time easy) thing usefull before going ahead is to know what a grayscale image is and how usefull it is for define a heightmap. At the same time is usefull to know how to use the alpha chanell of an image , for example to add clouds on a predefined sky.
The basic idea is to draw on a random sub region of the image a light grey rectangle (let's call it a "box") covering the sub region. After that we calculate n random point near the center of first box , we reduce box size (i.e by half) and we repeat for the n small boxes. Every time we draw a box we add its grey delta to the preexistents pixels.
In the sequence below we start with 2 recursion calls and we end with 20 recursion call. For the last image we repeat it 7 times and we reduce the grey delta to make vanishing the bigger boxes.
Finaly, the textures created are seamless and perfectly tileable
Using the code
The main recursive method of Contoli noise is very simple :
private void printQuad(float [,] Values, int wid, int hei,int x, int y, int boxSize, int deepness, int delta) {
if (deepness > 0 && boxSize>=1)
{
for (int i = -boxSize/2; i < boxSize/2; i++)
{
for (int j = -boxSize / 2; j < boxSize / 2; j++)
{
int pixX = (x + i) % wid;
int pixY = (y + j) % hei;
if (pixX < 0)
pixX = wid + pixX;
if (pixY < 0)
pixY = wid + pixY;
Values[pixX, pixY] = Values[pixX, pixY] + delta;
Iterations++;
}
int xx = r.Next(x, x + boxSize);
int yy = r.Next(y, y + boxSize);
printQuad(Values, wid, hei, xx, yy, boxSize / 2, --deepness, delta);
}
}
}
Where:
Values
is the bidimensional array of float representing the image pixels
wid
and hei are the image dimension
x
and y are the center point coords of the box
boxSize
is the size of the rectangle
deepness
how deep in recursion are now
delta
how many grey scale we add over existing values. (It represent the delta height)
Stopping the recursion :
if (deepness > 0 && boxSize>=1)
we stop the recursion if we are too deep or if box size reachs zero.
To call it ;
r = getrRandom();
for (int nr = 0; nr < N_Repetitions; nr++) {
int x = r.Next(0, wid - 1);
int y = r.Next(0, hei - 1);
printQuad(Values, wid, hei, x, y, box_size, Godeep, d);
}
updBitmap(Values, tmp, grayScale.Checked);
pictureBox1.Image = tmp;
pictureBox1.Refresh();
updBitmap
converts the Values array in a greyscaled bitmap.
getRandom
initialize the random number generator used inside printQuad
.
N_Repetitions
is self explained.
The application:
The Contoli Noise Methods:
Quad : the simplest already discussed;
Circ : draws circles instead of rectangles, we get a better effect keeping recursion deepness low;
Func ; draws a 2 variable function instead of rectangles. Actualy the function is a Torus ( http://en.wikipedia.org/wiki/Torus) .
Quad (left) VS Circ (right):
The torus example: 1 recursion deepnes vs 33 recursion deepnes.
General note: when incrementing "recursion" value is good to decrement "delta color" value.
Using the printFunc
code.
f func = (x1,y1) => (float)Math.Sqrt((0.4f * 0.4f - Math.Pow((0.6f - Math.Sqrt(x1 * x1 + y1 * y1)), 2)));
printFunc(Values, wid, hei, x, y, box_size, Godeep, d,func);
useValueArray = true;
break;
printFunc
accepts a function f
delegate. If you don't like TORUS You can redefine it the way you want.
Example for paraboloid:
f func = (x1,y1) => 1f + (float) ((x1*x1)/1f + (y1*y1)/1f) * -1f;
In the "Distance alg." section I present a set of algorithms to generate effects over a bitmap using tecniques based on distances from a set of random points. It's work in progress.
Voronoi diagram
In the Voronoi section we can experiment some implementations of the procedural space tesselation, based on Voronoi idea. The basic idea is : 1) take a random set S of points on a plane; 2) every point "s" of S defines a region "r" on the plane where each point in the region "r" is the closest to point "s" (harder to explain tha understand) 3) use some random color (grayscale) to paint each region (or the region borders) 4) add some coding to keep all the stuff "seamless"
The examples:
The code:
private void Voronoi(float[,] Values, int wid, int hei, int[,] points)
{
for (int i = 0; i < wid; i++)
{
for (int j = 0; j < hei; j++)
{
float minDist = Math.Min(wid,hei);
int minV = 0;
for (int p = 0; p < points.GetLength(0); p++) {
int pX = points[p, 0];
int pY = points[p, 1];
int pV = points[p, 2];
Double Dist1X = Math.Abs((i - pX));
Double Dist1Y = Math.Abs((j - pY));
Double Dist2X = wid - Dist1X;
Double Dist2Y = hei - Dist1Y;
Dist1X = Math.Min(Dist1X, Dist2X);
Dist1Y = Math.Min(Dist1Y, Dist2Y);
float dist = (float)Math.Sqrt(Math.Pow(Dist1X, 2) + Math.Pow(Dist1Y, 2));
if (dist < minDist) {
minDist = dist;
minV = pV;
}
}
Values[i, j] = minV;
Iterations++;
}
}
}
3D Noise
Going 3d. I added a 3d implementation of contoli noise and voronoi noise. To test it simply push "Start 3d noise" , wait some time depending on the parameters , enjoy.
Some explanation , in this case the 3rd dimension is TIME, so we get an "animated" noise. If you comapare printQuad3D
with printQuad
you'll find the 3rd dimension management. Obviosly, even the 3rd dimension is seamless, and let the animation to loop without cuts.
Animation demo links:
Quad 3d noise:
https://www.youtube.com/watch?v=cVnhmmPVSf8
Circ 3d noise:
https://www.youtube.com/watch?v=cFVYq_cS5C4
https://www.youtube.com/watch?v=7qPrKBut6qY
Voronoi animations
https://www.youtube.com/watch?v=GnR6dLPxvNc
https://www.youtube.com/watch?v=uihClJuwqz8
https://www.youtube.com/watch?v=TpkrNQe4guQ
https://www.youtube.com/watch?v=CfpY8saDa9U
History
First version.
9-NOV-2014 : added VORONOI section.
12-NOV-2014 : added 3D Noise section.
14-NOV-2014 : added 3d noise demos youtube links