App Hub
Sort Discussions: Previous Discussion Next Discussion
Page 1 of 1 (12 posts)

Deep Clone (Serialize) a Model

Last post 12/31/2008 1:32 AM by cpaganucci. 11 replies.
  • 2/13/2008 6:43 PM

    Deep Clone (Serialize) a Model

    Hi. I've been busy learning 3D in XNA and I've run into some problems.

    I've got a Model loaded in the regular way through Content.Load("Cube"); in a static Datalibrary class.

    I've got a class called Object3D with a Model variable that can update and draw itself etc.

    I've got multiple of the Object3D created using the same reference from the Datalibrary class.


    The problem is that when I go to draw all the objects it only draws one object. After debugging this FOREVER with everything looking right I found out that the object3D's are all using the same model reference and since I'm changing the actual Model variables when drawing it out they all get the exact same position/rotation etc.

    Looking into this even further before posting I found out that I maybe should perform a "Deep clone" of the model before placing it in the Object3D. It took a while but I managed to write a deep clone function, only to get the error message that the class Model is "not marked as serializable.



    Now, my question is, how can I successfully perform a deep clone of a model? OR, even better, just cut the references of the model
    (Creating a new instance, because that is all I want, and it seems that people using deep cloning are using it for slightly different reasons.)





    Here is the error message I get when trying to deepclone the model:

    Type 'Microsoft.Xna.Framework.Graphics.Model' in Assembly 'Microsoft.Xna.Framework, Version=2.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d' is not marked as serializable.
  • 2/13/2008 7:46 PM In reply to

    Re: Deep Clone (Serialize) a Model

    Cloning the model is not the right way to deal with this.

    You should think of the model instance as a read-only archetype. If you have a forest made of 100 oak trees, you would still only load a single oak tree model. You would then make a separate structure, perhaps something like:

        class OakTree
        {
           Model model;
           Vector3 position;
        }

    You can then create as many OakTree instances as you like, but they all reference the same shared model.

    If your drawing code is not working when you try to do this, that just means you've implemented the drawing code wrong. Most likely you are trying to set the transform matrices inside the model too early, so one instance overwrites the transforms of the next. You should only set the transforms at the last possible moment, immediately before you draw each instance.
  • 2/13/2008 8:56 PM In reply to

    Re: Deep Clone (Serialize) a Model

    That's almost what I was hoping, but I can't find a way to draw the models without changing the models variables. (Changing the .Root variable)

    I've got that OakTree class, though named Object3D, which will be the base of all my 3DObjects, it has it's own position, rotation, scale and everything else, the problem is that my model is placed by changing the .Root variable of the model instance, and since it then overwrites all other object3D's before draw, they all come to one spot.

    Is there a better way to translate and move my object to position it at the object3D's position and rotation than what I'm currently doing?

    This is my code where I set the drawing position of the model.


    class Object3D : DrawableGameComponent
    {
    private Vector3 v3Position = new Vector3();
    private Vector3 v3Angle;
    private Matrix mRotation = Matrix.Identity;
    private float fScale = 1.0F;

    private Model mModel;
    private Matrix[] mBoneTransforms;
    private Matrix[] mPartTransforms;

    public override void Update(GameTime gameTime)
    {
    mModel.Root.Transform = mRotation;
    mModel.Root.Transform *= Matrix.CreateScale(fScale);
    mModel.Root.Transform *= Matrix.CreateTranslation(v3Position);


    base.Update(gameTime);
    }


    public override void Draw(GameTime gameTime)
    {
    mModel.CopyAbsoluteBoneTransformsTo(mBoneTransforms);

    // Draw
    foreach (ModelMesh mesh in mModel.Meshes)
    {
    foreach (BasicEffect effect in mesh.Effects)
    {
    effect.World = mBoneTransforms[mesh.ParentBone.Index];
    effect.View = Camera.ActiveCamera.View;
    effect.Projection = Camera.ActiveCamera.Projection;

    effect.EnableDefaultLighting();
    effect.PreferPerPixelLighting = true;
    }
    mesh.Draw();
    }
    base.Draw(gameTime);
    }
    }
  • 2/14/2008 4:45 AM In reply to

    Re: Deep Clone (Serialize) a Model

    I made this exact complaint about mutable/immutable models in an earlier thread. Maybe Shawn has another idea, but here is what I did as a quick hack:

    1) After loading the model, I created an array of the original bone transforms and stuffed it into the Model's Tag property.
    2) My "OakTree" class was really a "Character" and I gave it a Matrix[] absoluteTransforms;
    3) In update: I restored the original transforms from the Model's tag and applied new transforms for that particular character instance
    4) all during Update: used CopyAbsoluteBoneTransforms to move the transforms into the Character instance's absoluteTransforms
    5) During Draw: used the absoluteTransforms to set the BasicEffect parameters

    Hopefully that helps!

    There is a Custom Model sample also if you need to customize the behavior of the model more fully and hopefully a future version of the Model class will address this common problem.
  • 2/14/2008 12:27 PM In reply to

    Re: Deep Clone (Serialize) a Model

    Answer
    Reply Quote
    Brandon: that seems way overcomplicated to me!

    The problem here is just that he's setting mModel.Root inside the Update method. That's no good, because the data gets overwritten before the next Draw.

    The solution is trivial: just move the lines that set mModel.Root from Update to the top of the Draw method.

  • 2/14/2008 1:52 PM In reply to

    Re: Deep Clone (Serialize) a Model

    I'll admit: I didn't read his code!

    You need to do what I described when you have an articulated body. In the case I was talking about, I had shoulder, elbow, and wrist joints of an arm. I was calculating rotation matrices in the Update method based on the state of the game pad triggers (think rock'em sock'em robots ;-)

    In this case, yes, just change the root in draw. Sorry, it was 430 in the morning... graduating early has me overworked... too much Red Bull...
  • 2/14/2008 6:11 PM In reply to

    Re: Deep Clone (Serialize) a Model

    Finally it works! Thanks so much for the help! Even though it's seems like that kind of code should be in the Update method but since it worked so pain free I'm very happy with the solution.

    I actually almost got it to work with Brandons solution aswell, but it did involve a lot extra code that didn't seem to efficient, but it was a good excersize in the end :)

    Thanks a lot both of you :)
  • 12/25/2008 1:06 AM In reply to

    Re: Deep Clone (Serialize) a Model

    Is this the most efficient method for creating static geometry in a scene, such as a forest of trees? Would instancing - such as in the Instanced Model example - be more efficient? I am rendering a stadium, and currently I'm loading a huge number of seats as a single model. The nice thing about that method is that I don't have to transform a large number of objects in my render loop, but I'm running into memory limitations.
  • 12/25/2008 10:29 PM In reply to

    Re: Deep Clone (Serialize) a Model

    Actually one large mesh for many similar objects wouldn't be too bad unless your vertex buffer has gotten too large. However when you created the Stadium you probably created one chair and copied it around. In that case each chair is probably a separate mesh. Flattening the model so that it's all one mesh would reduce draw calls, though it won't help if your vertex buffer is too large. That's a question only you and a performance monitor can answer.
  • 12/29/2008 4:07 AM In reply to

    Re: Deep Clone (Serialize) a Model

    cpaganucci:
    Is this the most efficient method for creating static geometry in a scene, such as a forest of trees? Would instancing - such as in the Instanced Model example - be more efficient? I am rendering a stadium, and currently I'm loading a huge number of seats as a single model. The nice thing about that method is that I don't have to transform a large number of objects in my render loop, but I'm running into memory limitations.


    The most efficient method highly depends on your game. Since the seats aren't transforming, you probably don't need instancing. However, If you have 60,000+ seats, that's a whole heck of a lot of vertices and memory would be a limitation. You could try making one model for each shape of stadium section. This would enable you to cull whole sections at once as well as cut down your memory overhead to at least 1/4th for a symmetrical stadium.
  • 12/29/2008 7:51 AM In reply to

    Re: Deep Clone (Serialize) a Model

    cpaganucci:
    Is this the most efficient method for creating static geometry in a scene, such as a forest of trees? Would instancing - such as in the Instanced Model example - be more efficient? I am rendering a stadium, and currently I'm loading a huge number of seats as a single model. The nice thing about that method is that I don't have to transform a large number of objects in my render loop, but I'm running into memory limitations.


    Mesh instancing works good too. I've had 500k building size cubes, and another 500k trees clumped around a 1024x1024 terrain still rendering at over 100fps. The terrain used a quadtree for culling and I had another quadtree for the mesh instances which split the quadtree once a definable number of instances had been added to it. I think from 2k - 5k instances per leaf worked well depending how many vertices in the model. Should handle your 64k seats easily.
  • 12/31/2008 1:32 AM In reply to

    Re: Deep Clone (Serialize) a Model

    Thanks for the feedback! I've got about 15k chairs which need to be fairly detailed (this is an architectural walkthrough, not a game). So far shader instancing from the InstancedModel example is looking like the winner. The first technique described in the thread combined with a simple culling algorithm netted me 10-40 FPS depending on how many chairs were visible. Hardware instancing gave me a more consistent framerate of about 13 FPS. Shader instancing is giving me a consistent rate of about 30, which is perfect for my needs.

    One thing I'm still concerned about is texturing. I'm using baked textures for the arena which gives realistic looking lighting with minimal performance hit, but I can't use baked textures on the instanced models since that would require each of them to have a unique texture. I'm guessing I can modify the instance shader to do a light map, but I'm not well versed in writing shaders so it may be a bit of a challenge.
Page 1 of 1 (12 posts) Previous Discussion Next Discussion