Refactoring the model instance management system. -- Owen Meyers
At the present moment, through playtests, it may be painfully obvious that even though we can support skinned meshes and animation (arguably the hardest type of model to support for the requirements of our game), there are zero static meshes, despite them being simpler and easier to process. There is a reason for this, and that reason is incredibly dumb when stated aloud. The system as it works right now has to reshuffle matrices whenever an enemy dies. This is to be expected, as the matrices are all in a singular buffer that every enemy refers to in order to keep rendering fast. The problem with that is when static meshes are introduced in order to add visual variety to the world, they are placed behind the skinned mesh matrices in that buffer. This leads to an issue where the buffer and a set of structs that index it desync from each other, and lead to rogue mesh instances placed out of bounds (this is rarely, but occasionally visible in the current build of the game, which has zero static meshes). That issue gets exponentially worse for each new model that has 1 or more world matrices in the buffer at a time. Obviously, the system as it stands must be rebuilt and fixed in order to prevent that from happening.
There are multiple approaches I am planning on utilizing to resolve this, each has their own benefits and downsides. The first approach is to make a new management system that holds all of the matrix data on its own, similar to the animation manager. This would have the benefit of keeping complexity within the Central Processing system down, and allowing for world matrices to be organized rather quickly, likely through the use of a hash map. The downside of this is that it would require a whole new system to be built separate from Central Processing, and as a result, could cause conflict on the GIT repo as well as simply being more time consuming to build. An alternative approach is to simply keep every thing separated from each other. What I mean by this is to simply have 2 buffers on the CPU-side that contain world matrices. The first buffer contains all of the world matrices for the skinned meshes, and the other for all of the static meshes. These buffers are then concatenated to each other before being sent to the GPU, with each struct that maintains indexing for static meshes having an implied offset that is the length of the skinned mesh buffer. This has the benefit of being relatively simple to write on top of the current system, and allows for the buffers to be kept separate from each other during processing of the scene, but then put together during rendering, keeping rendering speed fast. The downside for this is that every frame, 2 separate arrays would need to be written into one, and two sets of the indexing structs would also need to be copied into a buffer of one, with offsets written into them. This would greatly increase the time needed to process the scene, as the complexity of such an algorithm would almost certainly be O(n), with worst case climbing as high as O(n^2) if there is a) a high volume of matrices and b) a large amount of changes that need to be applied to the buffers that frame anyway (i.e. a large amount of enemies die simultaneously, a room is loaded (the entire static mesh buffer is invalidated), etc. etc.). I am experimenting with both, as I believe that the first solution will likely require some form of the second solution, however, the first solution abstracts it away and can even be placed on its own thread to allow for it to execute the organization concurrently while more time-consuming tasks (such as AI) are being processed.
Comments
Post a Comment