Howdy, Stranger!

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

In this Discussion

Quick Query

in Codea Craft Posts: 2,728

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?

Comments

  • dave1707dave1707 Mod
    Posts: 10,055

    @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
    
  • Posts: 2,728
    @dave1707 - thanks for that should be just what the doctor ordered. Will feed back when I've had chance to play with it.
  • dave1707dave1707 Mod
    Posts: 10,055

    @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
    
  • dave1707dave1707 Mod
    edited June 22 Posts: 10,055

    @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
    
  • Posts: 2,728
    @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.
  • dave1707dave1707 Mod
    Posts: 10,055

    @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.

  • edited June 22 Posts: 2,728
    @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.
  • dave1707dave1707 Mod
    edited June 22 Posts: 10,055

    @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
    
  • dave1707dave1707 Mod
    Posts: 10,055

    @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
    
  • edited June 23 Posts: 2,728
    @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.
Sign In or Register to comment.