Making a subdivided mesh?

I’m working on a cloth simulation and I want to make a mesh that follows the simulation points. My idea is to make a mesh and use addRectangle to make each polygon tile, but there are up to 4 overlapping vertices on the tile corners and I wonder if there is another way to set up the mesh so polygons share vertices, or if that’s impossible?

It would make getting the indexes of the mesh.vertices a lot easier, now I need to set multiple vertices to one position and it seems a bit weird and unwieldy. I guess I can use a 2d array to group the vertices that share a position, but I’m hoping there’s a way for polys to share points?

@Kirl I tried doing a mesh on my cloth example, but I liked the way it looked without the mesh better. Here’s a link to my original cloth example. I used the triangulate function, but I didn’t save the code.

https://codea.io/talk/discussion/6492/cloth-example

@Kirl - AFAIK, there’s no way to avoid setting individual vertex positions, even if several of them share the same position.

Because vector operations are slow in Codea, I might try

  1. storing the unique vertex positions in a table V
  2. creating a mesh where (say) only the x value is used for each vertex, to store the index number of each vertex in the table V
  3. using a shader, and giving it an array of current vertex positions. The vertex shader can use the x value of each mesh vertex to look up the current position in the array and assign it

I don’t know if this is faster, though.

Another option may be to only recalculate vertex positions every X frames, and interpolate between them (perhaps using a shader for speed).

@Kirl Heres my cloth example where I use mesh instead of lines. When I use lines, the fps is about 10, with mesh it’s about 50. I’m using random colors for each mesh. I guess I could use a single image and break it down into all the meshes. In this one, I use 2 triangles per rectangle.

EDIT: In setup, with a CIRCLE size of 0, the cloth passes thru itself. Increasing the size of CIRCLE makes the cloth act stiffer and prevents it from passing thru itself.

EDIT: I wasn’t expecting this to run this fast since I was recalculating the mesh values each draw cycle.

displayMode(FULLSCREEN)
supportedOrientations(PORTRAIT_ANY)

function setup()
    x1=20
    y1=30
    size=30
    dx,dy=0,0
    tab={}
    for x=1,x1 do
        tab[x]={}
        for y=1,y1 do
            local r=physics.body(CIRCLE,0)
            r.x=100+x*size
            r.y=HEIGHT-50-y*size
            r.gravityScale=.5
            if y==1 then
                r.type=STATIC
            end           
            tab[x][y]=r
            r=nil
        end
    end
    jVert={}
    for x=1,x1 do
        for y=2,y1 do
            local j=physics.joint(ROPE,tab[x][y-1],tab[x][y],
                tab[x][y-1].position,tab[x][y].position,size)
            table.insert(jVert,j)
            j=nil
        end
    end
    jHorz={}
    for x=2,x1 do
        for y=1,y1 do
            local j=physics.joint(ROPE,tab[x-1][y],tab[x][y],
                tab[x-1][y].position,tab[x][y].position,size)
            table.insert(jHorz,j)
            j=nil
        end
    end    
end

function draw()
    background(192, 225, 208, 255)
    stroke(0, 161, 255, 255)
    strokeWidth(2)
    mTab={}
    for x=1,x1 do
        for y=1,y1 do
            if x>1 and y>1 then
                table.insert(mTab,vec2(tab[x][y-1].x,tab[x][y-1].y))
                table.insert(mTab,vec2(tab[x-1][y-1].x,tab[x-1][y-1].y))
                table.insert(mTab,vec2(tab[x-1][y].x,tab[x-1][y].y))                
                table.insert(mTab,vec2(tab[x][y-1].x,tab[x][y-1].y))
                table.insert(mTab,vec2(tab[x-1][y].x,tab[x-1][y].y))
                table.insert(mTab,vec2(tab[x][y].x,tab[x][y].y))               
            end
        end
    end  
    m=mesh()
    m.vertices=mTab
    setColors()
    m.colors=cols  
    setColors()    
    m:draw()
    stroke(255,0,0)
    fill(255,0,0)
    ellipse(tab[1][1].x,tab[1][1].y,10)
    text("Cloth example",WIDTH/2,HEIGHT-10)
    text("Slide your finger to move the red dot",WIDTH/2,HEIGHT-40)
    text("Rate  "..1//DeltaTime,WIDTH/2,HEIGHT-70)
end

function touched(t)
    if t.state==MOVING then
        for z=1,x1-1 do
            tab[z][1].type=DYNAMIC
        end
        dx=dx+t.deltaX*200
        dy=dy+t.deltaY*200
        tab[1][1].linearVelocity=vec2(dx,dy)
    end
    if t.state==ENDED then
        dx,dy=0,0
        tab[1][1].type=STATIC
        collectgarbage()
    end    
end

function setColors()
    if cols==nil then
        cols={}
        for z=1,#mTab,6 do
            col=vec4(math.random(),math.random(),math.random(),1)
            for q=1,6 do
                table.insert(cols,col)
            end
        end
    end
end

Here’s the cloth example using an image. The image is upsidedown because of the way I originally did the cloth.

EDIT: I changed the code to correct the image.

EDIT: Changed the code to use mesh buffer.

displayMode(FULLSCREEN)
supportedOrientations(PORTRAIT_ANY)

function setup()
    x1=20
    y1=30
    local tTab={} 
    local xs=1/(x1-1)
    local ys=1/(y1-1)
    for x=0,x1-2 do
        for y=0,y1-2 do
            table.insert(tTab,vec2(x*xs,y*ys))
            table.insert(tTab,vec2(x*xs+xs,y*ys))
            table.insert(tTab,vec2(x*xs+xs,y*ys+ys))            
            table.insert(tTab,vec2(x*xs,y*ys))
            table.insert(tTab,vec2(x*xs,y*ys+ys))
            table.insert(tTab,vec2(x*xs+xs,y*ys+ys))
        end
    end
    local size=30
    dx,dy=0,0
    tab={}
    for x=1,x1 do
        tab[x]={}
        for y=y1,1,-1 do
            local r=physics.body(CIRCLE,0)
            r.x=100+x*size
            r.y=y*size
            r.gravityScale=.5
            if x==1 and y==y1 then
                r.type=STATIC
            end 
            if y==y1 then 
                r.type=STATIC
            end
            tab[x][y]=r
            r=nil
        end
    end
    jVert={}
    for x=1,x1 do
        for y=2,y1 do
            local j=physics.joint(ROPE,tab[x][y-1],tab[x][y],
                tab[x][y-1].position,tab[x][y].position,size)
            table.insert(jVert,j)
            j=nil
        end
    end
    jHorz={}
    for x=2,x1 do
        for y=1,y1 do
            local j=physics.joint(ROPE,tab[x-1][y],tab[x][y],
                tab[x-1][y].position,tab[x][y].position,size)
            table.insert(jHorz,j)
            j=nil
        end
    end  
    m=mesh()
    m.texCoords=tTab
    m.texture="Cargo Bot:Startup Screen"   
    m.vertices=tTab
    buf=m:buffer("position")
end

function draw()
    background(192, 224, 225, 255)
    stroke(0, 161, 255, 255)
    strokeWidth(2)
    local n=1
    for x=1,x1-1 do
        for y=1,y1-1 do
            buf[n]=vec2(tab[x][y].x,tab[x][y].y)
            buf[n+1]=vec2(tab[x+1][y].x,tab[x+1][y].y)
            buf[n+2]=vec2(tab[x+1][y+1].x,tab[x+1][y+1].y)                              
            buf[n+3]=vec2(tab[x][y].x,tab[x][y].y)
            buf[n+4]=vec2(tab[x][y+1].x,tab[x][y+1].y)
            buf[n+5]=vec2(tab[x+1][y+1].x,tab[x+1][y+1].y) 
            n=n+6           
        end
    end  
    m:draw()
    pushStyle()
    stroke(255,0,0)
    fill(255,0,0)
    ellipse(tab[1][y1].x,tab[1][y1].y,10)
    text("Cloth example",WIDTH/2,HEIGHT-10)
    text("Slide your finger to move the red dot",WIDTH/2,HEIGHT-40)
    text("Rate  "..1/DeltaTime//1,WIDTH/2,HEIGHT-70)
    text("KB Memory used  "..collectgarbage("count")//1,WIDTH/2,HEIGHT-100)
    popStyle()
end

function touched(t)
    if t.state==MOVING then
        for z=1,x1-1 do
            tab[z][y1].type=DYNAMIC
        end
        dx=dx+t.deltaX*200
        dy=dy+t.deltaY*200
        tab[1][y1].linearVelocity=vec2(dx,dy)
    end
    if t.state==ENDED then
        dx,dy=0,0
        tab[1][y1].type=STATIC
    end    
end

Thanks guys, looking cool dave, very well done!
I don’t want to redefine the mesh every frame but rather try to set the vertex positions using mesh:vertex(). The help mentions this is more efficient for setting a subset of vertices, I’m hoping the same is also true when setting all vertices. After seeing your example however, I had to go ahead and just try it as well. :slight_smile:

@Ignatz
Can you elaborate on your idea? Do you mean setting the vertex positions with a shader? I’ve been experimenting with shaders a little bit but never actually passed a value or did anything other than simple color adjustments.

@Kirl I made these changes to my code. I moved the code for mesh, texCoords, and texture out of draw() and into setup(). I left vertices and draw in draw() and the code runs OK.

    -- moved to setup
    m=mesh()
    m.texCoords = tTab
    m.texture = "Cargo Bot:Startup Screen"    
    -- still in draw
    m.vertices=mTab
    m:draw()

@kirl - you can redefine vertex positions “in place” inside the mesh using the position buffer.

Have a look for buffer in the mesh reference, there is an example there.

On reflection, I’m not sure a shader will help, because whichever way you do it, you have to set a whole bunch of vertices.

Here is how the draw function in dave’s example would look, assuming you had set up a mesh m, in setup.

    mTab=m:buffer("position")
    n=1
    for x=1,x1-1 do
        for y=1,y1-1 do
            --if x<x1 and y<y1 then
                mTab[n]=vec2(tab[x][y].x,tab[x][y].y)
                mTab[n+1]=vec2(tab[x+1][y].x,tab[x+1][y].y)
                mTab[n+2]=vec2(tab[x+1][y+1].x,tab[x+1][y+1].y)                              
                mTab[n+3]=vec2(tab[x][y].x,tab[x][y].y)
                mTab[n+4]=vec2(tab[x][y+1].x,tab[x][y+1].y)
                mTab[n+5]=vec2(tab[x+1][y+1].x,tab[x+1][y+1].y) 
            n=n+6           
            --end
        end
    end  

@Ignatz I modified my code above to use the mesh buffer which increased the fps.

Thanks a ton guys! I still seem to have the uv’s meshed up, because the images appear upside down. Needs more fiddling, but I’m nearly there. Thanks for the help! :slight_smile: