How do I update the positions of instances of meshes?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
ac3raven
Citizen
Posts: 60
Joined: Tue May 19, 2009 1:14 am

How do I update the positions of instances of meshes?

Post 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!
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

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

Post 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.
User avatar
ac3raven
Citizen
Posts: 60
Joined: Tue May 19, 2009 1:14 am

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

Post 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?
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

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

Post 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.
User avatar
ac3raven
Citizen
Posts: 60
Joined: Tue May 19, 2009 1:14 am

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

Post 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?
User avatar
slime
Solid Snayke
Posts: 3166
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

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

Post 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.
User avatar
ac3raven
Citizen
Posts: 60
Joined: Tue May 19, 2009 1:14 am

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

Post 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
User avatar
slime
Solid Snayke
Posts: 3166
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

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

Post 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
User avatar
ac3raven
Citizen
Posts: 60
Joined: Tue May 19, 2009 1:14 am

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

Post by ac3raven »

Yeah, that makes sense. Thank you! I'm a novice with instancing of meshes, so this is super helpful.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 13 guests