Sign in to follow this  
Kaze

XNA Model reseting BasicEffect matrix

Recommended Posts

Kaze    948
When I grab a model multiple times from the content manager it seems to return the exact same model including the same BasicEffect class. This means that if I take two copys from the content manager and alter BasicEffect settings both will be affected. I've managed to work around this by reseting any BasicEffect settings I want to use every frame from my own copies but in this rigid body animation tutorial you need to grab the original transform setting from the model and save the new ones to the model to render it correctly. So how am I suppose to create a new instance with a fresh world matrix.

Share this post


Link to post
Share on other sites
BLiTZWiNG    361
Um, that's how its meant to work. The ContentManager stops you from unnecessarily duplicating assets, and every frame you set the world matrix for each instance of your model, which is infinitely more efficient.

Share this post


Link to post
Share on other sites
Kaze    948
Quote:
Original post by BLiTZWiNG
Um, that's how its meant to work. The ContentManager stops you from unnecessarily duplicating assets, and every frame you set the world matrix for each instance of your model, which is infinitely more efficient.


That makes sense for immutable assets like the mesh data but for the effects its a pain to manage.

Either way the problem is that for models that have multiple meshes or transformed meshes I need to set the world matrix to its intended position relative to its original transform and if I do that I overwrite its original transform.

Share this post


Link to post
Share on other sites
Kaze    948
Here is the tank from the tutorial with its original transformations




And here it is with its world matrix forced and original ignored

Share this post


Link to post
Share on other sites
Kaze    948
Quote:
Original post by MJP
You can create a clone of any Effect if you want to maintain different state for multiple instances of the same Model.


I considered making a wrapper around the content manager that would save the original world matrices of all the meshes in the model but it seems like either their should be a easier way or its a bit of a design flaw.

Share this post


Link to post
Share on other sites
BLiTZWiNG    361
Quote:
Original post by Kaze
Quote:
Original post by MJP
You can create a clone of any Effect if you want to maintain different state for multiple instances of the same Model.


I considered making a wrapper around the content manager that would save the original world matrices of all the meshes in the model but it seems like either their should be a easier way or its a bit of a design flaw.


You have to be careful when you invoke the phrase "design flaw". What qualifications do you have to make this judgment? Given the rest of the industry does it the way we're telling you, is there a chance you could be wrong?

Share this post


Link to post
Share on other sites
Kaze    948
Quote:
Original post by BLiTZWiNG
Quote:
Original post by Kaze
Quote:
Original post by MJP
You can create a clone of any Effect if you want to maintain different state for multiple instances of the same Model.


I considered making a wrapper around the content manager that would save the original world matrices of all the meshes in the model but it seems like either their should be a easier way or its a bit of a design flaw.


You have to be careful when you invoke the phrase "design flaw". What qualifications do you have to make this judgment? Given the rest of the industry does it the way we're telling you, is there a chance you could be wrong?


If theirs a trick I don't know about or a flaw in my logic tell me but it seems to me if I can't render a model without overwriting its configuration data thats a flaw. Why couldn't it have had some separation between the data in the model file and render option I want give it later.

Share this post


Link to post
Share on other sites
MJP    19790
Quote:
Original post by Kaze
Quote:
Original post by MJP
You can create a clone of any Effect if you want to maintain different state for multiple instances of the same Model.


I considered making a wrapper around the content manager that would save the original world matrices of all the meshes in the model but it seems like either their should be a easier way or its a bit of a design flaw.


Effect's aren't really meant to hold per-instance state. The more common usage pattern is to have clones that hold per-model state (usually material data and other artist tweakables). Otherwise you'd need a clone for every single instance of every Model, and each Effect clone would contain the full state even for stuff that remains static. It makes more sense to just store your instance data in your own structures (since you probably have to do that anyway), that way you don't have memory wasted from having many copies of effect state everywhere.

It's really not that hard to do...

class ModelInstance
{
Model model;
Matrix worldMatrix;
// Any other per-instance parameters go here

void Draw()
{
foreach(ModelMesh mesh in model.ModelMeshes)
{
foreach(BasicEffect effect in mesh.Effects)
effect.World = worldMatrix;

// Do drawing stuff here
}
}
}


Then you can extend that to arbitrary effects and instance data, if you want.

Share this post


Link to post
Share on other sites
Kaze    948
Quote:
Original post by MJP
It's really not that hard to do...

class ModelInstance
{
Model model;
Matrix worldMatrix;
// Any other per-instance parameters go here

void Draw()
{
foreach(ModelMesh mesh in model.ModelMeshes)
{
foreach(BasicEffect effect in mesh.Effects)
effect.World = worldMatrix;

// Do drawing stuff here
}
}
}


Then you can extend that to arbitrary effects and instance data, if you want.


This is whats I was doing, the problem is that effect.World for each ModelMesh doesn't start off at Matrix.Identity;. It starts at whatever transform I assigned to it in the model editor.

EDIT:

class ModelInstance
{
Model model;
Matrix worldMatrix;
// Any other per-instance parameters go here

void Draw()
{
foreach(ModelMesh mesh in model.ModelMeshes)
{
foreach(BasicEffect effect in mesh.Effects)
effect.World = GetOriginalWorldMatrixFor(mesh) * worldMatrix;

// Do drawing stuff here
}
}
}




EDIT2:

thats wrong, the transforms are in the Model.Bones but its still the same problem, I cant modify them without overwriting the models original data.


[Edited by - Kaze on February 7, 2010 9:47:58 PM]

Share this post


Link to post
Share on other sites
Kaze    948
/// <summary>
/// simple rigid animation test based of xna tutorial
/// </summary>
public class Rig2
{
public Rig2(ContentManager content)
{
World = Matrix.Identity;
//get model from content manager
this.XnaModel = content.Load<Model>("rig2");

//get bone we want to move
Bone1 = this.XnaModel.Bones["Cube.002"];
//copy transform so we can move it realative to its original
//Transfomation rather than identity.
//***Problem part 1***
//We get our local copy from the model so if we call this later after another
//instance of this class has altered it the animation will be messed up
Bone1Transform = Bone1.Transform;
}
public Model XnaModel { get; private set; }
public ModelBone Bone1 { get; private set; }
public Matrix Bone1Transform { get; private set; }
public Matrix World { get; set; }

float ang = 0;
public void Update(GameTime time) {
ang += (float)time.ElapsedGameTime.TotalSeconds;
//rotate bone relative to its original transform and
//save the new transform to the bone
//***Problem part 2***
//We have to save the new transform back to the bone to
//calaculate the absolute transforms in the draw method
Bone1.Transform = Matrix.CreateRotationY(ang) * Bone1Transform;
}

public void Draw( Matrix view, Matrix projection)
{
//this is almost identical to the microsoft model rendering tutorials
Matrix[] transforms = new Matrix[XnaModel.Bones.Count];
XnaModel.CopyAbsoluteBoneTransformsTo(transforms);


foreach (ModelMesh mesh in XnaModel.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();

effect.View = view;
effect.Projection = projection;
effect.World =
transforms[mesh.ParentBone.Index] * World;

}
mesh.Draw();
}

}
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this