Howdy, Stranger!

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

descriptions somewhere on terrain gen?

john's example is great, but with no real description of the generate sequences and use of noise, they're daunting.

i'm wondering if there is prior art somewhere that would provide me some help?

thanks!

Comments

  • edited February 29 Posts: 1,605
    @RonJeffries - what have you got in mind? There are several examples of terrain generation in the forum. In the early days built on meshes. Now we've got Craft you can find a couple of simple examples from @dave1707 with tiling.

    I'd like to know how to display a portion of a mesh and scroll it infinitely.

    Also there are some examples for generating terrain height maps.

    Are you talking voxel terrains here or something like the textured sphere @John's Craft example.
  • voxel. i'll look for some simpler examples i guess.

  • didn't find much that hit me just right, but got some ideas from searching here.

    i was really looking for some background info on noise-controlled terrain, to get the drift. john's stuff is great, but takes a lot of teasing and decoding to grok.

    thanks!

  • JohnJohn Admin Mod
    Posts: 603

    Hi @RonJeffries this is the blog post that I based my terrain generation on:
    http://accidentalnoise.sourceforge.net/minecraftworlds.html

    This shows how it works in 2D. My terrain is a bit more complicated (rivers, trees, etc) but it should give you an idea of how to get started. The noise system I use is also based on the same thing.

  • Posts: 496

    thanks!

  • Posts: 496

    @john let me add that i read a lot of other folks' code, and much of it is pretty terrible. in contrast, yours is a delight to read: your skill is obvious. very good contributions! thanks!

  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries Come on Ron, give everyone a break. The people writing code here aren’t getting paid to do it. Most of them haven’t had that much experience writing code either. The ones that do have experience, myself included, write code in a matter of minutes to give examples to those asking questions, yourself included. So yes, a lot of the code here is terrible. But it gets the job done which is the whole point of this forum. Just giving you a rough time, and yes a lot of the code is terrible, mostly mine.

  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries Heres an example using Craft and perlin noise. If you zoom in, it looks like a very dense city. You can increase the value of waterLevel to raise the water to cut down on the number of buildings.

    displayMode(FULLSCREEN)
    
    function setup()
        assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
        scene = craft.scene()    
        v=scene.camera:add(OrbitViewer,vec3(200,50,0), 300, 0, 10000)
        v.rx=30
        scene.sun.rotation = quat.eulerAngles(25, 125, 0)
        scene.ambientColor = color(127, 127, 127, 255)       
        blockSet()
        scene.voxels:resize(vec3(30,1,30))          
        scene.voxels.coordinates = vec3(200,0,200)      
        val=200
        step=.42
        m=1/step
        h=craft.noise.perlin()
        waterLevel=0    
        for x=1,val,step do
            for z=1,val,step do  
                y=math.abs(h:getValue(x,0,z))
                scene.voxels:fill("DirtGrass")
                scene.voxels:box(x*m//1,0,z*m//1, x*m//1,y*10//1,z*m//1)
                scene.voxels:fill("Water")
                scene.voxels:box(x*m//1,0,z*m//1,x*m//1,waterLevel,z*m//1)
            end
        end
    end
    
    function update(dt)
        scene:update(dt)
    end
    
    function draw()
        update(DeltaTime)
        scene:draw()
    end
    
    function blockSet()    
        scene.voxels.blocks:addAssetPack("Blocks")
        dirtgrass = scene.voxels.blocks:new("DirtGrass")
        dirtgrass.setTexture(ALL, "Blocks:Dirt Grass")
        water = scene.voxels.blocks:new("Water")
        water.setTexture(ALL, "Blocks:Water")
    end
    
  • Posts: 496

    @dave1707 All the code I've seen here is good, and John's is the best. I review other people's code as part of the courses and training I do, and it is that code I'm referring to as not very good. Code written by professional programmers, working for high pay, for corporations, and it doesn't begin to measure up to what I see here. And John's is notably good.

    I'm sorry that I didn't make clear that I wasn't talking about any code I've seen here. I should add that I've always found your examples to be quite clear. John's big examples are huge and quite well structured. I'd be proud to write anything that clear, and wish I knew anywhere near what you and other contributors here know.

    Again, I'm sorry for giving the wrong impression.

  • Posts: 496

    And thanks for that example, I'll try it as soon as I'm back on an iPad. Particularly kind of you since you though I had just dissed you. Again, I apologize for expressing myself so poorly!

  • Posts: 496

    Yes, needed to charge the iPad before tomorrow, so ran your little thing. Saved me writing something very similar tomorrow, I can move directly to whatever's next. Except I'll probably write it anyway because I'm weird that way.

    The articles John pointed to handed me a few concepts that helped me understand much of what's going on with the combiners and such. Plus the articles are interesting in their own right. Some of them make clear what amazing things people are doing in the GPUs.

    I come from the era where we drew stuff on the face of an oscilloscope ... it was a big deal to get a machine that had a little graphics language to drive the beam around :)

    Thanks again!

  • edited March 2 Posts: 496

    Here's a question tho: why 0.42? and what does scene.voxels.coordinates do?

    Thanks,

    R

  • dave1707dave1707 Mod
    edited March 2 Posts: 8,193

    @RonJeffries I never thought you dissed me, I was just kidding you. I guess I wasn’t clear myself. As to the .42, it was just a number I picked. When working with perlin noise, you have to stay away from all integer x,y,z values, those always return 0. I was just picking a step value to stay away from hitting an integer.

  • edited March 2 Posts: 496

    ah :) ok good, i hate to ever offend anyone unintentionally :)
    hmm and why doesn't that loop draw a square instead of a circular disk?

  • dave1707dave1707 Mod
    Posts: 8,193

    @Simeon i noticed that Codea crashes if I use an octaves value of 0 or greater than 30 with perlin noise. There’s nothing in the docs that give a limit for octaves. Just wondering if other things will crash Codea with noise. I don’t know what’s easier, updating the docs to put limits on everything or modify Codea not to crash.

  • SimeonSimeon Admin Mod
    Posts: 5,202

    Hmm it definitely shouldn't crash. Good catch, I'll note this down and try to see what's going on with those values

  • Posts: 496

    fiddled a bunch and still not clear on why @dave1707 's program draws a disc instead of a square ... guessing this morning that there is a default voxels.radius set? when voxels.coordinates is used, does that affect what's drawn, and if so, in what way?

    i feel I'm missing a manual somewhere. :)

    Thanks!

    R

  • edited March 2 Posts: 1,605

    @RonJeffries - I think it's just using Perlin Noise to get a curve to define the shape and applying two sets of cubes - one as a flat plain with zero y and one with the actual box structure - they only differ in the y2 max coordinate for the craft.box definition.

    I assume val at 200 is the box size.

    I'd need to play around with it a bit more to be sure - but iPad on charge at the moment.

  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries From what I understand about the terrain stuff is the terrain is a circle or sphere based on the size you specify with voxels:resize. If you say resize(1,1,1) then the terrain area is 16x, 128y, 16z. If you say resize(5,1,5) then it’s 80x, 128y, 80z. The voxels.coordinates(x,y,z) places the center of the terrain at those coordinates. Not sure why it’s a circle (sphere) instead of a cube. I’m kind of playing with this stuff now, so I’m not 100% sure about what I’m saying. As for the prelim noise, at any x,y,z position you get some value. Think of a football field. Each point on the field gives some value. In my example I use that value to calculate a height (y) that I make the cubes at the x,0,z coordinates. So you get a lumpy area on the terrain that makes it look like a dense city.

  • Posts: 496

    I'm guessing that the radius value is controlling the round look. Just guessing.

    Reading the voxel terrain example of @John I see a setBounds(a,b) (in blend2D) that is not defined in the docs. I see (in flatten) that noise.scale takes x, y, z, presumably the scale. I don't know if that could have been set with the usual setX operations or not. It's not documented.

    I'd love to understand this well enough to help document it but so far I'm still at sea.

    ALSO I've seen at least one case of changing the code without effect (commented out tree generation only to see trees appear in the next run). The run after that, no changes, also no trees. As if the module was cached or didn't compile. Something cached in voxels and not cleared?

  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries Heres something I’m using to try and understand the terrain area.
    Change the values of size, rad, posX,posZ to see what happens. I draw a brown grid and also a blue line along the x and z axis. Depending on the visible radius and terrain size, parts of the grid and axis will show.

    displayMode(FULLSCREEN)
    
    function setup()
        fill(255)
        assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
        scene = craft.scene()    
        v=scene.camera:add(OrbitViewer,vec3(200,100,0), 600, 0, 10000)
        v.rx=45
    
        scene.voxels.blocks:addAssetPack("Blocks")
        dirtgrass = scene.voxels.blocks:new("DirtGrass")
        dirtgrass.setTexture(ALL, "Blocks:Dirt Grass")
        water = scene.voxels.blocks:new("Water")
        water.setTexture(ALL, "Blocks:Water") 
    
        size=30
        rad=13
        posX,posZ=200,200
    
        scene.voxels.visibleRadius=rad        -- visible terrain radius (rad * 16)
        scene.voxels:resize(vec3(size,1,size))  -- terrain area (size*16, 128, size*16)
        scene.voxels.coordinates = vec3(posX,0,posZ)  -- center of terrain area 
    
        scene.voxels:fill("DirtGrass")    
        for x=0,500,10 do   -- draw a grid of 500x500 blocks every 10 blocks
            scene.voxels:line(x,0,0,x,0,500)
            scene.voxels:line(0,0,x,500,0,x)
        end
    
        scene.voxels:fill("Water")    
        scene.voxels:line(0,0,0,500,0,0)    -- draw a blue line of blocks along the x axis
        scene.voxels:line(0,0,0,0,0,500)    -- draw a blue line of blocks along the y axis
    end
    
    function update(dt)
        scene:update(dt)
    end
    
    function draw()
        update(DeltaTime)
        scene:draw()
        text("Terrain Size   "..size.." * 16 = "..size*16,WIDTH/2,HEIGHT-25)
        text("Visible Radius "..rad.." * 16 = "..rad*16,WIDTH/2,HEIGHT-50)
        text("Center at   "..posX.." , "..posZ,WIDTH/2,HEIGHT-75)
    end
    
  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries Heres another version. Change the values for offset and waterLevel to see different things.

    displayMode(FULLSCREEN)
    
    function setup()
        assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
        scene = craft.scene()    
        v=scene.camera:add(OrbitViewer,vec3(100,0,0), 300, 0, 10000)
        v.rx=30
        scene.voxels.blocks:addAssetPack("Blocks")
        dirtgrass = scene.voxels.blocks:new("DirtGrass")
        dirtgrass.setTexture(ALL, "Blocks:Dirt Grass")
        water = scene.voxels.blocks:new("Water")
        water.setTexture(ALL, "Blocks:Water")
    
        scene.voxels.visibleRadius=20
        scene.voxels:resize(vec3(30,1,30))          
        scene.voxels.coordinates = vec3(100,0,100)      
    
        offset=6
        waterLevel=2 
        val=200
        m=1/val
        h=craft.noise.perlin()
    
        xx,zz=0,0  
        for x=1,val do
            xx=xx+m
            zz=0
            for z=1,val do  
                zz=zz+m
                y=math.abs(h:getValue(xx+offset,0,zz+offset))
                scene.voxels:fill("DirtGrass")
                scene.voxels:box(x,y*50//1-5,z,x,y*50//1,z)
                scene.voxels:fill("Water")
                scene.voxels:box(x,0,z,x,waterLevel,z)
            end
        end
    end
    
    function update(dt)
        scene:update(dt)
    end
    
    function draw()
        update(DeltaTime)
        scene:draw()
    end
    
  • dave1707dave1707 Mod
    Posts: 8,193

    Here’s another version. The more I play with it, the more I understand what’s happening. Alter the values for offsetX, offsetZ, and waterLevel, grassLevel, and dirtLevel.

    displayMode(FULLSCREEN)
    
    function setup()
        assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
        scene = craft.scene()    
        v=scene.camera:add(OrbitViewer,vec3(100,0,0), 300, 0, 10000)
        v.rx=30
        sprite()
        scene.voxels.blocks:addAssetPack("Blocks")
        dirtgrass = scene.voxels.blocks:new("DirtGrass")
        dirtgrass.setTexture(ALL, "Blocks:Dirt Grass")
        water = scene.voxels.blocks:new("Water")
        water.setTexture(ALL, "Blocks:Water")
        snow = scene.voxels.blocks:new("Snow")
        snow.setTexture(ALL, "Blocks:Snow")
        grass = scene.voxels.blocks:new("Grass Top")
        grass.setTexture(ALL, "Blocks:Grass Top")
    
        scene.voxels.visibleRadius=20
        scene.voxels:resize(vec3(30,1,30))          
        scene.voxels.coordinates = vec3(100,0,100)      
    
        offsetX=3
        offsetZ=1
        dirtLevel=25
        grassLevel=10
        waterLevel=2
    
        val=200
        m=1/val
        h=craft.noise.perlin()
    
        xx,zz=0,0  
        for x=1,val do
            xx=xx+m
            zz=0
            for z=1,val do  
                zz=zz+m
                y=math.abs(h:getValue(xx+offsetX,0,zz+offsetZ))*50//1
                if y>dirtLevel then
                    scene.voxels:fill("Snow")
                    scene.voxels:block(x,y,z)
                elseif y>grassLevel then
                    scene.voxels:fill("DirtGrass")
                    scene.voxels:block(x,y,z)
                elseif y>waterLevel then
                    scene.voxels:fill("Grass Top")
                    scene.voxels:block(x,y,z)
                else
                    scene.voxels:fill("Water")
                    scene.voxels:block(x,waterLevel,z)
                end
            end
        end
    end
    
    function update(dt)
        scene:update(dt)
    end
    
    function draw()
        update(DeltaTime)
        scene:draw()
    end
    
  • Posts: 496

    verrrry interesting ... are you seeing any pattern in what the offsets do? i've not discerned one. and your city-scape one was so flat with no noticeable continuity ...
    have you words yet for what you're seeing?

  • Posts: 496

    ah.,if i do small offsets (a few 200ths) i can see the land slide over a bit. larger offsets are obvs sampling different areas, but i've not seen the pattern. hmm ...

  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries Perlin noise is like static on an old TV screen except it’s always the same pattern for the same area. The output value is 0 for integer values of x,y,z . For fractional positions between integer values, you’ll always receive the same output, some plus or minus value, for the same input. So there will be a pattern over a large area.

  • Posts: 496

    ah, i see, didnt grok the xx zz. an integer change in offset samples a whole 'nother map, and we're staying very close to home.

  • Posts: 496

    fun to fiddle with octaves etc now. nice, thanks, i think this will put some of john's example into perspective. and i reckon generate can be considered nearly independently for threading and scale. probably. :)

  • dave1707dave1707 Mod
    edited March 2 Posts: 8,193

    @RonJeffries Heres an example that shows perlin noise over an area. I’m using the absolute value from the perlin noise function. The darker the area, the closer it’s value to zero. The brighter the area, the higher the value. Slide the offset parameter to move the perlin area to the left.

    displayMode(STANDARD)
    
    function setup()
        parameter.integer("offset",0,50)
        val=5
        step=.2
        n=craft.noise.perlin()
    end
    
    function draw()
        background(0)
        for x=-val,val,step do
            for z=-val,val,step do
                y=n:getValue(x+offset,0,z)  
                y=math.abs(y)  
                fill(y*255)
                rect(x*80+WIDTH/2,z*80+HEIGHT/2,20)
            end
        end
    end
    
  • Posts: 496

    thanks, interesting ...

  • Posts: 496

    @dave1707

    The output value is 0 for integer values of x,y,z

    If I'm not mistaken, that's true with frequency 0.5, the apparent default. A frequency like 0.73 or similar rando seems to have values at integer positions.

    Most confusing, but slowly he learned ...

    Slowly I learned ... step by step ... inch by inch ...

    R

  • dave1707dave1707 Mod
    Posts: 8,193

    @RonJeffries Here something to play with. The output is 0 when the x,y,z values are integer values and multiples of 2.

    displayMode(STANDARD)
    
    function setup()
        fill(255)
        parameter.number("x",0,4,0)
        parameter.number("y",0,4,0)
        parameter.number("z",0,4,0)
        n = craft.noise.perlin()
    end
    
    function draw()
        background(0)
        value = n:getValue(x,y,z)
        text(value,WIDTH/2,HEIGHT/2)
    end
    
  • Posts: 496

    yes, but now fuddle with n.frequency!

Sign In or Register to comment.