This project is read-only.

Beginner question concerning usage of BatchModel

Aug 18, 2009 at 9:39 AM

Dear Xen team, first of all let me express my gratitude for this great framework!

Being a beginner in the world of XNA development, I have a question concerning the usage of the BatchModel class in my game. In the game I need to draw several different models many times in a scene.

At the moment I have one DrawTargetScreen object which I populate with all the objects. If I understand the tutorial correctly, I need to add the BatchModel itself to the very end of the DrawTargetScreen object list. My questions are:

1) currently I populate the DrawTargetScreen object only once and add and remove objects as appropriate. As the BatchModel should be placed at the end of the list, I add objects to the DrawTargetScreen object using Insert(0, object) calls, which the BatchModels are placed at the end using Add(). Is this the way it's meant to be?

2) if I use different BatchModels, should I add all of them to the same DrawTargetScreen object, or would it make more sense to create several DrawTargetScreen objects for different object types? If multiple BatchModels are included in a single DrawTargetScreen object, does the order of added BatchModelInstances make a difference (e.g. I add the BatchModel to the end of the list and then insert Object A/Object B/Object A to the front vs. adding Object A/Object A/Object B)

Sorry, if these are dumb questions, but I haven't found any answers to this yet.

Thanks in advance,

best regards,

Arngrim

 

Aug 21, 2009 at 1:19 PM
Edited Aug 21, 2009 at 1:26 PM

Hi Arngrim.

Sorry for taking a week to reply. I've actually been travelling. I'm moving to Cambridge, UK to work (from New Zealand) and I've literally just spent my first proper night in Cambridge.  As such I'm quite limited in how I can help out right now...
However, I can answer your questions.

The trick with Draw Targets, is that internally, they are very simple. They just have a List<IDraw> storing the list of drawables.
When the Draw Target is Drawn, it simply loops over the list and then calls CullTest() and then Draw() on each of the IDraw objects in that list.
So:

foreach (IDraw item in drawList)
  if (item.CullTest(state))
     item.Draw(state);

Very simple.
What this means, is that you don't need to rely on the DrawTarget to control the order things get drawn. Provided you understand how CullTest works, you can draw your objects in whatever order you like.
For example, you might have a 'Scene' class that implements IDraw, and has a draw method something like this:


foreach (IDraw character in myCharacters) { ... cull/draw ... }
foreach (IDraw tree in myTrees) { ... cull/draw ... }
treeBatch.Draw(state);
foreach (IDraw cars in myCars) { ... cull/draw ... } 
skybox.Draw(state); // no bothering with the culltest as it's always visible...

etc. There is no requirement that you must use the DrawTarget list to order things. Just create a wrapper class of your own, and order things however you wish.

As for having multiple DrawTargetScreen objects, it is intended you never do this - as the vast majority of applications will only have one. A DrawTarget assumes it has to completely setup rendering for it's target, clear it, and then shutdown again.

Also, I'll say using batch model is only useful if you really need that last ounce of performance,,, ModelInstance is still pretty quick

Aug 26, 2009 at 9:35 AM

Hi StatusUnknown,

first of all thanks for your reply, which gave me some good insight about the drawing process concerning batch models.

However, I have a follow up question (and/or problem) for which I currently do not know what would be the right answer. As stated in the first post, I have a scene with several identical models (that's why I though about using BatchModels in the first place). In more detail, a game object consists of three model parts which can be separately rotated around each other (think of a cannon that consists of a base, a turret capable of y-rotation and a barrel capable of x-rotation). If I understand it correctly, I cannot use a BatchModel for the entire model (consisting of those three meshes), because I cannot apply the individual transformations to each mesh, is that right?

Which leads to the next problem: in my game, there can be quite a lot of these models, which are also visible at the same time. In a kind of stress test (which might not be too unrealistic for the final game), there are about 600 of the cannons placed in the scene, each with individual rotations of turrets/barrels. When starting out using pure XNA, I used the bone-structures to apply the rotation to the different meshes of the cannon-model. After moving to XEN, I tried using the BatchModel (as stated above), but found I couldn't rotate the individual meshes. So I created three individual models for the separate parts and drew those using three batch models - which lead to 1800 models beeing drawn and the framerate dropping on the xbox360 to 7.5fps. Doing some profiling, I found that 50% of the time is spent in the cull-test method of the batchModel. By the way, a complete cannon has about 180 primitives, so I guess the model itself is not too complex.

So I wonder what my options are to improve the performance?

a) using a single batchmodel for the cannon doesn't work, because of the rotation-limitations (while the performance is acceptable)
b) using three batchmodels for the individual model parts causes a very slow performance
c) limiting the number of models in the scene might work, but would counterfeit the idea of the game
d) I wonder whether turning off the cull-test in BatchModel would improve the performance - how would I deactivate it?

Perhaps I'm doing something essential wrong when rendering the scene? Or a 1800 meshes just too much for the framework? :(

Thanks again for your help,
Arngrim

Sep 1, 2009 at 9:44 PM

I'm not that surprised the performance hit is in CullTest. The .net runtime on the xbox is based on the compact framework, the CF has basically no floating point optimisation and support built in - it certainly doesn't have any vectorization support (which is *critical* for good performance on the xbox, using the VMX). So things like cull tests can really badly bog things down.

However 1,800 models should certianly get more than 7.5fps. The batch model sample draws 1,600 instances of Tiny and I'm pretty sure it does better than 7.5fps on the xbox in a full release build (note that debug builds with the debugger attached can be a lot slower!).
I don't have an xbox right now (as I've recently moved to the UK) however I'm also fairly sure that having multiple batch models wasn't a problem either.

You might want to look at the matrix setup code you are using. If you simply store the matrices and don't recalculate them each frame, does that help? (Most of the matrix methods in XNA are very slow, especially when you start using the non-static methods).

There is a little oversight in the current xen model code, for very simple models (1 geometry group, 1 mesh) the Draw method performs a needless CullTest. I've fixed this, however it's not committed yet for various reasons. If you don't bother calling CullTest() it should reduce the overhead a bit more....