ModelLoader

Jan 11, 2011 at 3:10 PM

Why sometimes I can't load a model when I call the loader.Load()?

Sometimes it works, sometimes no!

I use this code (with GoblinXNA 3.5.1)

 CaricaModello loader = new CaricaModello();
 Model nome = (Model)loader.Load("", "p1_wedge");
 GeometryNode nodoNome = new GeometryNode("Navetta");
 nodoNome.Model = nome;

The code of class CaricaModello.cs is similar to ModelLoader.cs

  public class CaricaModello : IModelLoader
    {
       
        public IModel Load(String path, String modelAssetName)
        {
            path = (path.Equals("")) ? State.GetSettingVariable("ModelDirectory") : path;
            String filePath = Path.Combine(this.path, modelAssetName);
            XNAModel xnaModel = State.Content.Load<XNAModel>(@"" + filePath);

            // Get matrix transformations of the model
            if (xnaModel != null)
            {
                Matrix[] transforms = new Matrix[xnaModel.Bones.Count];
                xnaModel.CopyAbsoluteBoneTransformsTo(transforms);

                IModel model = new GoblinXNA.Graphics.Model(transforms,xnaModel.Meshes,null);
                return model;
            }
            else
            {
                Log.Write("Il Modello " + filePath + " non esiste ");
                return null;
            }
        }
    }

The Debug give me this error

 Error loading "p1_wedge". GraphicsDevice component not found.

Coordinator
Jan 11, 2011 at 4:14 PM

Which line number throws that exception?

I never encountered the case where it sometimes load and sometimes not.

Ohan

Jan 11, 2011 at 6:20 PM
Edited Jan 11, 2011 at 6:30 PM

the line is: XNAModel xnaModel = State.Content.Load<XNAModel>(@"" + filePath);

I load the model in my augmented reality thesis project. By a button (in a windows form)  I open a thread by the istruction

 using (game = new Game1(panel1.Handle))
            {
                t1 = new Thread(new ThreadStart(game.Run));
                t1.Start();               

            }

In the Game1 Constructor there are these instructions:

IntPtr tempRif;

  public Game1(IntPtr handle)
        {
           
            graphics = new GraphicsDeviceManager(this);
            graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
            System.Windows.Forms.Control.FromHandle((this.Window.Handle)).VisibleChanged += new EventHandler(Game1_VisibleChanged);
            tempRif = handle;
            //State.ThreadOption = (ushort)ThreadOptions.MarkerTracking;
            Content.RootDirectory = "Content";
        }

then in the event handlers there are these istructions

public void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            PresentationParameters pp = e.GraphicsDeviceInformation.PresentationParameters;
            pp.DeviceWindowHandle = tempRif;

        }

        private void Game1_VisibleChanged(object sender, EventArgs e)
        {
            if (System.Windows.Forms.Control.FromHandle((this.Window.Handle)).Visible == true)
            {
                System.Windows.Forms.Control.FromHandle((this.Window.Handle)).Visible = false;

            }
        }

In this way I can use a windows Form and a XNA game (the output of webcam it is on the panel) in the same time.

Sometimes it works sometimes no!! (maybe it's a thread problem?)

thanks for help

Coordinator
Jan 12, 2011 at 3:10 AM

Yes, it is thread problem, and it's XNA related, not Goblin.

The GraphicsDevice is not guaranteed to be initialized until the "Initialize()" function is called in the main Game class. If you start the thread in your Game constructor, then you can never guarantee the initialization of GraphicsDevice before you load any contents (or any operation that requires GraphicsDevice).

Ohan

Jan 12, 2011 at 8:55 AM

If I load the model in the LoadContent method should work? I call the LoadContent Method and then the Create Objects() method in the Initialize method

 

protected override void LoadContent()
        {
            CaricaModello loader = new CaricaModello();
            orco = (Model)loader.Load("", "dude");
            base.LoadContent();
        }

Coordinator
Jan 12, 2011 at 1:54 PM

Make sure your base.Initialize() function in your Initialize method is called at the very beginning of your Initialize method since LoadContent is called in the base.Initialize() function.

Ohan

Jan 15, 2011 at 7:33 PM

What if I want to do the same CaricaModello class ..but I want to make it flexible by adding a  .fbx files but not necessarily from the Content folder in the project..I mean from any directory..is that possible?

in such case I will need to change this line of code:

Microsoft.Xna.Framework.Graphics.Model xnaModel = State.Content.Load<Microsoft.Xna.Framework.Graphics.Model>(@"" + filePath);

 

how should it be?

Thanks

Coordinator
Jan 17, 2011 at 3:10 AM

Content.Load method can only load things that are compiled to .xnb file.

If you want to load .fbx or any model files on the fly, you either need to compile .xnb file on the fly (see http://create.msdn.com/en-US/education/catalog/sample/winforms_series_2) or write your own method that parses the .fbx file.

In case you write your own method that parses the .fbx file, you need to write your own Model class that renders the information (vertices, normals, etc) correctly, and you CANNOT use the existing XNA's Model or GoblinXNA's Model class because those classes have an assumption that the model is loaded from an .xnb file.

It'll be more general to go with the .xnb conversion way, and that's what I recommend.

 

Ohan

Jan 18, 2011 at 10:57 PM

Thanks a lot for your help..I really appreciate your reply.

I just found it easier to follow the tutorial. However, there are some differences. I am not using a windows form, I am actually working on an Augmented Reality project in which I am using GoblinXna.

I modified the code in the tutorial so that it can fit in my case by doing the following:

--> I have a virtual keyboard and a screen which displays the .fbx files that I need to import on the fly from a specific location on the desk,,,in such case I do not need the OpenFileDialog

--> I have also modified the LoadModel function to be as follows:

public void LoadModel(string fileName)

{

  ContentBuilder contentBuilder;            

ContentManager contentManager;          

 ModelViewerControl modelViewerControl = new ModelViewerControl() ;
  contentBuilder = new ContentBuilder();
  contentManager = new ContentManager(modelViewerControl.Services,contentBuilder.OutputDirectory);

  // Unload any existing model.            

modelViewerControl.Model = null;            

contentManager.Unload();

// Tell the ContentBuilder what to build.          

 contentBuilder.Clear();            

contentBuilder.Add(fileName, "Model", null, "ModelProcessor");

 // Build this new model data.            

string buildError = contentBuilder.Build();
            if (string.IsNullOrEmpty(buildError))          

 {    // If the build succeeded, use the ContentManager to                

   // load the temporary .xnb file that we just created.              

 modelViewerControl.Model = contentManager.Load<Microsoft.Xna.Framework.Graphics.Model>("Model");              

else 

{ // If the build failed, display an error message.              

MessageBox.Show(buildError, "Error");            

}

}

 

I call this LoadModel function from the "Ok" button event handler in the virtual keyboard

 

I managed to do the references and to add the other classes correctly. However, I always get an error in  string buildError = contentBuilder.Build(); which says Missing Asset in the Temp location which the MSBuild should use. I used the project in the tutorial to import the same model and it was added successfully which ensures that there is no problem in loading the texture for example.

There is just a small remark, the default folder location where my virtual screen and keyboard opens (instead of the FileOpenDialog) is saved in  Properties.Settings.Default.Importpath and I do not pass it somehow to the LoadModel function, and I guess that the ContentManager Load function needs to have the path of the given file name. This problem is resolved with the OpenFileDialog because its properties are set including the filepath. However, I cannot use it in my case as I will have to have a virtual keyboard and I will use a datagloves that will capture the input inside the game screen.

 

So, could you please advise me in this. I would really be very thankful. I am really sorry for such very long post.

Thanks in advance

 

Jan 18, 2011 at 11:41 PM

UPDATE: I tried to use OpenFileDialog for the time being until I can resolve that and now I have no problem with string buildError = contentBuilder.Build() it worked fine

now the problem turned out to be in line

modelViewerControl.Model = contentManager.Load<Microsoft.Xna.Framework.Graphics.Model>("Model");

when I debugged it, I figured out that this line causes a runtime error when it goes through

public object GetService(Type serviceType)      

 {            object service;
            services.TryGetValue(serviceType, out service);
            return service;      

 }

I was not able to detect why this runtime error happened. could you please help me in that

Apr 21, 2011 at 1:44 PM
ohanoda wrote:

In case you write your own method that parses the .fbx file, you need to write your own Model class that renders the information (vertices, normals, etc) correctly, and you CANNOT use the existing XNA's Model or GoblinXNA's Model class because those classes have an assumption that the model is loaded from an .xnb file.

It'll be more general to go with the .xnb conversion way, and that's what I recommend.

Hi Ohan,

Wouldn't it be possible to parse the file manually, and then construct a CustomMesh instance, and pass this in the constructor of a PrimitveModel?

PrimitiveModel pyramidModel = new PrimitiveModel(pyramid);
GeometryNode pyramidNode = new GeometryNode();
pyramidNode.Model = pyramidModel;

I had this idea to combine this with Collada.net, to enable loading Collada files at run-time.

What are your thoughts on this?

Best regards,
Lex 

Apr 21, 2011 at 5:37 PM
Edited Apr 21, 2011 at 5:38 PM

Yes, that sounds like it should be possible.  Remember that files that contain 3D geometry can get really complicated really fast, so parsing the file manually and converting into a different format can prove to be difficult (this difficulty will probably be correlated to the complexity of your 3D scene, so if you only have basic shapes, you might be OK).

About a year ago, I took a piece of Collada for XNA code that I had found online and tweaked it to work within Goblin and specific set of COLLADA files I needed to load.  It worked on the models I had to convert, but it didn't work on some of the other files I downloaded from the warehouse, so we didn't include it into Goblin.  However, if you're interested I might be able to share that code with you.  By the way, the solution I am referring to an extension of the Content Pipeline, so we parsed the models at compile time.  But you could use the workflow described in this thread to make it load models at run-time.

Please let us know if you make any progress.  Building robust COLLADA support into GoblinXNA would be really nice.  That way we could load models from Google 3D Warehouse without having to convert them to .FBX or .X, which is a painful process.

Cheers,
Mengu