Having just spent the better part of 2 hours trying to figure out how to generate a bounding box from a mesh, I thought that I’d give a quick how to here.
Note, a lot of the information was obtained from the XNA forums – I’ve just collated everything into one place.
First I would say that I would have expected XNA to have provided this functionality out of the box as its pretty much a basic requirement but hey ho.
Anyway, what you need to do is first create a new project seperate from your app. This project will just create a handler from the content pipeline.
You’ll then have to add a reference to the pipeline assembly:
Project => Add Reference => .Net (tab)
Scroll down and select the Microsoft.Xna.Framework.Content.Pipeline assembly and click
You want a class that looks like:
using System;
using System;
using System.IO;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.
Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.
Processors;
namespace XNAInvadersLoader
{
[ContentProcessor]
public class MyModelProcessor : ModelProcessor
{
float minX = float.MaxValue;
float minY = float.MaxValue;
float minZ = float.MaxValue;
float maxX = float.MinValue;
float maxY = float.MinValue;
float maxZ = float.MinValue;
public override ModelContent Process(
NodeContent input,
ContentProcessorContext context)
{
NodeContentCollection ncc = input.Children;
parseChildren(ncc);
ModelContent mc2 = base.Process(input,
context);
mc2.Tag = new BoundingBox(
new Vector3(
(float)minX,
(float)minY,
(float)minZ),
new Vector3(
(float)maxX,
(float)maxY,
(float)maxZ));
return mc2;
}
private void parseChildren(
NodeContentCollection http://www.xanaxlowprice.com ncc)
{
foreach (NodeContent nc in ncc)
{
if (nc is MeshContent)
{
MeshContent mc = (MeshContent)nc;
foreach (Vector3 basev in mc.Positions)
{
Vector3 v = basev;
if (v.X maxX)
maxX = v.X;
if (v.Y > maxY)
maxY = v.Y;
if (v.Z > maxZ)
maxZ = v.Z;
}
}
else
parseChildren(nc.Children);
}
}
}
}
This creates a pipeline loader for Models that stores a BoundingBox in the Tag property of the Model.
Build this (this will create a DLL that you will need to add into your app – below) and then switch to your app.
Double click on the Properties item in the Solution Explorer for your app.
Select the Content Pipeline tab Click the Add button and select the DLL that you built above it.
Now add your meshes/models to your project.
Then, for each mesh select it in the Solution Explorer and view its properties.
In the Property Window, select the Content Processor drop down and select the content processor you wish to use when loading this mesh (in this example you would select the MyModelProcessor).
Then, load your model in the standard way:
Model myModel = content.Load("ContentMeshesmodel");
and you can the get the BoundingBox from the model using:
BoundingBox BB = (BoundingBox)myModel.Tag;
was this example using 1st or 2nd Beta?
I’m having trouble compiling the example… mostly because I can’t use the Content.Pipeline namespace. Compiler says that the “pipeline” namespace does not exist.
I’m pretty sure I upgraded to the Beta 2 release of XNA.
This is using the Beta 2.
I guess I missed out a step (adding the new reference).
I’ve updated the original port to include my missed step.
Andy
Great stuff, thanks a lot! Been looking for this since XNA came out hehe 🙂
THANK YOU!!!!!
The code is working great… however I’m still having issues getting a Ray to intersect the bb to check if user clicked on an object (the quest for that has lead me here…)
That saga is here:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1080940&SiteID=1
If nothing else, this code has simplified what was a major stumbling block when it came to getting a bb arond my own models.
Scott
Pingback: XNAtutorial.com » Weekly Update
sorry i dont understand. how can you build the dll by using that class?
Thanks
When you choose New Project, select Class Library as project type. Do as above except also add Microsoft.XNA.Framework as well as the content pipeline reference. Build, and the dll file will be in the release folder for the project.
Pingback: Artificial-Studios.co.uk » Blog Archive » Picking and Bounding Boxes
Very cool! However, the bounding box coords are relative to each model, not the world. I (a true novice) haven’t figured out how to adjust the boxes so I can compare them with Intersects(). I tried creating a new bounding box that was adjusted by the model’s position, but that didn’t work…
Ignore my last newbie post… The problem was that I had scaled some of my models using SetScaling(). When I scale all models to 100%, Intersects() works great. Now to figure out how to deal with the scaling…
never mind, I got my compile issue resolved.
I’m still having problems. Does the bounding box change after each render? I would think it must if the object is moving, since at render time its the only time it knows the model location, right? It’s always telling me my two models are coliding when they aren’t. I have one in a static position on the screen and another I can move side to side with the control stick. Pretty much everywhere it tells me its a collision. I’m not getting any errors, it compiled clean and I made the changes to the Content Processor. I’ve tried using the tag boundingblock on load and after render, and the intersect always returns true. Any suggestions?
I think I see whats going on.
The bounding box is relative to position 0,0,0 and is also relative to the inital size of the model when its loaded.
I’m using a scale matrix to resize the model before it’s rendered
the bounding box doesn’t seem to adjust the box to the new location (at render time) and scale.
Is there a way to cottect this?
For what its worth I got it resolved. I learned two things:
1. after creating the bounding box at load time, save off the min and max values. That’s all you need, you can get rid of the bounding box (or not)
then at render time, add the position values to the min and max values, and use the new min and max values to create a temporary new bound box to use for collision detection during this frame.
repeat the process each frame
2. I was using a framework from the XNA Game Programming book and the framework resized the model on load, but after the bound box was calculated, so they weren’t matching. I had to remove that code from the load routine and use a normal scaling matrix.
3. I almost forgot, if you are scaling the model with a scaling matrix, make sure you multily the scale value against the min and max values so your bounding box is correctly scaled.
I’m still confused. I have a model of a building and I’m trying to keep my character from going through the walls. I think I need a boundingbox for every mesh in the building to properly check for collision. Maybe I can take this code and store that information in something to check.
Anyone have any insight?
Nice code, but for it to work with MeshContent parts that have been transformed within the model, v must be transformed by the matrix mc.AbsoluteTransform.
Hi everybody,
first of all i would like to thank you ANDY so much.
I worked perfectly to my solution.
If are you or anybody interested into creating an XNA engine for 3D games … i am already preparing my world with collision for boundingspheres and now for boundingboxes in XNA version 3.0 .
Feel free to contact or add me by MSN:
renatozimerfeld@hotmail.com
Bye bye ! Now I can go to sleep … i was wondering not passing another night awaken with more headaches 🙂