I have a model that I made in Blender that has individual meshes in it. When I put it in an Xna project and try to move the model via Matrix translation, all the individual meshes go in seperate directions. My code basicly updates each mesh individually. Is there better code i should use to make the model's meshes move together?
If you call this:
private void DrawModel(Model model, Matrix worldMatrix)
{
//Matrix array for number of bones
Matrix[] modelTransformations = new Matrix[model.Bones.Count];
//Put bones into matrix array
model.CopyAbsoluteBoneTransformsTo(modelTransformations);
//for every model
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
//Add default lighting
effect.EnableDefaultLighting();
//Set default postion
effect.World = modelTransformations[mesh.ParentBone.Index] * worldMatrix;
//Set view
effect.View = camera.viewMatrix;
//Set projection
effect.Projection = camera.projectionMatrix;
}
//Draw Model
mesh.Draw();
}
}
And then translate the world matrix that you put in like this:
modelWorld *= Matrix.CreateTranslation(XDir, YDir, ZDir);
You should have no problems. At least, that's how I do it.
Related
Hallo I'm writting little RPG about Ants in XNA 4.0. I have made LoadModel class to fbx model load, and to create bounding spheres. I have one general bounding sphere at the model created by merging model mesh. Now i created model with additional sphere which represent my bounding sphere in game. I just checking if the Mesh name is "BoundingSphere" and when it is I'm adding mesh.BoundingSphere to my array of bs.
Now i dont now how to update those bs...
My code attempts:
private void buildBoundingSphere()
{
BoundingSphere sphere = new BoundingSphere(Vector3.Zero, 0);
List<BoundingSphere> spheres = new List<BoundingSphere>();
foreach (ModelMesh mesh in Model.Meshes)
{
if (mesh.Name.Contains("BoundingSphere") )
{
BoundingSphere transformed = mesh.BoundingSphere.Transform(modelTransforms[mesh.ParentBone.Index])
spheres.Add(transformed);
sphere = BoundingSphere.CreateMerged(sphere, transformed);
}
}
this.boundingSphere = sphere;
this.spheres = spheres.ToArray();
}
Now the BoundingSphere array get/set:
public BoundingSphere[] spheres
{
get
{
// No need for rotation, as this is a sphere
List<BoundingSphere> spheres = new List<BoundingSphere>();
foreach (ModelMesh mesh in Model.Meshes)
{
Matrix worldTransform = Matrix.CreateScale(Scale)* Matrix.CreateTranslation(Position);
if (mesh.Name.Contains("BoundingSphere")) {
BoundingSphere transformed = mesh.BoundingSphere.Transform(worldTransform);
spheres.Add(transformed);
}
}
return spheres.ToArray();
}
set{}
}
I have 2 spheres in model, and both of them are in the same place.
Thank you for any hint.
For one thing your setter is empty. If you're going for an auto-generated setter, use set; instead of set{}. So it seems everything you do in the buildBoundingSphere() is lost. Verify that first.
Another minor issue is that your bounding sphere accumulator starts as a point at the origin. This assumes the origin will be inside the final sphere, which is not true in general. Really you should somehow only generate the starting sphere once you know the first sphere.
I can't tell anything more from this snippet. If you're going to transform all the spheres in the getter, is it by the object's current transform? Scale and Position don't seem dependent on the mesh it's transforming the sphere of, so that construction of the worldTransform matrix could be moved outside the loop.
I'm new to 3D models so apologises if these seems basic. I've been searching the web and through my books but I'm lost.
I've made a model in 3D Studio Max 9. It consists of a variety of cubes, clyinders etc.
In Xna I've imported the model okay and it shows correctly. However, when I apply rotation, each component in the model rotates around it's own centre rather. I want the model to rotate as a singal unit rather than each component rotating on the spot.
I've linked the components in 3D Max and they rotate as I want in Max.
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
model = Content.Load<Model>("Models/Alien1");
}
protected override void Update(GameTime gameTime)
{
camera.Update(1f, new Vector3(), graphics.GraphicsDevice.Viewport.AspectRatio);
rotation += 0.1f;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);
Matrix worldMatrix = Matrix.Identity;
Matrix rotationYMatrix = Matrix.CreateRotationY(rotation);
Matrix translateMatrix = Matrix.CreateTranslation(location);
worldMatrix = rotationYMatrix * translateMatrix;
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = worldMatrix * transforms[mesh.ParentBone.Index];
effect.View = camera.viewMatrix;
effect.Projection = camera.projectionMatrix;
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
}
mesh.Draw();
}
base.Draw(gameTime);
}
EDIT: Rotating the object via it's properties works fine so I'm guessing there's something up with the code rather than with the object itself.
Translating the object also causes the objects to get moved independently of each other rather than as a single model and each piece becomes spread around the scene.
I have a sphere as FBX and a shader that enables me to have a texture inside of the sphere. Also inside of the sphere I have a camera. The goal is to have a simple panoramic viewer that is being driven by a headtracker.
The texture is being shown but the camera is reacting in a weird way:
When rotating the headtracker, the image is all over the place, jittery and not at all correlated to the actual movements. The headtracker input itself is correct, though.
See this video for further clarification. Each time I keep the tracker steady at first and then I move it. In the second half, the first three numbers are evaluated. The other three values are gyro.
I presume the problem to be in the following code, something about the Vectors(Vector3.whatever) could be off:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Microsoft.Xna.Framework.Color.CornflowerBlue);
foreach (ModelMesh mesh in skyDome.Meshes)
{
foreach (BasicEffect ef in mesh.Effects)
{
float aspectRatio = (float)graphics.GraphicsDevice.PresentationParameters.BackBufferWidth / (float)graphics.GraphicsDevice.PresentationParameters.BackBufferHeight;
Vector3 camPosition = Vector3.Transform(Vector3.Up, Quaternion.CreateFromYawPitchRoll(drehung, neigung, rollen));
ef.View = Matrix.CreateLookAt(Vector3.Zero, camPosition,Vector3.Forward);
ef.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspectRatio, 0.1f, 10000.0f);
ef.TextureEnabled = true; //Textur zulassen
ef.Texture = panoramaTextur; //Textur auf Model darstellen
}
mesh.Draw();
}
base.Draw(gameTime);
}
I have a project due very soon and I'm having lots of issues trying to load a model I made in 3D Studio Max. The model I made is what I want as my terrain in my XNA game. Here is what I've done so far:
Methods:
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Model terrainModel;
Vector3 terrainPosition = Vector3.Zero;
Vector3 cameraPosition = new Vector3(0.0f, 60.0f, 160.0f);
Vector3 cameraLookAt = new Vector3(0.0f, 60.0f, 160.0f);
Matrix cameraProjectionMatrix;
Matrix cameraViewMatrix;
LoadContent()
spriteBatch = new SpriteBatch(GraphicsDevice);
cameraViewMatrix = Matrix.CreateLookAt(
cameraPosition,
Vector3.Zero,
Vector3.Up);
cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(80.0f),
graphics.GraphicsDevice.Viewport.AspectRatio,
1.0f,
1000.0f);
terrainModel = Content.Load<Model>("alphastreet");
Draw(GameTime gameTime)
GraphicsDevice.Clear(Color.CornflowerBlue);
DrawModel(terrainModel, terrainPosition);
// TODO: Add your drawing code here
base.Draw(gameTime);
And then I want to Draw:
void DrawModel(Model model, Vector3 modelPosition)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.EnableDefaultLighting();
effect.PreferPerPixelLighting = true;
effect.World = Matrix.CreateTranslation(modelPosition);
effect.Projection = cameraProjectionMatrix;
effect.View = cameraViewMatrix;
}
mesh.Draw();
}
}
Everything else is just as an XNA file should look. The model it's self looks like a fairly straightforward street. However, upon XNA loading the model, it's just a big block in the window that loads.
I don't know what I'm doing that's making the model load like this, but it's making me pull my hair out. Any help would be appreciated.
Also, would anybody be able to direct me to walk-through/guide or a class that creates a First Person Shooter camera, since that is the game I'm going. I probably shouldn't have picked that, but it's way too late to change now, so if you could help there too you would really be saving my skin!
Thanks, Jake!
Is there more than one mesh in the model, and if so, have you tried rendering each one separately?
Have you tried using identity matrices for world and view to make sure these aren't the issue?
I assume you haven't made any other state changes to xna/directx, if so try disabling these.
For a FPS camera, you can just track the x and y rotation in float variables and update these each frame based upon how far the mouse has moved in x and y. From these you can generate a camera view matrix; something like the following:
var mx = Matrix.CreateRotationX(xangle);
var my = Matrix.CreateRotationY(yangle);
var pos = Matrix.CreateTranslation(position);
var view = mx * my * pos; // These might be in the wrong order, not sure off the top of my head
view.Invert();
The camera is always inverted because moving left moves the world right, turning left turns the world right etc.
I am new to XNA, and I am creating a simple game. Sorry that this is probably really simple, but I can't find any help on it. There is a ship in the game that I made with Blender, and I want to be able to control the ship by being able to rotate the ship's X, Y and Z axises. Here is the code I have:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
RotationMatrix = Matrix.CreateRotationY(MathHelper.PiOver2) * Matrix.CreateRotationY (rotationY) * Matrix.CreateRotationX(rotationX) * Matrix.CreateRotationZ(rotationZ);
Matrix shipTransformMatrix = RotationMatrix * Matrix.CreateTranslation(ship.Position);
DrawModel(ship.Model, shipTransformMatrix, ship.Transforms);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
public void DrawModel(Model model, Matrix modelTransform, Matrix[] absoluteBoneTransforms)
{
//Draw the model, a model can have multiple meshes, so loop
foreach (ModelMesh mesh in model.Meshes)
{
//This is where the mesh orientation is set
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = absoluteBoneTransforms[mesh.ParentBone.Index] * modelTransform;
effect.Projection = projectionMatrix;
effect.View = viewMatrix;
}
//Draw the mesh, will use the effects set above.
mesh.Draw();
}
}
This will rotate the ship, but not along the ship's axis's. If I rotate the Y axis (by changing the value of rotationY), the ship will rotate along its Y axis. But if I rotate the X or Z axis, the ship rotates according according to the world's X and Z axises, not its own. How do I make it so the ship rotates on its own axises? Do I need to do something different with the matrices?
Thanks
Using CreateRotationX, CreateRotationY, & CreateRotationZ all apply rotations around the world or global axes. Meaning it causes your object to rotate only around the world/global axes, not your object's local axes.
Using CreateFromAxisAngle allows you to input whatever rotation axis you want, including the ship's own local axes.
A shift in your overall rotation paradigm will be needed, however, since a rotation around an arbitrary axis like the ship's Up, for instance, can cause a change to any of the 3 angle values at once. Keeping track of all that is unnecessarily difficult. There is an easier way:
Simply store a rotation in matrix (or quaternion) form instead of the 3 angles.
EDIT: Giving some credit here to Steve below (great answer mate, been a while since I did alot of 3D math).
This tutorial here will show you how to setup what Steve suggested!
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series1/Rotation_-_translation.php
Original Post:
I believe you have to create an effect.Rotation in your BasicEffect loop.
All of this is covered in the basic tutorials over at MSDN I believe. Your code even looks like it came from there.
http://msdn.microsoft.com/en-us/library/bb203897(v=xnagamestudio.31)
If not, check out this link, Reimer covers everything in 3D worth knowing to start:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/series1.php
Here is what I ended up doing just in case anyone else gets stuck like I did:
Matrix RotationMatrix;
//every time I wanted to rotate around an axis, I would do something like this:
protected void rotateY()
{
RotationMatrix *= Matrix.CreateFromAxisAngle(RotationMatrix.Up, MathHelper.ToRadians(1.0f));
//For the X axis I used RotationMatrix.Right, and for the Z RotationMatrix.Forward
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
Matrix shipTransformMatrix = RotationMatrix * Matrix.CreateTranslation(ship.Position);
DrawModel(ship.Model, shipTransformMatrix, ship.Transforms);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
public void DrawModel(Model model, Matrix modelTransform, Matrix[] absoluteBoneTransforms)
{
//Draw the model, a model can have multiple meshes, so loop
foreach (ModelMesh mesh in model.Meshes)
{
//This is where the mesh orientation is set
foreach (BasicEffect effect in mesh.Effects)
{
effect.World = absoluteBoneTransforms[mesh.ParentBone.Index] * modelTransform;
effect.Projection = projectionMatrix;
effect.View = viewMatrix;
}
//Draw the mesh, will use the effects set above.
mesh.Draw();
}
}