(xna) need help spotting a problem (2 small functions)

Started by
5 comments, last by MJP 15 years, 9 months ago
Ok have been trying for a couple of days to figure this out, using here as a last resort. Aim of these two functions is to load in and display a 3D model. Some simpler 3D models with only 1 texture work fine with these. Has a range of issues depending on the 3Dmodel. Sometimes loads them in with only a couple of textures and the rest white, on more complex meshes gives me an issue with index out of bounds for textures[].
[source lang=csharp]

Model Model1;
Texture2D[] model1Textures;

private Model LoadModel(string assetName, out Texture2D[] textures)
{
  Model newModel = Content.Load<Model>(assetName);

  textures = new Texture2D[newModel.Meshes.Count];
  int i = 0;
  foreach (ModelMesh mesh in newModel.Meshes)
  foreach (BasicEffect currentEffect in mesh.Effects)
      textures[i++] = currentEffect.Texture;
              
   foreach (ModelMesh mesh in newModel.Meshes)
      foreach (ModelMeshPart meshPart in mesh.MeshParts)
            meshPart.Effect = effect.Clone(device);

  return newModel;
}

private void DrawModel1()
{
  Matrix[] Model1Transforms = new Matrix[Model1.Bones.Count];
  Model1.CopyAbsoluteBoneTransformsTo(Model1Transforms);

  int i = 0;
  foreach (ModelMesh mesh in Model1.Meshes)
  {
     foreach (Effect currentEffect in mesh.Effects)
  {
    Matrix worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) *       Matrix.CreateRotationY(rotateVal) * Matrix.CreateTranslation(new Vector3(xval, 0.1f, zval));

  currentEffect.CurrentTechnique = currentEffect.Techniques["Textured"];
                        currentEffect.Parameters["xWorld"].SetValue(Model1Transforms[mesh.ParentBone.Index] * worldMatrix);
  currentEffect.Parameters["xView"].SetValue(viewMatrix);
                       currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);                    

currentEffect.Parameters["xTexture"].SetValue(model1Textures[i++]);
  }
  mesh.Draw();
  }
}


[Edited by - soarah on June 30, 2008 11:15:06 PM]
Advertisement

Based on the remark over here, I'd guess setting the cloned effects on the meshparts somehow increases the number of effects referenced in the ModelMesh.Effects collection. You could try putting the 'clone loop' before the texture loop to see if that works.

As for the out of bounds exception, meshes may contain multiple meshparts with their own textures, so Texture2D[newModel.Meshes.Count] may well be too small. You could try using a List<Texture2D> instead. It'd be easier to tell where this exception comes from if you could provide a line number where it happens though.

Anyway, you might not need this complicated way of handling the textures. I don't know if you implemented this for a specific reason, but by default the XNA content pipeline already sets up the appropriate effects on the meshes and supplies them with the proper textures. If you're sure currentEffect.Texture is populated properly (since you use it in the load code), the code below might already do for rendering.

[source lang=csharp]Model Model1;Texture2D[] model1Textures;private Model LoadModel(string assetName, out Texture2D[] textures){    Model newModel = Content.Load<Model>(assetName);    return newModel;}private void DrawModel1(){    Matrix[] Model1Transforms = new Matrix[Model1.Bones.Count];    Model1.CopyAbsoluteBoneTransformsTo(Model1Transforms);    foreach (ModelMesh mesh in Model1.Meshes)    {        foreach (Effect currentEffect in mesh.Effects)        {            Matrix worldMatrix = Matrix.CreateScale(0.01f, 0.01f, 0.01f) * Matrix.CreateRotationY(rotateVal) * Matrix.CreateTranslation(new Vector3(xval, 0.1f, zval));            currentEffect.CurrentTechnique = currentEffect.Techniques["Textured"];            currentEffect.Parameters["xWorld"].SetValue(Model1Transforms[mesh.ParentBone.Index] * worldMatrix);            currentEffect.Parameters["xView"].SetValue(viewMatrix);            currentEffect.Parameters["xProjection"].SetValue(projectionMatrix);                     currentEffect.Parameters["xTexture"].SetValue(currentEffect.Texture);        }        mesh.Draw();    }}

Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
Thanks for the reply. Yeah I am reasonably new to XNA; so still playing around with it.

With the drawModel1() you wrote, it says.

currentEffect.Parameters["xTexture"].SetValue(currentEffect.Texture);


'Microsoft.Xna.Framework.Graphics.Effect' does not contain a definition for 'Texture'

Of course, sorry about pointing you down the wrong road [smile]

It depends on what kind of effect you're using for your mesh though. If you are using a BasicEffect (which is the default), then mesh.Draw() will use the appropriate textures for the subparts automatically. Essentially the BasicEffect objects in your model already have a reference to the correct to use. This would mean you can simply omit the 'texture line' from the code I posted. You can find some more information on this over here.

If you're using a custom HLSL effect, then there are a few ways to do this. The 'right way' would be to write a custom content processor to assign your custom effect to the model automatically. This way you shouldn't need any special code either and can use something similar to the above code, give or take a few custom parameters. I have to admit however that my experience with these processors is very limited, so hopefully someone (MJP?) will chip in some more useful information [wink]

Alternatively you could also handle a custom effect in your own code instead of using a content processor, but that's a bit messy messy (esp if you're just starting) and explaining it without knowing if you need it would only complicate matters. If you want to see some basic samples of how custom effects can be handled, here are some samples.

Hope this does help :)
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
Quote:Original post by remigius
If you're using a custom HLSL effect, then there are a few ways to do this. The 'right way' would be to write a custom content processor to assign your custom effect to the model automatically. This way you shouldn't need any special code either and can use something similar to the above code, give or take a few custom parameters. I have to admit however that my experience with these processors is very limited, so hopefully someone (MJP?) will chip in some more useful information [wink]


AFAIK its the importer that decides what effect gets bound to a model. But while you could write a custom importer for one of the model formats, it sounds about as much fun as...something that's not very much fun at all. I suppose you could override that in a custom content processor, but sounds kinda hacky compared to binding an effect to your model in your 3D modeling app. But I suppose it's an option if you don't want to go through the work of setting up XSI or 3dsmax or whatever to use your custom effects. If you did make a custom processor you could give it a public parameter with an enum or string value that you could set via the Properties windows in Visual Studio.

Probably the easiest option is to just ignore whatever effect is actually bound to the ModelMeshPart and use whatever custom effect you want. I believe this is done in the ShipGame starter kit, which uses a custom NormalMapping effect to render all the geometry.
It took me a few days but solved the problem. It was the custom effects file I was using, didnt seem to like complex 3D models with lots of textures.

Also discovered that XNA will almost load/apply textures to your 3D model by itself? which is amazing.

Cheers for all the help

p.s forgot to add instead of a custom effects file; just used BasicEffect which is built in?
Quote:Original post by soarah

Also discovered that XNA will almost load/apply textures to your 3D model by itself? which is amazing.



Yup. If your model specifies textures and shader constants, they will be set in the corresponding effect by the content processor. You can control some aspects of how this is done by going to the properties of any model and expanding the content processor node. For example, you can set whether you want textures loaded to a compressed DXT format or an uncompressed format.

This topic is closed to new replies.

Advertisement