Hey people! I’m really new to processing and programming as a whole and I’m trying to do a simulation of a terrain with pseudo-realistic river flow logic. Its a 2D array with perlin noise that does the trick for the terrain which is colour coded (every x and y has a random colour attributed to its rectangle in the grid that shows its height/altitude). I would want to know how can I make so that the program knows how to only place “river tiles” when a tile has almost the same colour but higher (in this case, darker) than the next one so the river is in constant downfall. So there would only be rivers where there are inclinations and not just to generate them based in “from this height to this height its river”. The code is as it follows:
int cols,rows;
int scale =25;
int w = 1800;
int h = 950;
float[][] terrain;
void setup(){
size(1800,950);
cols = w/scale;
rows = h/scale;
terrain = new float[cols][rows];
float yoff=0;
for (int y = 0; y < rows; y++) {
float xoff=0;
for(int x = 0; x < cols; x++) {
terrain[x][y] = map(noise(xoff,yoff),0,1,0,255);
xoff+=0.2;
}
yoff+=0.2;
}
}
void draw(){
noStroke();
for (int y = 0; y < rows; y++) {
for(int x = 0; x < cols; x++) {
fill(139,terrain[x][y],19);
rect(x*scale, y*scale, scale, scale);
}
}
}
I guess a naive approach would consist in picking “starting” cells (rectangles) at a specific height or with a specific noise value and, for each of them, find the neighboring cell with the closest height/noise value (either higher or lower than current one). Once found, these neighboring cells would become the new “starting” cells in turn and the previous starting cells would be marked as visited.
This routine can be repeated until either:
all neighboring cells are marked as visited
no higher (or lower, if going downhill) noise values are found in the neighborhood
M = 15.0 # Magnification
W, H = 1800, 900 # Dimensions of canvas
w, h = W/M, H/M # Dimensions of grid (number of cols & rows)
S = H/h # Step/Cell size
N = w*h # Number of cells
F = .05 # Factor of noise
U, L = .9, .15 # Upper and Lower bounds
K = (-w-1, -w, -w+1, -1, 1, w-1, w, w+1) # Kernel
visited = set()
def setup():
size(W, H)
noiseSeed(54561)
global n_vals
n_vals = [noise((i%w)*F, (i//w)*F) - .05 for i in xrange(N)]
for i, n in enumerate(n_vals):
if n<L and random(1)>.95:
descend(i)
for i, v in enumerate(n_vals):
c = color(v*255, v*255, 255) if i in visited else v*255
fill(c)
rect((i%w)*S, (i//w)*S, S, S)
def descend(id):
n_val = n_vals[id] # get noise value of currently examined cell
if n_val > U: return # if that noise value is too high -> return/stop the function
visited.add(id) # else -> mark it as visited
# Find neighboring cells with higher noise values (convolution)
nbhood = []
for k in K:
nid = int(id+k) # neighboring id
if 0 < nid < w*h and nid not in visited: # if neighboring cell inside canvas and hasn't been visited yet
nn_val = n_vals[nid] # corresponding noise value
if nn_val > n_val: # if noise value of neighboring cell is higher -> append to 'nbhood' array list
nbhood.append((nid, nn_val - n_val))
# If available neighbors, pick the one with closest noise value and explore it in turn
if nbhood:
nxt_id = sorted(nbhood, key=lambda x: x[1]).pop()[0] # pick neighbor with lowest noise difference (just slightly higher)
descend(nxt_id)
Thanks Solub! I cant express how grateful I am. Could I just ask you something? Can you write it in processing form? (Java). I dont know a thing about Python, I am starting to learn it but Im at the very beggining, sorry for the trouble and extra work but I just couldn’t grasp what you did fully. Thanks a lot, whole heartdly.
I selfishly posted Python code to a Processing Java question so I should be the one apologizing. I would have posted in Java if I was comfortable with it but unfortunately it is still not the case and I don’t have much time on my hands to make the translation from Python.
All I can do is briefly explain the code and break it down into small steps:
1/ compute 2D noise value for each cell in a grid (you did it already)
2/ select one or several cells above a certain noise threshold ( >0.85 for example)
3/ mark it/them as “visited”
4/ get the noise value of its/their surrounding (Moore neighborhood) unvisited cells
5/ filter out neighboring cells with higher noise values (keep only the ones with lower noise values)
6/ pick the one with the closest noise value (just slightly below)
7/ repeat step 3 to 6 recursively
8/ display visited cells (path of river) in a different color
Feel free to post your attempts and ask for help if necessary. Sorry I couldn`t be of more help.