Fbx Animated Model deforming when added to XNA - c#

Hey my problem is I have created the perfect model for what I want in 3dsMax I rigged a biped using the skin modifier,
I correctly positioned the envelopes and I animated the biped using frames and then exported as an .fbx and loaded it into XNA using the SkinnedModelPipeline.
Once Loaded into XNA the model deforms and it only seems to be on the models right arm.
As I'm only a new member I can't post images at this moment in time so I am sending a link to the images online.
3dsMax Model:
Model loaded in
Draw function for Models
//an array of the current positions of the model meshes
this.bones = animationPlayer.GetSkinTransforms();
for (int i = 0; i < bones.Length; i++)
{
bones[i] *= Transform.World;
}
//remember we can move this code inside the first foreach loop below
//and use mesh.Name to change the textures applied during the effect
customEffect.CurrentTechnique = customEffect.Techniques[technique];
customEffect.Parameters["DiffuseMapTexture"].SetValue(diffuseMap);
customEffect.Parameters["Bones"].SetValue(bones);
customEffect.Parameters["View"].SetValue(Game.CameraManager.ActiveCamera.ViewProperties.View);
customEffect.Parameters["Projection"].SetValue(Game.CameraManager.ActiveCamera.ProjectionProperties.Projection);
foreach (ModelMesh mesh in model.Meshes)
{
//move code above here to change textures and settings based on mesh.Name
//e.g. if(mesh.Name.Equals("head"))
//then set technique and all params
foreach (ModelMeshPart part in mesh.MeshParts)
{
part.Effect = customEffect;
}
mesh.Draw();
}
I've goggled around for a long time and i cant find anything that would solve this problem.
Any help is appreciated.

When transforming bones you do not move them in 'world' space.
They should inherit their parents transformation, so all bones has to be moved in relation to their parent.
Also issues with the scale\translation matrix in 3dsmax can cause similar looking issues.
This can be checked for by re-importing the FBX back into 3dsmax, if it looks good after doing that then it's the issue is in the code.

Related

Tiled object position doesn't match MonoGame position

I have an issue when importing Tiled maps with Object layers into a MonoGame project. Everything is pretty much working great; I can import the Tiled map into the project and render the map with the use of MonoGame.Extended.
My issue starts when I try to use an Object from an Object Layer in the Tiled map. I can access the object, and I can access its properties (position, etc) just fine. In fact, when accessing the object's properties, they output exactly as they should. Below are images to clarify:
This is the image of the object within the Tiled map editor
And below is the code where I import the map, collect the object's information, and assign that information (position, in this case) to another object (the player)
gameMaps.Add(MapBuilder.LoadTiledMap("TestMap"));
gameMapRenderer = new TiledMapRenderer(graphicsDevice);
var viewportAdapter = new BoxingViewportAdapter(GameInstance.Instance.Window, graphicsDevice, 1440 / 4, 810 / 4);
mainCamera = new Camera2D(viewportAdapter);
var player = new Player();
var playerStartPos = new Vector2();
foreach(var obj in gameMaps[0].ObjectLayers[0].Objects)
{
if (obj.Name.Equals("PlayerStart"))
{
playerStartPos = obj.Position;
break;
}
}
player.position = playerStartPos;
entities.Add(player);
mainCamera.LookAt(player.position);
But below is the image that demonstrates the issue:
Issue as an image
The sprite/character is the player object that is assigned the position, in case that wasn't clear.
To explain: I am able to get the object's position and assign it to my 'Player' object, and my player is then at the correct position per what the object's position is in the Tiled map editor. However, the Tiled map itself is actually rendering at an incorrect position- even though I never make any adjustments to the position of the map as a whole.
Some further details that might help:
In the Tiled map editor, the position x0,y0 is the utmost top tile of the map. However, in MonoGame, if I go the same position- the Tiled map is actually rendered/placed some dimensions below. This means that the positioning of the map is incorrect with what it should be.
Below is an image showing what that position is in MonoGame, and how it is not properly correlating with what that position is in Tiled.
MonoGame screenshot
After speaking a bit to the creator of Monogame.Extended, we narrowed down the issue. It was actually two things:
In the Tiled map editor, the grid system for isometric maps is different from the grid system Monogame uses to render everything. Tiled's grid system for isometric maps is a normal grid but rotated to match the isometric view, whereas Monogames is just a normal grid. This causes the position (x,y) of Objects in Tiled to be imported into Monogame with a position value that doesnt match with where it should actually be in Monogame- which explains the position being wrong in the image above. Monogame.Extended's creator took note on the bug but said a fix isnt certain because it would require a formula for converting an isometric Tiled position to a Monogame position.
Because my sprites had extra padding at the top, it was causing the overall map to render x many pixels lower than at what should be the proper 0 position. It had something to do with the map being generated in Monogame via the sprites dimensions, instead of the maps. Not a giant problem, honestly, since a workaround could be presumably made in a custom implementation of the TiledMapRenderer.
I can post the link to the Monogame.Extended discussion later.

Odd geometry with 3D models XNA + Blender

Ok, this is hard to explain without pictures. I made a very limited model of a glock in Blender with an extruded cube making up the base and a scaled cube making up the barrel.
In Blender, It looks fine:
However, after exporting the model to .fbx and loading it into the compiler, it comes out like this:
I don't know exactly what is going on. Everything on the model is properly UV Mapped and the coordinates are correct, It just seems the translation is.. off..
Here is my drawModel code:
private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.World = world;
effect.View = view;
effect.Projection = projection;
}
mesh.Draw();
}
}
Any pointers will be helpful!
EDIT: After Applying rotation, location, and scale, I was able to get them in the right position, but why does it look transparent?
Thank you for all the help!
As Nikola mentioned, in the later versions of Blender, they have proper XNA support.
Here's a screenshot of the settings I chose when exporting a model:
Why this happens:
Your Depth Buffer is not enabled, so when your GPU draws the barrel first, then the stock/handle, the handle is drawn on top of the barrel, even though some parts of it are supposed to be invisible because they would be hidden by the barrel.
How to fix:
Enable Depth Buffer as other answer suggests. And/Or order meshes in your model based on distance from camera, and draw tehm in order from the nearset to the farthest. This may not seem usefull now, but when you start working with transparent objects, you will see why this is a good thing to learn.
Enable depth buffer:
GraphicsDevice.DepthStencilState = DepthStencilStates.Default;
And to Draw a model in Xna you can follow this tutorial, that shows how the bone transforms have to be applied to get the meshes in right position.

XNA - How to access a texture from .x model?

I am just getting into XNA programming and have been unable to figure out how can I access the texture from a ".x" model. I am using a custom shader to display my model (just a cube with a texture mapped on it) with the filters set to point. To do this I needed to pass the effect my texture file which needed to be imported separately from my model or else it would complain since it is included in my model as well. This works perfectly how I want it, however this isn't really an agreeable method when I have many different models with their own textures.
My question is:
How am I able to access the texture included in my model directly from it and send that to my shader? Or am I able to access it directly with HLSL?
What I have tried:
I have found posts saying that it can assigned to a texture variable with:
Texture2d texture = ((BasicEffect)model.Meshes[0].Effects[0]).Texture
When I tried this the game runs but the cubes are just black. I can see that the texture variable is holding info and has the right dimensions but I can't tell if it is correctly holding the actual image. When I used just the BasicEffect they rendered just fine with their texture.
Update:
I have managed to get this to work after a little bit of fiddling. My game loads in a few hundred of the same cube and upon creation of each it would try save the texture of the model using the code above and then go through the mesh parts and change the effects to my custom effect. I discovered that the first cube created would save the texture okay but any subsequent cubes created would complain that they can't be cast as a BasicEffect. This resulted in one textured cube and then a lot of black ones. I am guessing that when it reuses the same model over and over like that it will just use the one that was modified to use my custom effect which was done on the first instance of the cube. Is this normal? I have got them all to render as textured by changing the texture variable to static.
Please observe that you are assigning the texture of your model to a temporary Texture2D variable, and not setting the Texture present in the Effect currently tied to your mesh.
If you do the following:
Texture2D textureToSet = Content.Load<Texture2D>("MyTex");
//Keep in mind that this method requires a basic effect type and that only one
//effect is present on each mesh to work properly.
foreach(Mesh mesh in model.Meshes)
{
((BasicEffect)(mesh.Effects[0])).Texture = textureToSet;
}
The quirky stuff going on inside the foreach is simply that you are grabbing the effect, then casting it to a BasicEffect and using its Texture property to give it a new texture to draw when used. Please see the documentation and Shawn's blog for a more detailed introduction.
If anyone else is wondering about this as I was then saving the texture using:
Texture2d texture = ((BasicEffect)model.Meshes[0].Effects[0]).Texture
This does work but there is one thing to watch for which is what was causing me problems. If you change the effect of the model from the default BasicEffect for one instance it will be changed for every instance of the model created thereafter. So you will only be able to use the above code before you change the effect for the first time on a particular model.
I later found this book which describes exactly how to extract the texture and other information from a model: 3D Graphics with XNA Game Studio 4.0 by Sean James - Specifically chapter 2

import scene in xna

I have a scene that contains mutiple objects. How can i import it in xna and mentain each objects position? right now i export the scene in .fbx and load it in a model like this :
cube.model = contentManager.Load<Model>("cub");
but the objects don't retain their position and are all gathered in one point.
I need a method to import all the objects as individual objects but to retain the objects position in the scene?
(i.e. i need to import the scene so that i may manipulate the objects and retain their position in the scene so that i shouldn't reposition all the objects by myself)
Each object's scene position is in the fbx. The way to get it and implement it is to create a matrix array to hold every object's transform relative to the scene origin, then utilize the appropriate transforms when setting the effect.World for each object during draw time.
//class variables
Matrix[] objectTransforms;
//LoadContent section
cube.model = contentManager.Load<Model>("cub");
objectTransforms = new Matrix[cube.model.Bones.Count];
cube.model.CopyAbsoluteTransformsTo(objectTransforms);// the magic is done here
//draw method
foreach(ModelMesh mm in cube.model.Meshes)
{
foreach (BasicEffect bfx in mm.Effects)
{
bfx.World = objectTransforms[mm.ParentBone.Index] * whateverLocalTransformYouWant;
//draw here
}
}
Without utilizing 'objectTransforms' all objects will be drawn with their local origins located at the world origin, which sounds like what you are experiencing.
I personally made a level editor for most of the things in my game, but I do have a large scene in blender that links to other models. That way I can arrange all the level pieces in blender. When I export each individual piece, it does retain is global position and import correctly in the game. I would say that the issue resides in your fbx exporter. There should be an option to preserve location.
What modelling program do you use? If you use blender, there is an fbx exporter set made specifically for XNA that you should use.

XNA not loading model textures automatically

I have a very n00b like question here .. I have this small XNA game in which I tried importing a 3D model already made and provided by Microsoft. The problem is XNA isn't loading the textures associated with this model, even though it makes sure that the associated with the model are present in the project directory (compiler gives an error if it can't find these textures), .. So basically I just see a big clay model :P ..
This picture shows the result I'm getting:
This is what it should be like:
Is there anything which I'm missing here ? Shouldn't XNA automatically apply all textures associated with a specific model ?
When you are rendering your dude.fbx model, make sure that in the loop for drawing the model that you have something like the following:
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
}
}
This is off the top of my head, so the method calls might not be correct.
Xna does not automatically load the textures for the model.
The exception you're getting when the texture is not present is thrown by the Xna's resource compiler and is not related to actually importing anything.
The way you would solve this is by loading the texture manually in LoadContent() or anywhere else where you have a ContentManager using:
modelTexture = Content.Load<Texture2D>("mytexture");
and then add the texture either as a parameter if you have a custom effect or put it in the Texture property on your BasicEffect instance when you draw it:
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect eff in mesh.Effects)
{
eff.TextureEnabled = true;
eff.Texture = modelTexture;
}
mesh.Draw();
}
(drawing should obviously not be done in LoadContent() though)
Notice the eff.TextureEnabled = true; which is required to activate textures when using BasicEffect.

Categories

Resources