Procedurally Creating Objects

I understand creating objects one by one, but I can’t seem to understand how to create objects in bulk. From what I’ve looked at, you need a table to tell all the objects of a class apart, but that’s as far as I can understand…

@MalikWilburn If you know how to create an object and you know they go in tables then you’re 99% of the way there. Here’s an example of creating Craft spheres. You can create a single or multiple spheres without a table, but if you want to modify something about them, then you need a table. He an example of creating a single or multiple spheres, and then multiple spheres using a table. Then using the spheres in the table, I’m changing their colors.

displayMode(FULLSCREEN)

function setup()
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")        
    scene = craft.scene()
    skyMaterial=scene.sky.material
    skyMaterial.sky=color(158, 202, 223, 255)
    skyMaterial.horizon=color(98, 166, 114, 255)
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 200, 0, 1000)

    -- create a single sphere
    createSphere(vec3(0,0,0),3)

    -- create multiple spheres without a table
    for z=1,20 do
        createSphere(vec3(math.random(-50,50),
            math.random(-50,50),math.random(-50,50)))       
    end

    -- create multiple spheres using a table
    tab={}
    for z=1,20 do
        table.insert(tab,createSphere(vec3(math.random(-50,50),
            math.random(-50,50),math.random(-50,50))))      
    end
end

function draw()
    update(DeltaTime)
    scene:draw()
end

function update(dt)
    scene:update(dt)
    
    -- change the sphere colors using the spheres in the table
    for z=1,#tab do
        tab[z].material.diffuse=color(math.random(255),
            math.random(255),math.random(255))
    end
end

function createSphere(p)
    local pt=scene:entity()
    pt.position=vec3(p.x,p.y,p.z)
    pt.model = craft.model.icosphere(3,2)
    pt.material = craft.material("Materials:Specular")
    pt.material.diffuse=color(255,0,0)
    return(pt)
end

@dave1707 - very impressive, but I have a problem just with spheres - on how to texture a single sphere. That is wrap in 3D rather than tile. Looking at the documentation for craft I’m sure I saw a command for unwrapping an object, say an icosahedron, but I can’t seem to locate it now. All I can find is

u, v = myModel:uv( index )
myModel:uv( index, p )
myModel:uv( index, u, v )

I’d like to be able to take a Craft icosphere and texture it or build up my own sphere vertices list and texture it as a Craft object.

Any ideas?

@Bri_G I haven’t tried wrapping a craft sphere yet. I’ll look into it later. Maybe one of the Craft examples has something.

@dave1707 - there is an example in theCraft demos (World Generator) but it involves exagerated terra forming for the texture, superb but way out of my league. May be able to pick out the basics so will revisit it.

@Bri_G My MeshExt class has a sphere creator which uses a standard texture mapping. I’ve used it to create star backgrounds and planets. I can dig up some code if you’re interested.

@LoopSpace - thanks for the offer, if you have something I’d be very interested. I am currently using JMV38s planet creator which is great. Anyone interested in an excellent tutorial should chase it up. He has both simple and optimised models together with shadow.

My main interest is in using it alongside Craft, I think it’s a case of integrating the planet model produced with the Craft Scene.

Looking to produce a video of what I’m doing but don’t hold your breath.

I’ll check out your MeshExt class - thanks for the pointer.

@Bri_G Here’s a texture example that I created from a sphere example I posted long ago. I couldn’t find my original post, it must be in someone else’s discussion. This doesn’t use Craft, that’s something I’ll have to try later. The texture image should be twice as wide as it is high so that it doesn’t appear stretched. I created a texture example that is the correct size, but the other texture examples aren’t. Slide the image slider for the other examples and the Dist slider to move in or out. You can also move the Angle X or Y slider.

function setup()
    myTexture=image(1024,512)
    setContext(myTexture)
    background(170, 198, 223, 255)
    fill(0, 19, 255, 255)
    fontSize(40)
    text("This is my texture example, move image slider for more.",512,256)
    fill(255,0,0)
    ellipse(300,128,100,50)
    fill(0,255,0)
    ellipse(900,128,50,100)
    fill(255,255,0)
    rect(640,320,128,64)
    stroke(0)
    strokeWidth(3)
    for z=0,1024,64 do
        line(z,0,z,512)
    end
    for z=0,512,32 do
        line(0,z,1024,z)
    end
    setContext()
    
    img={myTexture,"Cargo Bot:About Info Panel","Cargo Bot:Cargo Bot Title",
        "Cargo Bot:Startup Screen","Surfaces:Desert Cliff Color",
        "Surfaces:Desert Cliff Height","Surfaces:Basic Bricks Roughness",
        "Surfaces:Stone Brick Height","Environments:Sunny Up"}
    level=50
    parameter.number("AngleX",0,360,90)
    parameter.number("AngleY",0,360,180) 
    parameter.integer("Dist",300,1500,600)
    parameter.integer("image",1,#img,1)
    AngleZ=180
    tex,vert,tab={},{},{}
    radius=100
    M,N=level,level
    -- calculate sphere points
    for n=0,N do
        tab[n]={}
        for m=0,M do
            x=radius * math.sin(math.pi * m/M) * math.cos(2*math.pi * n/N)
            y=radius * math.sin(math.pi * m/M) * math.sin(2*math.pi * n/N)
            z=radius * math.cos(math.pi * m/M)
            tab[n][m]=vec3(x,y,z)
        end
    end
    hor=0
    ad=1/level
    -- calculate vertices and texcoord from sphere points
    for n=0,N-1 do
        ver=1
        for m=0,M-1 do
            table.insert(vert,tab[n][m])
            table.insert(vert,tab[n][m+1])
            table.insert(vert,tab[n+1][m+1])  
            table.insert(vert,tab[n][m])
            table.insert(vert,tab[n+1][m])
            table.insert(vert,tab[n+1][m+1])
            table.insert(tex,vec2(hor,ver+ad))
            table.insert(tex,vec2(hor,ver))
            table.insert(tex,vec2(hor+ad,ver))
            table.insert(tex,vec2(hor,ver+ad))
            table.insert(tex,vec2(hor+ad,ver+ad))
            table.insert(tex,vec2(hor+ad,ver))
            ver=ver-ad
        end
        hor=hor+ad
    end
    sphere=mesh()    
    sphere.vertices=vert
    sphere.texCoords=tex
    sphere:setColors(255,255,255,255)   
end

function draw()  
    background(223, 211, 142, 255)
    sprite(img[image],150,150,200)
    perspective()
    camera(Dist,0,0,0,0,0,0,1,0)
    rotate(AngleX,1,0,0)
    rotate(AngleY,0,1,0)
    rotate(AngleZ,0,0,1)
    sphere.texture=img[image]
    sphere:draw()
    AngleZ=AngleZ-.3
end

@dave1707 - thanks for the code, that’s a very neat example. I’ve started playing around with it and using it for texture viewing now. Hope I can link this into Craft somehow.

@Bri_G I don’t think it can be used with Craft. Run this code to see how an icosphere is created. My code creates a sphere made up of rectangles and then splits the rectangle into 2 triangles to be used by mesh. Think of latitude, longitude rectangles. The icosphere is made up of triangles, but the triangles don’t make a bunch of rectangles. That means it wouldn’t match up to a rectangular texture map. So at this point I don’t know how to map it.

displayMode(FULLSCREEN)

function setup()
    assert(craft, "Please include Craft as a dependency")
    assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")        
    scene = craft.scene()
    skyMaterial=scene.sky.material
    skyMaterial.sky=color(158, 202, 223, 255)
    skyMaterial.horizon=color(98, 166, 114, 255)
    scene.sun.rotation=quat.eulerAngles(20,45,-30)
    v=scene.camera:add(OrbitViewer, vec3(0,0,0), 100, 0, 1000)
    v.rx=0
    v.ry=-88
    createSphere(vec3(0,0,0))
end

function draw()
    update(DeltaTime)
    scene:draw()
    fill(255)
end

function update(dt)
    scene:update(dt)
end

function createSphere(p)
    pt=scene:entity()
    pt.position=vec3(p.x,p.y,p.z)
    pt.model = craft.model.icosphere(30,1,true)
    pt.material = craft.material("Materials:Standard")
    pt.material.diffuse=color(255,0,0)
end

I have a vague recollection that the icosphere model doesn’t set texture coordinates so it can’t be used with a texture unless you figure out what they should be (but if you figure those out, there’d be no difference to using a regular sphere texture).

Here’s the code from my roller coaster project that creates a star sphere:

        local galaxy = PseudoMesh()
        galaxy:addSphere({radius = 100})
        galaxy:invertNormals()
        e = scene:entity()
        e.model = galaxy:toModel()
        e.material = craft.material("Materials:Basic")
        e.material.map = "Project:starmap_small"

It uses my PseudoMesh and MeshExt libraries. The texture is a star map from NASA. So, quite simple, I hope you’ll agree.