Jordan Bonser
  • Home
  • CV
  • University Work
    • Second Year Work >
      • Top-Down Shooter
    • Third Year Work >
      • Terrain Analysis Project >
        • Terrain Analysis Tool
        • Game Demonstration
      • Post Processing
      • Android Application - Sports Centre
  • Projects
    • Unity Development >
      • Lerpz Tutorial
      • Dare to be Digital Entry - "Lit"
      • Unity Game
    • Geometry Instancing
    • Road to Eldorado
    • Level Editor
    • OpenGL Work
    • JBEngine
  • Blog
  • Tutorials
    • Flask Session Timeout

Geometry Instancing

Geometry Instancing Work

I have talked about geometry instancing in various sections of my portfolio. First of all in the improvements to my Terrain Analysis Tool and also in my blog. I have now decided I am going to attempt to implement Instancing inside the renderer that I have currently been using for my projects.

The Problem

In most naive renderers each model is rendered via a single draw call which passes all it's geometry information such as vertices and also the models position, textures and other data needed for it to be drawn. Each draw call is fairly expensive for the CPU, which even with a high end CPU you would probably only be able to reach a few thousand draw calls each frame and still have a comfortable frame rate. This causes a dilemma as in most modern games there can be a few thousand trees or shrubs in one frame. So without even the artificial intelligence or pathfinding to be considered the CPU would be overloaded with work.  

Instancing - The Solution

Instancing tackles this problem by allowing the GPU to draw many "Instances" of the same model in various locations in one draw call.

This is done by passing the normal geometry information across to the vertex buffer in a draw call and also, in a separate buffer sending all the instance information such as:
  • Position
  • Rotation
  • Scale
  • Colour
  • Texture
  • Animation

The vertex shader then uses the geometry data along with the instance data to draw many instances of the same object in a scene. The Instance buffer which is where the Instance data is stored can hold as many different variables as needed so instances don't have to look exactly the same, for example they could look a different colour, use different animations or different textures.  The more information that is used for each instance means that the Instance buffer won't be able to hold as many instances.

Development

So now you know a little about instancing and what it does I will begin development on making it work in DirectX10.

Initial Development

First of all I took a step back from even opening visual studio and headed straight for the internet. The first port of call was finding out the process that is needed for doing instancing. After many hours looking at various websites and the DirectX SDK's I had finally gotten a grip with the process of instancing. There are certain things that need to be added and adjusted including the Vertex Input Layout and a new Buffer. 

The two vertex buffers then needed to be set to the IA stage along with their associated strides and offsets. Finally the DrawIndexedInstanced function can be used. The first day at trying this was largely unsuccessful and I had to delve further into some research and debug the new code to make sure all buffers, layouts and other things were all being created properly. 

Once this was done then there were some minor tweaks to the HLSL to ensure that all layouts matched and that the vertex shader used the instance positions rather than the original model position.

Finally Working

After a long day of hitting my head against the wall I finally got it to do the instancing of 7000 models in one draw call. This was such a relief, as my motivation was nearly breaking and was just about to call it a night. To the right you can see a screenshot of the instancing. As you can see in the image the frame rate was not that great at all, in fact it was essentially the same as the normal technique for rendering. I though this was strange and checked back through the code to ensure it was working properly. Everything seemed fine so there needed to be some other explanation for the performance lag.
Picture
At this point there seemed to be an issue with the models not being rendered when you turn too far left or right. This was obviously due to the frustum culling, as there is actually only one model that has been placed in the scene. The instanced data had been generated using a position offset from the original bottom left sphere. This meant that if the bottom left sphere was frustum culled then so where all of them.

Instancing - 70,000 models of 16 polygons

Picture
Did some optimisation testing for about half an hour and realised that the bottleneck was in the DXGI.dll which meant it was nothing to do with the C++ side. I had come to a point where I thought maybe my implementation was done poorly and then finally as one last thought I decided to check the model I was using. It turned out that the sphere model I was using had 1600 polygons. Why a sphere model needs 1600 polygons I don't know but I changed it to a 16 polygon diamond and the results were amazing. As you can see in the image; 70,000 polygons and it's still running at 100 FPS. An added point is that my AI Demonstration is actually running at the same time as well. Due to the fact that all the instances are done in one draw call means the CPU has so much time for all the Path finding and other AI that is in my game demonstration.
The Instancing architecture still needs some work to allow for the instancing to be used for any model specified and also to switch it on and off for particular models as clearly instancing high polygon models turns out to be not very effective at all. There is also the fact that currently none of the models move, I have looked into this somewhat and it seems to be the case that you use the UpdateSubResource Function to handle that. I am sure it won't be that simple though.

Instance Movement

I have worked on the movement aspect of the instancing and after reading up on the different types of buffers available I decided to go with the UpdateSubResource approach. Below is a video showing the movement of 100,000 models:
The program is still coping very well even with 100,000 models and the movement involved. I'm pretty happy about the progress that has been made so far but still plenty more needs to be done.

The next step will be to integrate the instancing properly to allow for levels/scenes to be loaded in as normal and instancing to occur where and when it's necessary. This could be quite a long task as I'm working with someone else's entity manager and mesh loader. 

Instancing Integration

This part of the development was really about allowing the models to be loaded exactly how they used to be and then allowing the models to be instanced where necessary. I started by creating a main render loop which would allow for the collection of the instance data and passes it to the instance buffer for use within the draw call. This part was particularly tricky and needed a few attempts before I finally got it. Once that was done there was not much needed changing. 

To the right is a video of two different types of models that have been instanced simply by turning "Instancing" to "true" using XML. These models can now be used just like any other entity meaning they can be updated using the entity manager. 
There are only 20,000 models featured in this video as there has been a considerable performance hit due to the increased number of entities that are being managed by the entity manager. I could tackle this and remove the entities from being updated but that may sometimes be necessary so there will be some thought going in to how I will be approaching this. 

I will also need to adjust the instancing to take into account rotation and scale at some point as it currently only uses position to place the models within the scene.
Powered by Create your own unique website with customizable templates.
  • Home
  • CV
  • University Work
    • Second Year Work >
      • Top-Down Shooter
    • Third Year Work >
      • Terrain Analysis Project >
        • Terrain Analysis Tool
        • Game Demonstration
      • Post Processing
      • Android Application - Sports Centre
  • Projects
    • Unity Development >
      • Lerpz Tutorial
      • Dare to be Digital Entry - "Lit"
      • Unity Game
    • Geometry Instancing
    • Road to Eldorado
    • Level Editor
    • OpenGL Work
    • JBEngine
  • Blog
  • Tutorials
    • Flask Session Timeout