Modifying Mesh Vertices


I’m using this star burst effect I created (feel free to use it if you like it) but I’ve got a feeling that my method for animating the mesh’s vertices is not optimal. Basically I’m iterating over the existing mesh.vertices, modifying each vertex and copying it into a new table, then setting mesh.vertices to the new table. See the StarburstView:update() method for that code. Is there a more efficient way? I’ve tried modifying each vertex in place (eg: mesh.virtices[i].x = whatever) as well as removing and reinserting vertices into the existing mesh.vertices table, but neither of those things seemed to work at all (it was as if mesh.vertices is immutable).

Any advice appreciated, cheers!

--# Main

-- Use this function to perform your initial setup
function setup()
    c = color(255, 103, 0, 224)
    starburstView = StarburstView(WIDTH/2, HEIGHT/2, WIDTH/1.5, 3, 20, c)

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(0, 0, 0, 255)

    -- This sets the line thickness
    fill(243, 9, 9, 255)

    -- Do your drawing here

--# StarburstView
StarburstView = class()

function StarburstView:init(x, y, radius, lifetime, numRays, colour)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.radius = radius
    self.lifetime = lifetime
    self.numRays = numRays
    self.lifetimeLeft = self.lifetime
    self.maxSwellTime = self.lifetime / 2
    self.swellRadsPerTime = math.rad(180 / self.lifetime)
    self.currentSwellRad = math.rad(0)
    local brt = 100
    self.colour = color(colour.r+brt, colour.g+brt, colour.b+brt, colour.a)
    self.colourVar = 100 -- how much the colour can vary from the original in each channel

function StarburstView:buildMesh()
    self.mesh = mesh()
    self.raySpeeds = {}
    local vertices = {}    
    local colours = {}
    for rayNum = 1, self.numRays do
        local rotation = math.rad(math.random(360))
        local rotWidth = math.rad(math.random(40))
        local rndRad = self.radius * (1+math.random())
        local v1 = vec2(0,0)
        local v2 = vec2(0, rndRad):rotate(rotation)
        local v3 = vec2(0, rndRad):rotate(rotation + rotWidth)
        table.insert(vertices, v1)
        table.insert(vertices, v2)
        table.insert(vertices, v3)
        table.insert(colours, self:randomColour())
        table.insert(colours, self:randomColour())
        table.insert(colours, self:randomColour())
    self.mesh.vertices = vertices
    self.mesh.colors = colours

function StarburstView:addRandomSpeeds(rotWidth)
    local speed = math.rad(math.random(50, 200))
    local catchupSpeed = rotWidth / self.lifetime
    table.insert(self.raySpeeds, speed + catchupSpeed) -- first edge
    table.insert(self.raySpeeds, speed) -- second edge

function StarburstView:randomColour()
    local r = self:randomColourChanel(self.colour.r)
    local g = self:randomColourChanel(self.colour.g)
    local b = self:randomColourChanel(self.colour.b)
    return color(r, g, b, 128)

function StarburstView:randomColourChanel(chanel)
    return chanel - self.colourVar + math.random(self.colourVar*2)

function StarburstView:update()
    local newVertices = {}
    for rayNum = 1, self.numRays do
        local i = ((rayNum-1) * 3) + 1
        local v1 = self.mesh.vertices[i]
        local v2 = self.mesh.vertices[i+1]
        local v3 = self.mesh.vertices[i+2]
        local j = ((rayNum-1) * 2) + 1
        local edge1Speed = self.raySpeeds[j]
        local edge2Speed = self.raySpeeds[j+1]
        v2 = v2:rotate(edge1Speed * DeltaTime)
        v3 = v3:rotate(edge2Speed * DeltaTime)
        table.insert(newVertices, v1)
        table.insert(newVertices, v2)
        table.insert(newVertices, v3)
    self.mesh.vertices = newVertices
    self.lifetimeLeft = self.lifetimeLeft - DeltaTime
    self.currentSwellRad = self.currentSwellRad + self.swellRadsPerTime * DeltaTime

function StarburstView:draw()
    if self.lifetimeLeft >= 0 then
        translate(self.x, self.y)

Looks great! Just tried it out. Very cool effect.

We’ve added the following functions in the next update. These make it more efficient to access single, or small numbers of vertices in mesh — they do not require updating the whole table and instead index the existing vertex buffer.

v = mesh:vertex( index ) -- Read vertex at indes

-- Set vertex at index
mesh:vertex( index, x, y )
mesh:vertex( index, x, y, z )
mesh:vertex( index, vec2 )
mesh:vertex( index, vec3 )

v = mesh:color( index ) -- Read color at indes

-- Set color at index
mesh:color( index, r, g, b )
mesh:color( index, r, g, b, a )
mesh:color( index, color )

v = mesh:texCoord( index ) -- Read texCoord at indes

-- Set texCoord at index
mesh:texCoord( index, x, y )
mesh:texCoord( index, vec2 )

mesh.size -- Get number of vertices in mesh

Cool I’ll give that a shot when it comes out - might be able to up the number of rays I’m using :). Thanks!


Now that mesh vertices are 3D, what’s the best idom for rotating them in 2D space, instead of what I had above as this (which no longer works):

local v2 = self.mesh.vertices[i+1]
v2 = v2:rotate(edge1Speed * DeltaTime)


@peteroyle it should work in 1.3.6 (it will use a 2D vector rotate if you call v:rotate on a vec3). However for now you can do:

local v2 = self.mesh.vertex( i + 1 ) -- This is faster than mesh.vertices!
v2 = vec2(v2.x,v2.y):rotate( edgelSpeed * DeltaTime )

Thanks Simeon. I’ll switch to mesh.vertex and use the vec2 workaround for the time being.