#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# A *big* collection of Mountain fractals(Terrain Generation) in 3D and 2D + useless bonus

edited August 2015 in Examples Posts: 116

Hey, Im impressed by fractals, i wrote a bunch of them. Here are some fractals about recursive generating of mountains

2D Mountain generation
This is my first try. you can use scl parameter to zoom in. Later i will attempt to use the same method in 3D, so this is like a trailer for the upcoming 3D fractals.
Code:

``````-- 2d Mountain
function setup()
size = WIDTH/2
points = {-0.1,HEIGHT/2,HEIGHT}
parameter.action("next",next)
parameter.integer("scl",1,100,1)
end
function draw()
scale(scl)
strokeWidth(1/scl)
background(40, 40, 50)
for num,pt in ipairs(points) do
if num > 1 then
line(size*(num-2),points[num-1],size*(num-1),pt)
end
n = num
end
end
function next()
for i = 1, n-1 do
table.insert(points, i*2,0)
points[i*2] = rndh(i*2)
end
size = size * 0.5
end
function rndh(number)
lim1 = math.floor(points[number-1])
lim2 = math.ceil(points[number+1])
if lim1 > lim2 then
return math.random(lim2,lim1)+math.random()
elseif lim2 > lim1 then
return math.random(lim1,lim2) +math.random()
else
return math.random(lim2,lim1) +math.random()
end
end

``````

3D Fractal Mountain using a self invented caricature to Midpoint Displacement Algorithm
This is my first fractal working in 3D and it works a bit crappy, but at least it works. It takes the input from the camera, so it shouldnt be black. With the first 4 parameters you can set the starting points and with the 5th, you can start over using these. You can also play with this replacing mid(...) with one of the last functions. Later i wrote something like that, but using Perlin noise.
Here is the code:

``````function setup()
parameter.number("h11", 0, 1000, 0)
parameter.number("h12", 0, 1000, 200)
parameter.number("h21", 0, 1000, 400)
parameter.number("h22", 0, 1000, 800)
parameter.action("setH",setHeights)
size = 1000
heights = {}
heights = {0,200}
heights = {400,800}
hLenght = 0
ms = mesh()
ms:setColors(255,255,255,255)
parameter.action("next",next)
parameter.number("CamHeight", 0, 4000, 3000)
parameter.number("Angle",-360, 360, 90)
parameter.number("FieldOfView", 10, 140, 38)

parameter.number("roundness",0.05, 5, 1)

end

function draw()

-- First arg is FOV, second is aspect
perspective(FieldOfView, WIDTH/HEIGHT)

-- Position the camera up and back, look at origin
camera(1024,CamHeight,-3000, 1024,0,0, 0,1,0)
rotate(Angle,0,1,0)
background(24, 24, 165, 255)
strokeWidth(1)
ms:draw()
end
function next()

size = size * 0.5
for i, row in ipairs(heights)do
hLenght = hLenght + #row
end
for row=1, #heights-1 do
table.insert(heights,row*2,{})--inserting a new row
for col = 1, #heights[row] do

--REPLACE HERE
table.insert(heights[row*2], mid({heights[row*2-1][col],heights[row*2+1][col],heights[row*2][col-1],heights[row*2+1][col+1],heights[row*2-1][col+1],heights[row*2+1][col-1],heights[row*2-1][col-1]})+(noise(col * size, row*2 * size)+1)*roundness*size)--inserting the 1, 3, 5... height in that row
end
end
for i, row in pairs(heights) do
for col=1, #row-1 do
if i == 1 then
--REPLACE HERE
table.insert(row,col*2,mid({heights[i][col*2-1], heights[i][col*2+1],heights[i+1][col*2-1], heights[i+1][col*2+1]})+(noise(col*2 * size, i * size)+1)*roundness*size)
elseif i == #heights then
table.insert(row,col*2,mid({heights[i][col*2-1], heights[i][col*2+1],heights[i-1][col*2],heights[i-1][col*2-1], heights[i-1][col*2+1]})+(noise(col*2 * size, i * size)+1)*roundness*size)
else
table.insert(row,col*2,mid({heights[i][col*2-1], heights[i-1][col*2],heights[i][col*2+1],heights[i+1][col*2-1], heights[i+1][col*2+1],heights[i-1][col*2-1],heights[i-1][col*2+1]})+(noise(col*2 * size, i * size)+1)*roundness*size)
end
end
end
setVrt()
end
function setVrt()

tx = {}
msvrt = {}
for y, row in pairs(heights) do
if y >1 then
for x, pt in pairs(row) do
if x+1 <= #row then
table.insert(msvrt,vec3(x*size,pt,y*size))--tri vertices
table.insert(msvrt,vec3(x*size,heights[y-1][x],(y-1)*size))
table.insert(msvrt,vec3((x+1)*size,heights[y-1][x+1],(y-1)*size))
--[[
table.insert(tx,vec2(x/#row,1-y/#heights))--tex coords
table.insert(tx,vec2(x/#row,1-(y-1)/#heights))
table.insert(tx,vec2((x+1)/#row,1-(y-1)/#heights))
]]
end
if x>1 then
table.insert(msvrt,vec3(x*size,pt,y*size))--tri vertices
table.insert(msvrt,vec3(x*size,heights[y-1][x],(y-1)*size))
table.insert(msvrt,vec3((x-1)*size,heights[y][x-1],y*size))
--[[
table.insert(tx,vec2(x/#row,1-y/#heights))--tex coords
table.insert(tx,vec2(x/#row,1-(y-1)/#heights))
table.insert(tx,vec2((x-1)/#row,1-y/#heights))
]]
end
end
end
end
ms.vertices = msvrt

for i, val in pairs(msvrt) do
table.insert(tx, vec2(i/#msvrt,i/#msvrt))
end

ms.texture = CAMERA
ms.texCoords = tx
end
function mid(values)
result = 0
for i, value in ipairs(values) do
result = result + value
num = i
end
return result/num
end
function rnd(vls)
values = {}
for i, value in pairs(vls) do
table.insert(values, value)
end
max = math.max(table.unpack(values))
min = math.min(table.unpack(values))
return(math.random(min,max))
end

function midrnd(vls)
values = {}
for i, value in pairs(vls) do
table.insert(values, value)
end
while #values > 2 do
for i, value in pairs(values) do
if value == math.max(table.unpack(values)) or
value == math.min(table.unpack(values)) then
table.remove(values,i)
end
end
end
max = math.floor(math.max(table.unpack(values)))
min = math.floor(math.min(table.unpack(values)))
return(math.random(math.floor(min),math.ceil(max)))
end
function maxrnd(vls)
values = {}
for i, value in pairs(vls) do
table.insert(values, value)
end
max = math.max(table.unpack(values))
min = math.min(table.unpack(values))
return(math.abs(math.random(math.floor(min),math.ceil(max)))*(math.log((size/1000))))--math.random(math.floor(min),math.ceil(max)))
end
function setHeights()
size = 1000
heights = {}
heights = {h11,h12}
heights = {h21,h22}
end

``````
Tagged:

## Comments

• edited August 2015 Posts: 5,396

A big collection is 2 fractals? I'm not sure your 2D line is fractal, because it doesn't look similar at all scales, which I think is the definition of fractal. Instead, it starts off as a straight line, and just gets more jagged.

I'll be interested to see your final 3D version - why not use a commonly accepted method rather than trying to invent your own?

Noise is also good for landscapes, although it isn't fractal.

• Posts: 116

-Noise 6th Edition 3D Mountain Fractal- <-the name in codea
A Mountain Fractal using Perlin Noise
This is my last fractal about generating a mountain. Now i used Perlin noise values to generate the mountain. I have no idea how to fix it, but after 7-8 iterations there is a wavy field there(i want a mountain). But expect that it works great.

``````function setup()
parameter.action("setH",setHeights)
setHeights()
ms = mesh()
ms:setColors(255,255,255,255)
parameter.action("next",next)
parameter.number("CamHeight", 0, 4000, 3000)
parameter.number("Angle",-360, 360, 90)
parameter.number("FieldOfView", 10, 140, 38)
parameter.number("roundness",0.05, 5, 2)
field = 2
noisescl = 1000
noisepos = vec2(math.random(-100000,1000000),math.random(-100000,1000000))
end

function draw()

-- First arg is FOV, second is aspect
perspective(FieldOfView, WIDTH/HEIGHT)

-- Position the camera up and back, look at origin
camera(1024,CamHeight,-3000, 1024,0,0, 0,1,0)
rotate(Angle,0,1,0)
background(24, 24, 165, 255)
strokeWidth(1)

--[[
for i, row in ipairs(heights) do
text(table.concat(row," "), WIDTH/2, HEIGHT-50*i-50)
end
]]

ms:draw()
end
function next()
noisescl = noisescl * 0.25
size = size * 0.5
field = field + (field - 1)
heights = {}
for i=1, field do
table.insert(heights,{})
end
for r, row in ipairs(heights) do
for i=1, field do
s = noisescl
h = (noise((i * noisescl)+noisepos.x, (r * noisescl)+noisepos.y)+1)*roundness*size
while s < 1000 do
s = s * 4
h = h +  (noise((i * noisescl)+noisepos.x, (r * noisescl)+noisepos.y)+1)*roundness*size
end
table.insert(row, h)
end
end
setVrt()

--[[

for row=1, #heights-1 do
table.insert(heights,{})--inserting a new row
for col = 0, #heights[row]-1 do
s = noisescl
h = (noise((col * noisescl)+noisepos.x, ((#heights[row]-1) * noisescl)+noisepos.y)+1)*roundness*size
while s < 1000 do
s = s * 4
h = h +  (noise((col * noisescl)+noisepos.x, ((#heights[row]-1) * noisescl)+noisepos.y)+1)*roundness*size
end
table.insert(heights[#heights], h)--inserting heights in that row
end
end
for i, row in ipairs(heights) do
for col=1, #row-1 do
s = noisescl
h = (noise((col * noisescl)+noisepos.x, (i * noisescl)+noisepos.y)+1)*roundness*size
while s < 1000 do
s = s * 4
h = h +  (noise((col * noisescl)+noisepos.x, (i * noisescl)+noisepos.y)+1)*roundness*size
end
table.insert(row,h)
end
end
setVrt()
]]
end
function setVrt()

tx = {}
msvrt = {}
for y, row in pairs(heights) do
if y >1 then
for x, pt in pairs(row) do
if x+1 <= #row then
table.insert(msvrt,vec3(x*size,pt,y*size))--tri vertices
table.insert(msvrt,vec3(x*size,heights[y-1][x],(y-1)*size))
table.insert(msvrt,vec3((x+1)*size,heights[y-1][x+1],(y-1)*size))
--[[
table.insert(tx,vec2(x/#row,1-y/#heights))--tex coords
table.insert(tx,vec2(x/#row,1-(y-1)/#heights))
table.insert(tx,vec2((x+1)/#row,1-(y-1)/#heights))
]]

end
if x>1 then
table.insert(msvrt,vec3(x*size,pt,y*size))--tri vertices
table.insert(msvrt,vec3(x*size,heights[y-1][x],(y-1)*size))
table.insert(msvrt,vec3((x-1)*size,heights[y][x-1],y*size))
--[[
table.insert(tx,vec2(x/#row,1-y/#heights))--tex coords
table.insert(tx,vec2(x/#row,1-(y-1)/#heights))
table.insert(tx,vec2((x-1)/#row,1-y/#heights))
]]
end
end
end
end
ms.vertices = msvrt

for i, val in pairs(msvrt) do
table.insert(tx, vec2(i/#msvrt,i/#msvrt))
end

ms.texture = CAMERA
ms.texCoords = tx
end
function mid(values)
result = 0
for i, value in ipairs(values) do
result = result + value
num = i
end
return result/num
end

function setHeights()
size = 1000
heights = {}
heights = {0,0}
heights = {0,0}
end

``````
• Posts: 116

BONUS
My very first try to make a 3D fractal and my first try to make something in 3d. Dont ask anything. I dont know how it works. Code:

``````function setup()
size = 50
points = {{},{},{}}
points = {vec3(0,0,0),vec3(250,125,0),vec3(500,250,0)}
points = {vec3(0,125,250),vec3(250,250,250),vec3(500,375,250)}
points = {vec3(0,250,500),vec3(250,375,500),vec3(500,500,500)}
pts = {vec3(0,0,0),vec3(250,0,125),vec3(500,250,0)
,vec3(0,125,250),vec3(250,250,250),vec3(500,375,250)
,vec3(0,250,500),vec3(250,375,500),vec3(500,500,500)}

ms = mesh()
ms:setColors(255,255,255,127)
msvrt1 =        {pts,pts,pts,
pts,pts,pts,
pts,pts,pts,
pts,pts,pts,
pts,pts,pts,
pts,pts,pts,
pts,pts,pts,
pts,pts,pts}
msvrt ={points,points,points,
points,points,points,
points,points,points,
points,points,points,
points,points,points,
points,points,points,
points,points,points,
points,points,points,}
ms.vertices = msvrt
parameter.action("next",next)
parameter.number("CamHeight", 0, 500, 0)
parameter.number("Angle",-360, 360, 0)
parameter.number("FieldOfView", 10, 140, 45)
end

function draw()

-- First arg is FOV, second is aspect
perspective(FieldOfView, WIDTH/HEIGHT)

-- Position the camera up and back, look at origin
camera(0,CamHeight,-300, 0,0,0, 0,1,0)
rotate(Angle,0,1,0)
background(24, 24, 165, 255)
strokeWidth(1)
ms:draw()
--[[
for x,column in pairs(points) do
for y,value in pairs(column) do

end
end
]]
--[[
for num, coord in pairs(points) do
if num > 1 then
p1 = points[num-1]
p2 = coord
line(p1.x,p1.y,p2.x,p2.y)
end
end
]]
ortho()
end
function next()
for y, row in ipairs(points) do
for x, val in ipairs(row) do
n1 = y
n2 = x
end
end
pointsRow = n1
pointsCol = n2
pointsLen = n1*n2
for y = 1,n1-1 do
--print("inserting the row "..y*2)
table.insert(points,y*2,{})
pointsRow = pointsRow + 1
for x = 1,pointsCol do
--print("row: "..(y*2)..", x: "..x.."inserting at pos "..x)
table.insert(points[y*2],vec3(points[y*2+1][x].x, 0, (y-1)*250))
pointsLen = pointsLen + 1
end
for x = 1, pointsCol do
points[y*2][x].y = rndh(y*2,x)
end
end
for y = 1,pointsRow do
for x = 1,n2-1 do
print("row: "..y..", x: "..x.."inserting at pos "..x*2)
table.insert(points[y],x*2 , vec3(0, 0,(y-1)*250))
if y == 1 then
pointsCol = pointsCol  + 1
end
pointsLen = pointsLen + 1
--rndh(y,x*2)
end
for x = 1,n2-1 do
points[y][x*2].x = points[y][(x*2)+1].x/2
points[y][x*2].y = rndh(y,x*2)
end
end

print("rows: "..pointsRow)
print("cols: "..pointsCol)
print("len: "..pointsLen)
msvrt = {}
for y, row in ipairs(points) do
if y >1 then
for x, pt in ipairs(row) do
if math.fmod(x, 2) == 1 then
if x+1 <= pointsCol then
table.insert(msvrt,pt)
table.insert(msvrt,points[x][y-1])
table.insert(msvrt,points[x+1][y-1])
end
else
table.insert(msvrt,pt)
table.insert(msvrt,points[x][y-1])
table.insert(msvrt,points[x-1][y])
end
end
end
end
ms.vertices = msvrt
end
function rndh(x,y)
maxX = {}
print(y.." recieved as y")
for ycoord, localRow in ipairs(points) do
for xcoord, val in pairs(localRow) do
maxY = ycoord
maxX[ycoord] = xcoord
end
end
print(table.concat(maxX, "_"))
neighborHeights = {}
if x > 1 then
table.insert(neighborHeights,math.floor(points[y][x-1].y))
end
if x < maxX[y] then
table.insert(neighborHeights,math.floor(points[y][x+1].y))
end
if y > 1 then
if x < maxX[y-1] then
table.insert(neighborHeights,math.floor(points[y-1][x].y))
end
end
if y < maxY then
-- if not maxX[y+1] == nil then
if x < maxX[y+1] then
table.insert(neighborHeights,math.floor(points[y+1][x].y))
end
--  end
end
for i, nbrHeight in ipairs(neighborHeights) do
if i >1  then
if neighborHeights[i-1] > nbrHeight then
nbrHeight = math.random(nbrHeight,neighborHeights[i-1])
elseif nbrHeight > neighborHeights[i-1] then
nbrHeight = math.random(neighborHeights[i-1],nbrHeight)
else
nbrHeight = math.random(nbrHeight,neighborHeights[i-1]+1)
end
table.remove(neighborHeights, i-1)
end
end
return neighborHeights
--[[
if not points[y][x-1] == nil then        --INSERT THE EXISTING VALUES IN A TABLE
limx1 = math.floor(0)
else
limx1 = math.floor(points[y][x-1].y)
end
if points[y][x+1]==nil then
limx2 = math.floor(0)
else
limx2 = math.ceil(points[y][x+1].y)
end
if points[y-1][x]==nil then
limy1 = math.floor(0)
else
limy1 = math.floor(points[y-1][x].y)
end
if points[y+1][x]==nil then
limy2 = math.floor(0)
else
limy2 = math.ceil(points[y+1][x].y)
end

if limx1 >= limx2 then
limx = math.floor(math.random(limx2,limx1))
elseif limx2 > limx1 then
limx = math.floor(math.random(limx1,limx2))
else
limx = math.floor(math.random(limx2,limx1+1))
end
if limy1 > limy2 then
limy = math.floor(math.random(limy2,limy1))
elseif limy2 > limy1 then
limy = math.floor(math.random(limy1,limy2))
else
limy = math.floor(math.random(limy2,limy1+1))
end
if limx > limy then
return math.random(limy,limx)
elseif limy > limx then
return math.random(limx,limy)
else
return math.random(limy,limx+1)
end
]]
end

``````
• Posts: 116

You are just too fast @Ignatz If not fractals then, maybe... recursive things?
I invented own things just because i didnt know anything about noise or other algorithms for this

• Posts: 5,396

You shouldn't need to do recursion with noise. I generate terrain with just one pass. I find that using lighting and averaging the normals creates a nice rounded effect without a lot of vertices. See here..

https://coolcodea.wordpress.com/2015/08/05/221-world-of-warships-4/

This might also interest you.

https://coolcodea.wordpress.com/2014/09/23/165-playing-with-noise-and-tiling-images/

There's been quite a lot posted on the forum about terrain, including infinite terrain that goes on forever....

Sign In or Register to comment.