Page 1 of 1

How do I update the positions of instances of meshes?

Posted: Sun May 16, 2021 3:37 am
by ac3raven
I am interested in using the drawInstanced() function, but I am struggling to understand how to update the positions of each instance of a mesh. The example here: https://love2d.org/wiki/love.graphics.drawInstanced shows the positions of the triangles being sent to the shader one time.

Using the example on the wiki page:

Obviously if I want to update the position, I need to pass the new positions of the vertices to the shader every frame. But I don't know how to do that. shader:send() doesn't help because that only sends uniforms. I figure maybe I need to use setVertexAttribute() every frame, but when I try that nothing renders.

I also tried simply looping through the table of positions ("instancepositions") and setting pos.x,and pos.y, thinking that maybe since that attribute is already attached, then all I would need to do is update the values in the table. But that also does nothing. in fact, if I print out pos.x and pos.y, I just get 0,0, and that seems to be the only value in the instancepositions table, even though print(#instancepositions") has 2,304 values in it.

So I am just lost. I need each instance of a mesh to have its own position and movement, and I don't know how to do that in combination with drawInstanced().

I appreciate any help!

Re: How do I update the positions of instances of meshes?

Posted: Sun May 16, 2021 4:06 am
by grump
You don't send the positions to the shader directly, you update them by calling instancemesh:setVertexAttribute with the instance number, the attribute index, and the position values.

Re: How do I update the positions of instances of meshes?

Posted: Sun May 16, 2021 4:21 am
by ac3raven
Ah, I see. I was close then, I was just trying to update the wrong mesh.

I got it working with this basic proof of concept:

Code: Select all

local testx = 0
function love.update(dt)
  testx = testx + 10 * dt
  for i=1,instancemesh:getVertexCount() do
   instancemesh:setVertexAttribute(i,1,testx,100)
  end
  instancemesh:setVertexAttribute(2,1,testx,400)
end
Is the instancemesh required when using drawInstanced? Or can I simply operate on the regular mesh directly? Is that wise when instancing?

Re: How do I update the positions of instances of meshes?

Posted: Tue May 18, 2021 3:27 pm
by grump
ac3raven wrote: Sun May 16, 2021 4:21 am Is the instancemesh required when using drawInstanced? Or can I simply operate on the regular mesh directly? Is that wise when instancing?
It's not required IIRC. If you don't have an attribute mesh then you can't change the attributes of the instances, and you have to use uniforms instead, which kind of defeats the purpose of instancing.

Re: How do I update the positions of instances of meshes?

Posted: Sat May 22, 2021 1:27 am
by ac3raven
So, in this example, self.dir is randomly either 1 or -1. This is just to try to get the circles to move in different directions for testing.

Code: Select all

  for c,self in ipairs(circles) do
    self.x = self.x + (self.speed * dt)* self.dir--just testing
    self.y = self.y + (self.speed * dt) * self.dir--just testing
    for i=1,instancemesh:getVertexCount() do
      instancemesh:setVertexAttribute(i,1,self.x,self.y)
    end
  end
My draw code is like this:

Code: Select all

  lg.setShader(shader)
  lg.drawInstanced(mesh, #instancepositions,0,0,0,instanceScale,instanceScale)
  lg.setShader()

Here is how everything gets setup (the for loop here seems wrong):

Code: Select all

function Circle:load()
  for i=1,instanceCount do
    local pos = {400/instanceScale,400/instanceScale,random(1,10)}
    self:create(400/instanceScale,400/instanceScale,random(1,10))
    table.insert(instancepositions,pos)
  end
  instancemesh = love.graphics.newMesh({{"InstancePosition", "float", 2}}, instancepositions, nil, "static")
  
  mesh:attachAttribute("InstancePosition", instancemesh, "perinstance")
end
My circles still move all together, on top of each other, despite the movement code theoretically moving them at different speeds and directions.

What am I missing here?

Is it that I am only inserting to the instancepositions table one time, at load? Or something?

Re: How do I update the positions of instances of meshes?

Posted: Sat May 22, 2021 1:41 am
by slime
Your circle update code is overwriting every instance position with the same value in each iteration of the loop over the circles array - so only the position of the last element of that array is being applied, and it's applying to every instance instead of a specific one.

Re: How do I update the positions of instances of meshes?

Posted: Sat May 22, 2021 2:02 am
by ac3raven
Thanks for that helpful hint!

I don't know if this is correct or not, but I found that it works when I replace i with c:

Code: Select all

  for c,self in ipairs(circles) do
    print(self.dir)
    self.x = self.x + (self.speed * dt)* self.dir--just testing
    self.y = self.y + (self.speed * dt) * self.dir--just testing
    for i=1,instancemesh:getVertexCount() do
    	instancemesh:setVertexAttribute(c,1,self.x,self.y)
    end

Re: How do I update the positions of instances of meshes?

Posted: Sat May 22, 2021 2:09 am
by slime
In that case you can get rid of the inner for-loop entirely, as long as instancemesh has at least as many elements in it as there are circles:

Code: Select all

  for c,self in ipairs(circles) do
    self.x = self.x + (self.speed * dt) * self.dir--just testing
    self.y = self.y + (self.speed * dt) * self.dir--just testing
    instancemesh:setVertexAttribute(c,1,self.x,self.y)
  end

Re: How do I update the positions of instances of meshes?

Posted: Sat May 22, 2021 2:12 am
by ac3raven
Yeah, that makes sense. Thank you! I'm a novice with instancing of meshes, so this is super helpful.