Now it’s time to get serious about ramping up production. I’ve brought up wanting to make a level editor before so here’s how I plan on making it. The rendering pipeline isn’t as good as I thought it out to be. Part of this has to do with how XNA’s content processors create models and meshes for your game, but another part of it is with how I am handling the instancing of meshes.
The problem with the code is more in the access of a particular object in the scene than the creation of them. I don’t see myself implementing a loading/saving system for scenes without fixing this first.
First, an aside: For a while I knew that the pine tree model I used in previous screenshots had some issues with how it was made, and I was right. It had a suspiciously high poly count. For reasons unknown to me, it had literally hundreds of overlapping polygons in several areas. Fortunately, they were hiding underneath the canopy, so removing them didn’t really change its overall appearance.
And remove them I did. I may not be a modeling wiz with Blender, but I know enough to “buff out” meshes in need of some clean-up. I set a temporary shortcut to delete the faces with a single click, and to much mouse abuse, cut the mesh down from almost 2700 polys to under 900. So a 67% reduction! After the fix, the test scene had a decrease in 25ms render time, and the model could now actually be usable for the game. Also, I improved the alpha testing so the mipmap textures look good in all distances, as well as added a kind of texture splatting that draws a different texture on steep slopes.
A new way to draw
I started to introduce the forward renderer to my engine. This will provide an option for low-performance hardware, when deferred rendering is too slow. Currently, it only supports one directional light, no shadows, and the terrain shader isn’t complete yet. But it’s already testable. I ran my test scene, and it averaged about 6 6.25 to 6.67 milliseconds per frame, while the deferred renderer (with shadows and terrain disabled) took 9 to 10 milliseconds per frame. Plus, having hardware MSAA is always nice.
It didn’t come without some significant rework to the scene rendering code, but this was actually a good thing in disguise. Older versions of the engine used the mesh’s GBuffer effect to draw the objects in the Scene Renderer. But it’s of no use if I didn’t want deferred rendering. I could’ve added some forward rendering shaders to the effect file, but then it will no longer be just a GBuffer effect, but a mash of many different rendering schemes. I chose to keep forward rendering in its own effect, and instead have the SceneRenderer set the current effect you wanted to use, and have that (hopefully) render the scene correctly with it.
There are two overloads to drawing a model in the Scene Renderer: one with a GBuffer effect and one with a custom effect. As I removed the requirement of a G-Buffer, the overloads now only made sense in a different way: the custom effect didn’t set parameters for camera settings, while the “standard” previously G-Buffer-only overload did. Now my rendering system is a bit more generic, and determined by whether you pass the camera vars to directly to the Scene Renderer or not.
So in the end, only the Shader classes are responsible for supplying the effects, and to send the appropriate one to the Scene Renderer. With this, implementing the forward shader class was a lot easier, and I created a new Render Profile to use it with.
After I brought instancing to the engine, the methods were altered to directly change the last instance (by default) or given a number, the instance that belongs to that number index. That isn’t going to cut it for the long run.
For a user interface, you shouldn’t need to care where the source of the object’s mesh is coming from. It’s more intuitive to think of them as separate entities. So I will introduce the ModelEntity class, which define a position, rotation and scale, and most importantly, will have a reference to exactly one instance of the model. They just need a different name so you can tell which is which.
The current code to make two identical models would be:
scene.Model("fighterShipModel"); // Makes a ship model as it didn't exist yet scene.Model("fighterShipModel").NewInstance();
The Model method lazy loads, so if the model didn’t exist yet, load its content and create the first instance. But if it already exists, just return that instance. This has a hidden bug/gotcha… if you only typed the second line, you’d get two ships regardless! Also, the only way to access the instances individually is if you remember the order in which you made them or assign an InstancedModel object explicitly. Otherwise it’s lost in the void forever (to be more accurate, stuck in the origin).
With the new Entity system, the new code should read something like this:
scene.AddModelEntity("yourFighterShip", "fighterShipModel"); scene.AddModelEntity("comradeFighterShip", "fighterShipModel");
Maybe I will just call the method AddEntity instead, it could be much clearer. Only the rendering code needs to access everything about the model’s mesh data. So with that said, my scenes would benefit from additional object pools. Not necessarily for improved performance, but to group the data differently for use in different contexts. An Entity only needs to know about its position, rotation, color, what model represents it, etc. It won’t be simply a part of a list of mesh data instances.
So, the next thing to do, is have a pool of Entities for easy lookup by name. Optionally, let the program name the entity for you, because it may not be very important. An example is many rock meshes copied hundreds of times as part of the scenery. They are still individual models, but you don’t care what each one is called. All you would care is that they are rocks and you can select them and move them around. Eventually, when the physics system is in place, they can have their own collision shape as well. Fortunately BEPU would make this simple because it has a straightforward way of accessing all of them.