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[1] = {0,200}
    heights[2] = {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[1] = {h11,h12}
    heights[2] = {h21,h22}
end

Comments

  • IgnatzIgnatz Mod
    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[1] = {0,0}
        heights[2] = {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[1] = {vec3(0,0,0),vec3(250,125,0),vec3(500,250,0)}
        points[2] = {vec3(0,125,250),vec3(250,250,250),vec3(500,375,250)}
        points[3] = {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[2],pts[4],pts[1],
                        pts[2],pts[4],pts[5],
                        pts[2],pts[6],pts[3],
                        pts[2],pts[6],pts[5],
                        pts[4],pts[8],pts[7],
                        pts[4],pts[8],pts[5],
                        pts[6],pts[8],pts[9],
                        pts[6],pts[8],pts[5]}
        msvrt ={points[1][2],points[2][1],points[1][1],
                points[1][2],points[2][1],points[2][2],
                points[1][2],points[2][3],points[1][3],
                points[1][2],points[2][3],points[2][2],
                points[2][1],points[3][2],points[3][1],
                points[2][1],points[3][2],points[2][2],
                points[2][3],points[3][2],points[3][3],
                points[2][3],points[3][2],points[2][2],}
        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[1]
        --[[
        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 :D
    If not fractals then, maybe... recursive things?
    I invented own things just because i didnt know anything about noise or other algorithms for this

  • IgnatzIgnatz Mod
    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.