Dual models displaying

Topics: Developer Forum, User Forum
Apr 5, 2007 at 2:54 PM
Edited Apr 10, 2007 at 8:45 AM
I'm back.

I've managed to get the animations onscreen without the bones (see http://www.codeplex.com/animationcomponents/Thread/View.aspx?ThreadId=8829 for details) and can play around with it in my own classes, for now there are only two classes that uses animated models. They both inherit from a base class that handles the actual loading and drawing of models/animations.

Now. I've never really understood this part of the code, in the tutorial placed in LoadGraphicsContent:

effect.View = View;
effect.Projection = Projection;

I understand the code so far that I know what it does (I've used it a lot) but what I don't understans is where you actually draw the mesh in the tutorial. I see the dwarf on screen and all so I guess it must be drawn right ;)

Now I have a function that looks like this

foreach (ModelMesh mesh in m.Meshes)
{
foreach (Effect effect in mesh.Effects)
{
if (effect is BasicEffect)
{
BasicEffect basic = (BasicEffect)effect;
basic.View = Game1.Camera.View;
basic.Projection = Game1.Camera.Projection;
basic.World = mesh.ParentBone.Transform * world;
}
else if (effect is BasicPaletteEffect)
{
BasicPaletteEffect palette = (BasicPaletteEffect)effect;
palette.View = Game1.Camera.View;
palette.Projection = Game1.Camera.Projection;
palette.World = mesh.ParentBone.Transform * world;
}
}
mesh.Draw();
}

See where I do the drawing? Now. For some really weird reason, the models loaded appear in what I believe to be VectorPosition (0, 0, 0) unscaled, unrotated and well unpositioned. Does

*basic.View = Game1.Camera.View;
basic.Projection = Game1.Camera.Projection;*

have anything to do with this? Because when I outcomment mesh.Draw(); the model that I wish to be drawn (e.g. my Player (controlled by input)) disappears. Fine, I brought that on me because I outcommented it. What I cannot understand though is that the unscaled, unrotated and unpositioned model still appears on Position (0,0,0).

A little more research shows that this happens with all meshes loaded this way. Next to my Player (which I have to scale down) is a tiny Enemy-dwarf (which I have to scale up when actually using it).

When not calling the draw method at all both meshes disappear. What should I do? Should I not call my Player.Draw() method (the one posted above) or what kind of solutions might there be to the problem?

I'd like to know how your drawing/rendering works and where/when it happens because I believe our different programming strategies to be the cause of the problem.

Thank you for your time taken.
Coordinator
Apr 6, 2007 at 6:23 AM
Edited Apr 6, 2007 at 6:30 AM
The animator is a DrawableGameComponent, so it adds itself to the game Components on creation, and draws itself every frame. I've considered making it not automatically add itself for clarity, but I figured I'd get more questions about this.

Anyway, it looks like you would be best off manually calling draw. So, after creating the animator, call (in your game class)
this.Components.Remove(animator);

Then call Update in your update method and draw in your draw method (or wherever you want to update/draw it).

Note that to correctly draw a skinned mesh, you'll have to use the ModelAnimator class (or do a lot of work yourself.) This shouldn't a problem though, since you get remove it from the GameComponents and control when the update and drawing occurs.

One last thing to mention is that the view/projection matrices are expected to be updated by the user, while the world matrix is handled by the animator. I realize this is confusing, but I've documented my reasons for doing this.
Apr 10, 2007 at 6:55 AM
*Back from the holidays*

Hmm.. Seems like that call removes everything I draw.....

*getting the thinking hat out*
Apr 10, 2007 at 7:05 AM
Edited Apr 10, 2007 at 8:44 AM
Hmmm Can't seem to get the mesh to draw when adding that line of code. Is there something wrong with my Draw() call?

Coordinator
Apr 10, 2007 at 11:44 AM
You want to call ModelAnimator.Draw(), not Mesh.Draw(). Likewise, call ModelAnimator.Update() if you remove it from the game components. Alternatively, setting ModelAnimator.Visible to false allows for manual drawing and automatic updating, and setting ModelAnimator.Enabled to false allows for manual updating and automatic drawing.

Mesh.Draw() doesn't work because the effects use a matrix palette for skinned animation, and the ModelAnimator handles this, but the ModelMesh doesn't.
Apr 10, 2007 at 2:00 PM
Ok.
Since we were trying to use the Skinned Model from Microsoft first, we baked that in to the solution. Now we're trying to use your library instead. We have a pretty well-organized structure by now so I'm trying to get the animation into our project without having to blow everything to pieces and build everything from the start.

Now. I have made a LevelHandler that is to handle well... The Levels. When loading a new level I unload graphics content for the old level. I have two ContentManagers for this. One that keeps everything that I will always need. For now it's just the player mesh and interface spritebatches, but things might be added to that list.

When I run the "first" level and change the drawing settings so that the player mesh (and the enemies) show it's fine and dandy. But when changing level the game breaks at base.Draw(); in Game1.Draw() with a message of corrupt memory.

This is the problem I am trying to work around now. I believe that somehow the ModelAnimators for the enemies (which I unload between the levels) are unloaded but not removed from the game itself.

 
//excerpt from LevelHandler
    public void UnloadGraphicsForCurrentLevel()
        {
            Game1.gameContentManager.Unload();
        }

This is my main problem right now.
Coordinator
Apr 10, 2007 at 3:15 PM
Yup. Model animators are not loaded through the content pipeline.

So, you also need to remove animators and animation controllers from the GameComponents collection when your done with them.

I.E., this would remove all ModelAnimators and AnimationControllers:

List<IGameComponent> toRemove = new List<IGameComponent>();
foreach (IGameComponent component in Game1.Components)
{
if (component is ModelAnimator || component is AnimationController)
{
toRemove.Add(component);
}
}
foreach (IGameComponent component in toRemove)
Game1.Components.Remove(component);


A bit tedious, but still far easier than managing objects with no garbage collector.
Apr 11, 2007 at 6:16 AM
Oh Dastle, what would I do without you?! That works like a charm. I can now change levels and hopefully free memory so that the game doesn't grow in size over the course of time.

Thank you so much!
Jul 19, 2007 at 3:12 AM
Edited Jul 21, 2007 at 6:37 AM
I think I see how to do this.