drawing the model outside the animation component

Topics: Developer Forum, Project Management Forum, User Forum
Feb 19, 2007 at 12:32 PM
Hi all, I read this is the QA section

"The animator is a game component, and as such it implements the Draw method. This is where the model is drawn.

If you want to decide when to draw the model without using the framework, you can set the visible property to false or remove the animator from the game components collection. After this, just call the draw method when you want it to be drawn"

Currently, I am creating a terrain using trianglstrips and loading the dwarf model - all this is done inside the default XNA draw method (i set animation controller visible to false). I don't have access to the code atm so can't post any of it, but the draw method simply displays the vertex buffer for the lanscape then renders the models mesh then calls the base.draw. The models are loaded with a loadmodels method which is initialized in the default XNA initialize section. Also, I don't use the graphics content load section except for loading my terrain texture.

I have set-up the animation component exactly as it should be, have the required references and processors all working fine.

My question is how to I go about by-passing the animation componenets Draw method in preference to my own but still display the animations?? When I check through the animation controller contents after game launch, all the bones are there and everything else but the model just renders in it's default 'star shaped' pose.

Please be aware I have been programming for about 4 days now so I might not make much sense - if you need my (currently crappy) code, I'll post it later tonight.

Thanks for any help,

Kil.
Feb 19, 2007 at 3:07 PM
(Even though this is a suggestion to dastle, not an answer to Kilanirax's questions, I think it fits this topic)

About the animator game component being added automatically to the game's components collection I believe that it should not do that, leaving it up to the programmer to add it later.

The reason is simple: the users of your class will probably want to wrap the ModelAnimator in some kind of GameCharacter or GamePlayer class that will not necessarily extend ModelAnimator (ModelAnimator may well be a private member of it). In this cases, that GameCharacter should be the one with the update() and draw methods() being called from the game class when added to its components; there's no need for the ModelAnimator's update and draw to be called that way too, introducing the need to order the GameCharacter and the ModelAnimator so that the rest of the character's update and draw code be called before the modelanimator's. I.e. The GameCharacter's update() and draw() should be the ones calling the ModelAnimator's methods with the same name.

Of course one could always remove the ModelAnimator instance from the game's components collection after creating it, bue there should be no need to do so.

This being said, I suggest you remove the game.Components.Add(this); line from the ModelAnimator's constructor.

Cheers
Feb 19, 2007 at 3:47 PM
I'll give removing the game component add from the constructor and see if I can sort it like that - thanks for the reply!
Feb 19, 2007 at 4:07 PM
When I suggested you removed that line from the ModelAnimator class ctor, by you I meant dasle, in his actual project code.

In a reply to your question, if you set Enabled and Visible to false on your ModelAnimator instance, it should show the animation if you call the update() and draw() methods of that instance (not the model instance!) from your own code.
Feb 19, 2007 at 5:12 PM
will try that first :) - do have the source and could compile it with some mods but I would prefere not to go messing about too much in there just yet. I'll let you know how it goes.
Feb 19, 2007 at 8:48 PM
hmm came up against a snag,

from the ModelAnimator.cs the draw function is describe as;

"public override void Draw(GameTime gameTime)
{
if (Enabled)
{


int index = 0;
for (int i = 0; i < numMeshes; i++)
{
ModelMesh mesh = model.Meshesi;
if (matrixPaletteParamsindex != null)
{
for (int j = 0; j < palette.Length; j++)
{
int p = paletteToBoneMappingj;
Matrix.Multiply(ref skinTransformsip, ref posep, out palettej);
}
foreach (Effect effect in mesh.Effects)
{
worldParamsindex.SetValue(world);
matrixPaletteParamsindex.SetValue(palette);
index++;
}
}
else
{
foreach (Effect effect in mesh.Effects)
{

worldParamsindex.SetValue(posemesh.ParentBone.Index * world);
index++;
}
}
mesh.Draw();
}
}
}
"

as it can be seen, setting my dwarfAnimator.enabled to false causes this draw function to do practically nothing. So when I call dwarfAnimator.Draw(gametime)from within my draw method, nothing happens. If I set the dwarfAnimator.enabled to true, I get the error NullReferenceException unhandled on teh dwarfAnimator.Draw call (I am sure this is because I effectively have 2 methods both called Draw, one being called inside the other but I may be wrong).

I thought about copying and modifying the ModelAnimator.Draw() code to make it fit my own ModelDraw method, but I can't reference any of the values for Pose, paletteToBoneMapping etc... that the draw method contains.

The dwarfAnimator.Update however calls fine from inside my default XNA update method.

Any ideas would be most welcome.
Coordinator
Feb 19, 2007 at 9:02 PM
You're right - the "Enabled" check in the draw function is obsolete code left over from when the animation was updated in the Draw method. More recently I switched the update code to the update method so it's more predictable and the user can control the update speeds. That check should effective be taken out.

You can bypass it by removing the dwarfAnimator from the game components and setting enabled to true. Then the draw will work only when you tell it to (same for the update).

As for the issue about how ModelAnimator should not add itself to the game components - I think differently. Many people will want to wrap the animator in a class, but many people will also want to use the framework for updating and not wrap it at all. Removing it from the game components is one line - but so is adding it. From an ease of use perspective, I think the decision about whether a component should add itself should be based on how often the framework will be used for that component and how often it will not be used. The GraphicsDeviceManager, for example, adds itself.
Coordinator
Feb 19, 2007 at 10:08 PM
Edited Feb 19, 2007 at 10:16 PM
You can also set enabled to false now if you use the latest checkin.

You said:
"My question is how to I go about by-passing the animation componenets Draw method in preference to my own but still display the animations?? When I check through the animation controller contents after game launch, all the bones are there and everything else but the model just renders in it's default 'star shaped' pose."

Do you want to make a wrapper around the ModelAnimator and call draw when you want, or do you actually want to change how it's drawn? And if you do want to change how its drawn, how so?
Feb 20, 2007 at 9:22 AM
I have my default XNA draw method and my own modelDraw method, ModelDeaw gets called within the default XNA Draw method after I render my trianglestrip terrain - really what I want is to be able to add the animation information to my own ModelDraw method and then be able to call that as it is now within my Draw method.

that make sense? and thanks for the reply :)
Coordinator
Feb 20, 2007 at 10:22 PM
Edited Feb 21, 2007 at 8:06 PM
I'm not sure I completely understand - why can't you have a member variable for ModelAnimator and call the draw method on that within your draw method?

Is what you want to do actually call the draw method on the model itself? What advantage will this give you? This requires you taking the absolute world bone transforms and multiplying by the inverse bind pose transforms (you can't do this right now).
Feb 21, 2007 at 7:31 PM
"I'm not sure I completely understand - why can't you have a member variable for ModelAnimator and call the draw method on that within your draw method?"

it's got a little confusing - this is exactly what I think I am doing, however the call to dwarfAnimator.Draw() from within my own Draw() method results in a NullReferenceException unhandled error.

Will continue to fiddle but any ideas be welcome...
Coordinator
Feb 21, 2007 at 8:08 PM
That's weird. I don't know what to say.. I don't even see how that is possible unless you are using your own effects with the animator.
Feb 21, 2007 at 8:20 PM
ah I think you might have just nailed the problem on the head - I have two versions of my code, one using the basic effect and the other a custom effect from a tutorial page - this must be where the problems lie...sooo silly. Is there any way to use a custom effect or is it basic or nothing atm?

thanks for the help dastle.
Coordinator
Feb 21, 2007 at 8:56 PM
Edited Feb 21, 2007 at 9:11 PM
Is your model skinned?

You can use custom effects but there are a few guidelines:
- If your model is not skinned, your effect must have a "World" parameter.

- If your model is skinned, your effect must have a "World" parameter and a "MatrixPalette" parameter. You need to write the skinning code in your effect yourself, but its only 6 or so lines (check out the Skin4 method in PaletteEffectContent)
- Skinning info is passed into the vertex shader as:
half4 indices : BLENDINDICES0;
float4 weights : BLENDWEIGHT0;

After that, there are a few ways to use your effect on your model (this is as of nightly build 1.0.0.51. It is best if you download the latest source, but I think 1.0.0.51 will work). Here they are listed from easiest to hardest:
- You can just set the effects on the model before you create the animator
- You can set the effects after the animator has been created, but you must call ModelAnimator.InitializeEffectParams() after doing so
- You can subclass the AnimatedModelProcessor in the content pipeline, override the ReplaceBasicEffect method, and set the meshPart.MaterialContent to your effect. This may require you creating your own content writer and reader.

Hope I didn't make this seem more complicated than it is...
Feb 21, 2007 at 10:21 PM
nah not too complicated - thanks dastle - will get right to it!