XNA Creators Club Online
Page 1 of 1 (8 items)
Sort Posts: Previous Next

Engine design: How to handle drawing of Models (instancing)?

Last post 3/5/2009 11:08 PM by Craig Martin. 7 replies.
  • 3/4/2009 8:15 AM

    Engine design: How to handle drawing of Models (instancing)?

    Hi all,
    Up until now, I've been programming my little games from scratch everytime i.e. I had no real framework/engine (whatever you want to call it) I could just reuse for every new game. However, the more I get into game dev, the more I'm interested in doing something like an engine. So I started looking around the net and found a few nice sets of tutorials on how to write a basic engine (e.g. from Innovative Games, Running on empty...)

    The problem I'm having is this. Most of these tutorials have a sort of Actor base class which will handle the drawing of each model. Inside the draw method, the Actor base class will call Mesh.Draw() (the usual Model draw stuff).

    Now what if I have a few hundreds Actors? That will give me a few hundred Draw calls...not good.
    For the sake of it I made a test: In a small test program I drawed a few hundred cubes. Each cube being drawn by its own DIP call. That crashed performance very badly of course.

    I know about instancing and I would really like to implement it (no SM3 card here, so no Hardware instancing). Now my question is: How would I go about clerverly implementing instancing in such an engine? I checked the Instancing Sample but I couldn't figure out a clever method on how to proceed. Maybe my brain is just running slowly and the issue is really easy to handle :-)

    Hope someone can give me some directions in this matter



  • 3/4/2009 12:58 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    The Actor approach you describe is fine in most situations. Hardware instancing is only useful for a situation where you want to draw very large amounts of very few different kinds of low-poly models. It is especially unsuited for complicated 3d mesh with skeletal animations.

    Basically for HI you will need a manager class that manages an array of instances. An instance is usually described by a transformation matrix and maybe a color. The manager's Update function can then apply an algorithm to this matrix/color each frame and the Draw function will pass them on to the GPU where the shaders can apply them to the actual 3d mesh.

    I would not recommend implementing any of this until performance and in particular data throughput to the GPU actually becomes a concern. Drawing a mere hundred cubes should not be a problem either way, especially when using vertexbuffers. Unless they're all filling 100% of the screen or something, in which case HI will not help you anyway.
    "I must Create a System, or be enslaved by another Man's. I will not Reason & Compare; my business is to Create." - William Blake
  • 3/4/2009 1:34 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    I see. Then I'll keep the Actor approach and see where I go from there.

    The reason I ask is because my last game - which I haven't finished yet because my code got messy, hence my desire to rebuild from scratch - is a 3D sokoban clone. The walls are represented by simple cubes. Around 100 per level --> +-100 DIP calls for the walls. However, I got a framerate of only 60 FPS (and yes, I disabled VSync). That might be OK, but I can run other things much faster which must be far more complicated to render then 100 cubes. Therefore I was thinking about implementing Instancing.
    Well, probably the problem I have is lying elsewhere then. I think I really need to start learning to understand what PIX and CLRProfiler are trying to tell me :-)
  • 3/4/2009 2:07 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    The .Draw call does a lot of overhead related to the effect that doesn't need to be done between meshes that share the same effect.

    If your models all have the same effect and technique then you can setup the effect and the technique once, draw all the models using drawindexedprimitives, and end the technique
    once and save a lot of time.

    Effect.Begin()
      effect.currenttechnique.begin()

        set model 1 parameters
        effect.commitchanges()

        drawindexedprimitives ( info from model 1...)

        set model 2 parameters
       
         effect.commitchanges()
       ...

       effect.currenttechnique.end()
    effect.end()
       
    ..shaders make you feel... powerful, or very very stupid.
    http://drjbn.spaces.live.com/
  • 3/4/2009 2:38 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    @Byron: I actually did that. The only thing I had to set for every model (i.e. wall tile in my example) was the world matrix.

    I rather suspect that my Shader was performing badly. I am a real n00b regarding anything shaders you know :-) I implemented the phong lighting model inside a pixel shader with a single Light source. I may have to check that instead.
  • 3/4/2009 3:47 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    Yes your engine needs to be good at batching the Draw calls. The critcal ones are things like changing to a different effect instance like Byron described above, changing texture, vertex/index buffers/streams, and renderstate changes. If you can group your Draw calls to minimize these changes, that's about the best you can do in terms of GPU efficiency.

    There's a lot about batching for PC GPU's on the web, the Nvidia site has some great info on the subject.

    For general game engine design, it can be confusing trying to incorporate all the different aspects of graphics drawing into a general model. I've found it best to try and keep the graphics drawing code well separate from the main game entitity model, otherwise it becomes hard to maintain flexibility, efficiency and comprehension at the same time. e.g. the main game entities don't know how they are drawn, and don't care, the drawing component manages it all.


    re HI, you could Draw 10k of your wall cubes even if they're all moving independently of each other, no problem, just like in the HI sample here. It is perfect for that scenario of needing to draw hundreds or thousands of simple meshes.




    Game hobbyist hell-bent on coding a diabolical Matrix
  • 3/5/2009 1:43 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    @Craig Martin:
    If I understand correctly, you'd recommend that every "Actor" just exposes its VB/IB, Effect etc... it needs and then have a "DrawManager" decide what to do i.e. first sort by Effect, set the common effectparameters etc... and then draw each Actor.

    If I have models I know will be drawn often and I would want to use instancing for them, I would use a class InstancedModel which has an array of transformationMatrices. If the DrawManager detects that the Actor is of type InstancedModel, I would go and call the Shader Instancing Shader.

    Hmm, that sounds doable.
  • 3/5/2009 11:08 PM In reply to

    Re: Engine design: How to handle drawing of Models (instancing)?

    Rizman:
    @Craig Martin:
    If I understand correctly, you'd recommend that every "Actor" just exposes its VB/IB, Effect etc... it needs and then have a "DrawManager" decide what to do i.e. first sort by Effect, set the common effectparameters etc... and then draw each Actor.

    If I have models I know will be drawn often and I would want to use instancing for them, I would use a class InstancedModel which has an array of transformationMatrices. If the DrawManager detects that the Actor is of type InstancedModel, I would go and call the Shader Instancing Shader.

    Hmm, that sounds doable.


    Yup. It might be a bit cleaner if you encapsulate the VB/IB/Effect stuff into a Material class or something that the DrawManager understands, and the Actors contain (and exposes) one or more of these material objects.
    Game hobbyist hell-bent on coding a diabolical Matrix
Page 1 of 1 (8 items) Previous Next