Quick Query

All - I am currently working on a project to load and display the 3D models I have in my Codea root folders.These models vary in size so I was looking into how to scale the models to fit within the screen dimensions using Craft. What I have done in the past is to create a table of numbers, corresponding to the particular model, that would scale accordingly. Building the tables up for each source folder is time consuming and needs updating occasionally.

My thoughts on improving this goes along the lines of interrogating the model when it is loaded and checking the model vertices looking for the largest dimension in the x,y,z values and deriving a factor from that and the screen size to scale accordingly so when a model loads you can display it centrally and in reasonable size.

My question is - has anyone accessed Craft model vertices? And, if so - how is that done?

@Bri_G Not sure if this is what you’re after, but it might be a start. This gives you the min, max, and center x,y,z vertices values. You can use the min, max values for the size of the model and the center value for the placement. I just threw this together, no time right now to do more.

viewer.mode=STANDARD

function setup()
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()    
    sc = scene:entity()
    sc.model = craft.model("Watercraft:watercraftPack_003")
    
    minMax()
    
    viewer = scene.camera:add(OrbitViewer, vec3(0,0,0), 30, 0, 2000)
end

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

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

function minMax()
    minX,minY,minZ=999,999,999
    maxX,maxY,maxZ=-999,-999,-999
    for a,b in pairs(sc.model.positions) do
        minX=math.min(b.x,minX)
        minY=math.min(b.y,minY)
        minZ=math.min(b.z,minZ)
        maxX=math.max(b.x,maxX)
        maxY=math.max(b.y,maxY)
        maxZ=math.max(b.z,maxZ)
    end
    print("minX "..minX)
    print("maxX "..maxX)
    print("centerX ",(minX+maxX)/2)   
    print("minY "..minY)
    print("maxY "..maxY)
    print("centerY ",(minY+maxY)/2)   
    print("minZ "..minZ)
    print("maxZ "..maxZ) 
    print("centerZ ",(minZ+maxZ)/2)   
end

@dave1707 - thanks for that should be just what the doctor ordered. Will feed back when I’ve had chance to play with it.

@Bri_G Had time to play with it more. Here’s another version, but it might need some tweaking.

viewer.mode=STANDARD

function setup()
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()    
    sc = scene:entity()
    sc.model = craft.model(asset.builtin.Watercraft.watercraftPack_027_obj)
    
    minMax()
    
    viewer = scene.camera:add(OrbitViewer, vec3(cx,cy,cz), ((sMax/WIDTH)*1500), 0, 2000)
end

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

function minMax()
    print(#sc.model.positions)
    minX,minY,minZ=999,999,999
    maxX,maxY,maxZ=-999,-999,-999
    
    -- determine min,max values
    for a,b in pairs(sc.model.positions) do
        minX=math.min(b.x,minX)
        minY=math.min(b.y,minY)
        minZ=math.min(b.z,minZ)
        maxX=math.max(b.x,maxX)
        maxY=math.max(b.y,maxY)
        maxZ=math.max(b.z,maxZ)
    end
    
    -- center values
    cx=(minX+maxX)/2
    cy=(minY+maxY)/2
    cz=(minZ+maxZ)/2
    
    -- size values
    sx=math.abs(minX)+math.abs(maxX)
    sy=math.abs(minY)+math.abs(maxY)
    sz=math.abs(minZ)+math.abs(maxZ)
    
    -- largest x,y,z size
    sMax=math.max(sx,sy)
    sMax=math.max(sMax,sz)
    
    print("minX "..minX)
    print("maxX "..maxX)
    print("centerX ",cx)   
    print("minY "..minY)
    print("maxY "..maxY)
    print("centerY ",cy)   
    print("minZ "..minZ)
    print("maxZ "..maxZ) 
    print("centerZ ",cz)   

    print("sMax "..sMax)
end

@Bri_G I don’t think the code is getting all of the position values. I think there might be multiple files for some of the models I’ve been testing. Here’s an example showing the problem. I draw a white sphere at all of the positions and on a lot of the models the spheres don’t cover everything. I have to search the forum because I think something was mentioned a one time about multiple files.

viewer.mode=STANDARD

function setup()
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()    
    sc = scene:entity()
    sc.model = craft.model(asset.builtin.Watercraft.watercraftPack_006_obj)
    
    minMax()
    
    viewer = scene.camera:add(OrbitViewer, vec3(cx,cy,cz), ((sMax/WIDTH)*1500), 0, 2000)
end

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

function minMax()
    print(#sc.model.positions)
    minX,minY,minZ=999,999,999
    maxX,maxY,maxZ=-999,-999,-999
    
    -- determine min,max values
    for a,b in pairs(sc.model.positions) do
        createSphere(b,.05)
        minX=math.min(b.x,minX)
        minY=math.min(b.y,minY)
        minZ=math.min(b.z,minZ)
        maxX=math.max(b.x,maxX)
        maxY=math.max(b.y,maxY)
        maxZ=math.max(b.z,maxZ)
    end
    
    -- center values
    cx=(minX+maxX)/2
    cy=(minY+maxY)/2
    cz=(minZ+maxZ)/2
    
    -- size values
    sx=math.abs(minX)+math.abs(maxX)
    sy=math.abs(minY)+math.abs(maxY)
    sz=math.abs(minZ)+math.abs(maxZ)
    
    -- largest x,y,z size
    sMax=math.max(sx,sy)
    sMax=math.max(sMax,sz)
    
    print("minX "..minX)
    print("maxX "..maxX)
    print("centerX ",cx)   
    print("minY "..minY)
    print("maxY "..maxY)
    print("centerY ",cy)   
    print("minZ "..minZ)
    print("maxZ "..maxZ) 
    print("centerZ ",cz)   

    print("sMax "..sMax)
end

function createSphere(p,s)
    local pt=scene:entity()
    pt.position=p
    pt.model = craft.model.icosphere(s,2)
    pt.material = craft.material(asset.builtin.Materials.Specular)
    pt.material.diffuse=color(255)
end

@dave1707 - I can’t keep up with the pace that you generate these projects. Loaded your first two and they are great, have been trying to adapt to my models. I’ll try out your third demo later this evening, will feed back my thoughts later

Do you have a degree in maths ? You seem to pick up what is needed very quickly.

@Bri_G No degree in math. I’ve always liked math and I play around with it a lot, but not at a degree level. If something is over my head, I’ll Google it and try to learn from there.

@dave1707 - see what you mean about multiple objects. The best way to build objects like that would be as parent object children. Not into that as yet but you would expect that they would be linked into the parent in some way. I think @UberGoober may have delved into parent/child modelling.

They may possibly be linked in the parent object file.

@Bri_G Here’s the correct way to get the positions of a model.

Run the code. I put a white sphere at all the position points. Uncomment the readObj line and run it again. You’ll now see all of the position points.

The first run just uses the sc.model.positions file. The second run uses the obj file.

viewer.mode=STANDARD

function setup()
    ast=asset.builtin.Watercraft.watercraftPack_001_obj
    
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()    
    sc = scene:entity()
    sc.model = craft.model(ast)

    minMax()
    --readObj()
    
    viewer = scene.camera:add(OrbitViewer, vec3(0,0,0), (20), 0, 2000)
end

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

function minMax()
    for a,b in pairs(sc.model.positions) do
        createSphere(b,.05)
    end
end

function readObj()
    str=readText(ast)
    for a,b,c in string.gmatch(str,"v (%g+) (%g+) (%g+)") do
        createSphere(vec3(a,b,c),.05)
    end  
end

function createSphere(p,s)
    local pt=scene:entity()
    pt.position=p
    pt.model = craft.model.icosphere(s,2)
    pt.material = craft.material(asset.builtin.Materials.Specular)
    pt.material.diffuse=color(255)
end

@Bri_G I think this does mostly what you want. This is the original code above, but uses the obj file instead of the positions file. This sizes and centers the models that I tried, so I think it works ok. You can uncomment the line createSphere() to see a white sphere drawn at all the position points. This gave me something to do while I avoided the high temps today, so thanks.

viewer.mode=STANDARD

function setup()

    ast=asset.builtin.Watercraft.watercraftPack_003_obj
    
    assert(OrbitViewer, "Please include Cameras as a dependency")
    scene = craft.scene()    
    sc = scene:entity()
    sc.model = craft.model(ast)
    
    minMax()
    
    viewer = scene.camera:add(OrbitViewer, vec3(cx,cy,cz), ((sMax/WIDTH)*1500), 0, 2000)
end

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

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

function minMax()
    minX,minY,minZ=999,999,999
    maxX,maxY,maxZ=-999,-999,-999
 
    -- determine min,max values
    str=readText(ast)
    for a,b,c in string.gmatch(str,"v (%g+) (%g+) (%g+)") do
        
        --createSphere(vec3(a,b,c),.05)
        
        minX=math.min(tonumber(a),minX)
        minY=math.min(tonumber(b),minY)
        minZ=math.min(tonumber(c),minZ)
        maxX=math.max(tonumber(a),maxX)
        maxY=math.max(tonumber(b),maxY)
        maxZ=math.max(tonumber(c),maxZ)
    end
    
    -- center values
    cx=(minX+maxX)/2
    cy=(minY+maxY)/2
    cz=(minZ+maxZ)/2
    
    -- size values
    sx=math.abs(minX)+math.abs(maxX)
    sy=math.abs(minY)+math.abs(maxY)
    sz=math.abs(minZ)+math.abs(maxZ)
    
    -- largest x,y,z size
    sMax=math.max(sx,sy)
    sMax=math.max(sMax,sz)
    
    print("minX "..minX)
    print("maxX "..maxX)
    print("centerX ",cx)   
    print("minY "..minY)
    print("maxY "..maxY)
    print("centerY ",cy)   
    print("minZ "..minZ)
    print("maxZ "..maxZ) 
    print("centerZ ",cz)   
    
    print("sMax "..sMax)
end

function createSphere(p,s)
    local pt=scene:entity()
    pt.position=p
    pt.model = craft.model.icosphere(s,2)
    pt.material = craft.material(asset.builtin.Materials.Specular)
    pt.material.diffuse=color(255)
end

@dave1707 - I think you’ve hit the jackpot, thanks. Will fit into my code. We’ve been getting temperatures of low 30’s (in shade) in central UK. Unpleasant for us but I bet well below your temps.

Thanks again.

P.s. I love the vertex sphereing looks like a totally different model !!! Seriously, that’s a handy tool.