Last week I spent quite a bit of time on the slopes snowboarding, but mostly in the mornings: I was back working at my computer in the afternoons. And while the mornings weren’t meant to be spent working, I actually found that some of my best ideas came to me while sitting on a chair-lift.
One such idea was around efficient mesh management inside Forma.
We’ve been working on a prototype web-based multi-agent simulation system where the results are displayed in either Forma or Tandem. This will form much of what I'll talk about in my session at the upcoming Autodesk DevCon in Amsterdam.
As with earlier prototypes where we’ve integrated VASA into Forma, one of my favourite mechanisms for displaying calculated information is to render it as a Forma mesh. We did this for the visibility dome and shadows shown in my AU 2024 talk with Håvard Høiby (see page 24 of the handout to see what I mean).
I wanted to do something similar for our multi-agent system, where we have agents moving around a building along paths calculated using VASA. We’d have a mesh for the ghosted building geometry - so that we can have see-through walls - plus a mesh for each of the agents and perhaps one for each of the 3D paths they’re travelling along. Etc., etc.
This image should give a sense of what I’m talking about:
This worked quite well but presented a number of interesting challenges: for an agent to be visible through the walls of a translucent building, the building needs to be rendered after the agent. So whenever you add an agent, you need to remove and re-render the building. This is also true for each path that gets created - and these are created even more frequently than the agents themselves!
To start with I built a complex system of re-generating/re-rendering the building geometry whenever new agents or paths were rendered. It was an unholy mess. Then, on a chair-lift, I realised a couple of things:
1) We could avoid having multiple meshes for agents and paths by maintaining one for all the agents and one for all the paths. A mesh in Forma is just a vertex buffer with a bunch of vertex colors - there’s nothing that says the triangles need to be adjacent. You can use one mesh to represent a number of objects throughout your scene. (While Forma uses THREE.js to display create and display geometry, this level of interface - at the mesh definition level - means you can use your own version of THREE.js - or another library entirely - to generate your mesh content. This was actually a very sensible architectural decision.)
2) We could add these central meshes - with zero vertices! - to Forma during initialization and then update them to have more vertices whenever appropriate. As long as we added the “dummy” meshes in the right order (agents, paths, building) then we could avoid all that silly removing and re-adding. Whenever we want to hide a mesh temporarily, rather than removing it - our previous approach - we just remove the vertices that represent it from the mesh. Or choose not to include them when we next create the mesh, of course.
This approach has worked perfectly. The rendering logic is intuitive and I have been able to rip out all the scaffolding that supported the removal and re-adding of meshes.
And the system scales well, too. I was worried about the fact we have to update an aggregate mesh whenever a single entity represented in the mesh moved, but it seems that the overhead for doing this is lower that that of managing and re-rendering multiple meshes. It’s both simpler and more performant!
I imagine that some of you will either already be using an approach such as this, and yet others will be saying “well, how else would you do it?”, but I’m posting this on the off-chance that other people like me are out there who would benefit from this technique.
Do come to the Autodesk DevCon to see this in action!