XNA Collision Detection for 3D models

The tutorial

Update 17 Apr 2009:

Get the latest sample here (v1.3.0.0).

IMPORTANT: The tutorials have not been updated to reflect this XNA v3.0 version and refactoring.

The main changes are these:

  • updated for XNA v3.0
  • refactored to make it easier to include your own models and textures
  • refactored so that the subdividing info is now contained in XML files

Includes the following 24 Feb 2007 updates…

  • When constructing a BoundingPart you now additionally pass the original ModelMesh’s original BoundingSphere. This is used as a general proximity test, so the rest of the BoundingSphere’s don’t need to be transformed and tested on every frame.
  • This behavior is optional. When calling Transform() there is a bool “optimize” parameter. Pass false and the behavior is as it was before.
  • Re factored a little. The List stuff is now encapsulated into a class.
  • When you run the sample, you will notice the BoundingSpheres often don’t move with the model. This is deliberate, and demonstrates the optimizations working. It means they didn’t need to get transformed on each frame because nothing (i.e. the 3D Mouse Cursor) is in the general proximity of their BoundingPart.
  • the XBOX 360 controller now rumbles when the 3D Mouse cursor collides. ;)

Features:

there is a Mouse moveable black Cursor that goes White when colliding. The controls are…

  • Pitch model: XBOX 360 Left Thumbstick Forward/Backwards or Keyboard W/S
  • Roll model: XBOX 360 Left Thumbstick Left/Right or Keyboard A/D
  • Yaw model: XBOX 360 Right Thumbstick Left/Right or Keyboard Q/E
  • Scale model: XBOX 360 Left/Right Trigger or Keyboard LeftShift/LeftCtrl
  • Move 3D cursor: Mouse
  • Move 3D cursor forward/backwards: Mouse Scrollwheel Forwards/Backwards
  • Screenshot and XML Dump (put in \Screenshots sub directory): Keyboard PrintScrn

if you’re after the original (XNA v1) working sample that matches the Tutorial text, get it here

22 Responses to “XNA Collision Detection for 3D models”

  1. XNAtutorial.com » Weekly Update - Competition in February Says:

    [...] Lawrence finished his 3D collision detection tutorials, and it ended up in three parts. Well worth checking out. [...]

  2. sickbattery Says:

    Hi,

    I found your tutorial some weeks(?) ago and wondered if you will finish it. Now I’m sitting at work, drinking some coffee (I’m a bit burned out today) and surfing the web… thought I should check again if someone has found a good way for collision detection with XNA … So, I read and read your tutorial an suddenly oO … at 50% on page 2 … I got the Idea oO …

    I coded a bit wirh C# and Managed DirectX 9 and remember a function to subdivide faces/vertices from meshes oO … to make it short: Why don’t you try to create a second Mesh with 33% of the faces your real model has and take that one for collision detection?

    You don’t need to transform the lowpoly Mesh every time you transform the real one. Transform it when a bullet is inside the BoundingSphere of your whole Model. Now, meshes/models consist of faces and faces have a forefront and a flipside oO … so all you have to do is check the Normals of every face in your lowpoly model for that (when the “bullet” is inside the BoundingSphere oO) … …

    Oh. Sorry, I don’t have the time to read your tutorial to the end right now ^^ … have to work again. Maybe you allready got that Idea ^^ …

    CiaoCiao,
    sickbattery.

  3. Sharky Says:

    Yeah, for sure.

    Some kind of Mesh based collision would be the ultimate.
    I wouldn’t have a clue how to do something that advanced though! I wonder if future versions of XNA will provide a solution for that?

    My tutorial goes no further than describing a multi-Sphere approach. Relatively primitive I know, but still an option, and it was something I was able to get working with my limited knowlege. It can definately be optimized and improved on.

    BTW, I’ve heard some commercial games still use this approach for collision detection. Depending on the game, it might be appropriate. It’s good enough for my game anyway.

    :)

  4. Ultrahead Says:

    “… Why don’t you try to create a second Mesh with 33% of the faces your real model has and take that one for collision detection? …”

    I agree: http://sharky.bluecog.co.nz/?p=120#comment-1250 , but I’d wait to see what’s coming on next releases/updates of XNA; maybe methods to ease collision testing on polygons are provided by the XNA Team for us.

    So, for now, the tree testing implementation on boundingspheres seems to be quite ok to me …

    Cheers!

  5. Tim Says:

    Thanks. This was really great stuff and certainly worth the read. I also appreciate the sample you put together!!

  6. Arek Bal Says:

    Heh… it’s easy to say about using simpler models. Harder to do.
    1st. xna team tried their best to make it hard. There is no easy way to retrive vertex data from Model Object. You can’t just catch that data before model is pushed to gpu(i wonder why?). It’s preety obvious that we wish to have few more parameters in content loading method.
    I spend few days in my research… and I was really sure(it was so obvious to me)… that is possible. There is a way to store vertex data from model at loading time. But if you wish to just load low poly collision model, without loading it to gpu, you would have to reinvent the wheel, and rewrite process method of loader.
    So…
    I ended up with my own .x mesh reader. No content pipeline procedure implemented for know.
    Ok. Sorry for crying up all my tears on you guys. ^^
    Btw. ANybody know how to register from poland to xbox gamertag without lying?

  7. Phil Perm Says:

    Hey,
    I really liked this tutorial, one problem though I’m using XNA 2.0 and I can’t launch or use the tutorial. Are you going to provide a version for XNA 2.0? I’m a geekbie (a newbie geek)…

  8. Phil Perm Says:

    You can discard my last post, i managed to convert it my self. I used the XNA Upgrade wizard and changed some of the code.

  9. Sharky Says:

    ha ha, no problem Phil. I’ll update it one day…

    ;o)

  10. Phil Perm Says:

    When i change the camera view to be more of an isometric view (_cameraView = Matrix.CreateLookAt(new Vector3(0f, 1000f, -250.0f), _position, Vector3.Up);)

    The mouse input gets all distorted, even though I change the z-component for the mouse vector, how come?

  11. David H Says:

    hey thanks for this tutorial the bounding sphere stuff really helped. i created some mouse collision detection with just one sphere, and found it to be insufficient because i could click on air and hit the object. so i looked around for a more accurate method and this seems to be it :D . i do have one question tho, for the model subdivision Vector4 objects how will i know when i have the right scaling factors? i havent looked at the sample code yet so if there is a way to draw the boundingspheres that would be a good way to test the subdivisions, but it just seems like guess and check to me. Any suggestions?

  12. Sharky Says:

    Thanks David H.

    Glad it helped. I really must update it for XNA 3.0.

    Yes, it is very much tweak -> test -> repeat till happy.

    The sample app will render the model for you with the sphere’s visible. I tend to change the sphere color of the model part I’m tweaking to something distinctive – so that I can see what I’m doing better.

    I have an updated app in the works, but it’s just not ready to share yet. It’s a lot tidier for a start, with the layout of the spheres in an XML file instead of C# arrays. Also XNA 3.0.

    I reckon I could even make the tool so they can be tweaked on the fly – visually, and xml saved when you’re happy.

    Stay tuned. No promises on when though, sorry.

  13. Stan Says:

    I have problem getting the code loaded on Visual Studio C# 2005 express edition.
    I installed XNA 1.0, XNA 2.0, XNA 3.0 and still when i loaded, i got this error that says the project installation is not supported.

    Any idea please?

  14. Sharky Says:

    Hi Stan.

    I’m not sure the exact problem, but you’ve prompted me to finally update the sample to work with XNA v3.0. Something I’ve had mostly done, but unreleased for a while.

    The code in this version will be quite out of synch with the tutorial, but the principal is the same.

    Take another look at this page, as I have appended an update and link to the new source.

  15. WiseOne Says:

    Hey Sharky…i had set up a simple game using the ship model provided in the XNA Tutorial here http://msdn.microsoft.com/en-us/library/bb203897.aspx, and was having trouble

    i tried copying my files into the proper place, and because im inexperienced with XMLs, i just copied yours and renamed it.

    When i ran the program, i saw my ship, but no bounding spheres anywhere!

    i tried commenting out the mesh.draw line in the model drawing code to see if my ship was covering up the boundingspheres, but they simply werent there. im not sure what i did wrong…

    can anyone help me out? im looking to keep this ship model because it looks cool and i dont want to rework my game.

  16. Sharky Says:

    Hi WiseOne. I’m not sure how this reply will format in the blog but here goes…

    So my viewer code makes a few assumptions:

    I’ll get onto the spheres later, but…

    Assumption 1:
    It loads a Texture file independent of any Texture files referenced inside the FBX model. Meaning, I load my texture in code, rather than rely on XNA loading it based on the content of the FBX model. (these would be loaded automatically by XNA as part of the Model load).
    However, I like to keep my choice of texture separate from the model for flexibility in my games. i.e. I might want player selectable skins for a given model.

    Now I see the RelativeFilename in the FBX file just happens to be correct for where you’ll have placed the wedge_p1_diff_v1.tga file in the viewer source. (Otherwise you’d get an error compiling)

    Assumption 2:
    My viewer code assumes the texture file loaded will always match the model name, so besides changing that behaviour in the code you’d want to rename the wedge_p1_diff_v1.tga file to p1_wedge.tga.

    Here’s are the steps I did to get it working in my viewer code.

    - create a p1_wedge.xml file into the MeshInfo folder (copying one of the others).
    - add the p1_wedge.fbx file to the Content\Meshes
    - add the wedge_p1_diff_v1.tga texture into the Content\Textures
    - BUT, then rename it to p1_wedge.tga (to match the model name).

    Renaming it however will make the Model not compile because of the texture references inside the FBX file, so I comment those out as follows:

    - Fortunately the Microsoft’s FBX model has been exported in ASCII format so you can open the FBX file and search for any “Filename:” & “RelativeFilename:” bits. (There might be several)

    - comment them out by putting a “;” at the beginning of the lines.

    e.g.
    ;Filename: “C:/Documents and Settings/a-mdudl/My Documents/maya/projects/default//textures/spacewars/tga/renamed/wedge_p1_diff_v1.tga”
    ;RelativeFilename: “..\textures\wedge_p1_diff_v1.tga”

    Now the model should render, with the texture.

    Now to fix the BoundingSpheres edit the p1_wedge.xml file as follows.

    - there needs to be a “MeshPart” element in the Xml file for each mesh you find in the FBX model and the id is used to find the right one, so these need to be named correctly.

    To get the correct names of these MeshPart’s search the FBX file for “Model::”

    e.g. finds lines something like this…

    Model: “Model::p1_wedge_geo1″, “Mesh” {

    so you’d give your MeshPart id=”p1_wedge_geo1″

    In that FBX file I can only see one “Model::” that seems to be some kind of Mesh. The others seem to be some kind of “Camera” type. (I’m not familiar with the FBX format at all. Just a guess)

    Here’s my quick hack at an arrangement of spheres…
    The blog wouldn’t let me post the p1_wedge.xml here as a comment, so download it instead from here

    Like I said, I don’t really know the FBX format at all, but it’s interesting that for Microsoft’s model seems to have 3 MeshParts if you break point in the DrawModel() method. Each with the same Name. Not sure why. Perhaps something to do with different Materials defined also in the FBX file?

    Hope that works for you.
    All that stuff about the textures is really for my viewer logic. In your game you can do whatever you want, but the BoundingSpheres is what you’re really after right?

  17. WiseOne Says:

    Thanks a lot for the help…i understood most of what you said, and i did place the files thae way you had stated…however, i cant find any .FBX files..they are all .XNB(both models and textures)…i will try to copy your fbx and see what happens.

    for now i am going to use your .xml and run with it to see how it goes.

  18. WiseOne Says:

    ok well i never really figured out how to get it to work (although i did eventually get at least the spheres visible!) so i am just using your .xml for now..

    thanks for your help though, even your quick version is a lot more effective than the singular sphere i was using before

  19. Sharky Says:

    Hi WiseOne.

    I think you might be getting confused between your compiled output files and the actual source files.

    If you’re seeing .XNB files you must be looking at the compiled output, not the source Content.

    When you compile Game Studio takes your source Content like your models (.FBX, .x, etc….), and textures (.jpg, .bmp, .tga, .dds, etc….) and puts them in a propriatory .XNB format along with your compiled application.

    (I’m pretty sure you can’t take an .XNB file and put it in another games source.)

    You must have already copied the p1_wedge.FBX model from the Microsoft sample into the viewer source Content\Meshes. This is the one you’d edit as I described above. NOT, the compiled XNB file under \bin\x86\Debug\Content\Meshes.

  20. M3hdi Says:

    Hi guys !!
    this might be a dumb question (i’m an XNA novice and i’m trying to set up my first xna game as a project for my c++ class ) any way, i’m having some issues concerning the building of the project you provided here :http://sharky.bluecog.co.nz/uploads/code/Sharky.3DCollisionDetection.Tutorial_v1.3.0.0.zip
    whenever i try to run the project i get an exception in the MeshInfo.Load() method when it reaches this particular line:

    float x0 = float.Parse(subdivisionNode.Attributes["x"].Value);

    it says that “the input string format is incorrect” (i tried my best to translate the error text cause i’m from france and the interface language of my IDE is set to french :p )

    i’ve tried to modify the xml file, changed its location and its path, and several other code modification but without success.
    so please sharky, can you help me fix this problem ?

    Ps : sorry for my lame english, my command of it still not perfect yet :)

  21. Sharky Says:

    Hey M3hdi.

    Your english is great – I really wouldnt have known.

    I think I know what the problem might be. The clue was that you said your IDE is set to french. I remember Air Legends failing Peer Review once because when played on Xboxes in the France & Italy regions it did weird things. Giant Models to be specific.
    It turned out to be a problem with similar Parse/Convert code. If I remember correctly France & Italy use a comma character (”,”) to delimit the fractional part of a number. In most english language locales we use a period, or decimal point character (”.”).

    The solution was to add an extra parameter to all the Parse & Convert statements that dealt with numbers.

    for instance, I changed….

    float x0 = float.Parse(subdivisionNode.Attributes["x"].Value);

    to…

    float x0 = float.Parse(subdivisionNode.Attributes["x"].Value, CultureInfo.InvariantCulture.NumberFormat);

    (CultureInfo can be found in System.Globalization)

    I hope this solves it for you. Let me know how you go.

    Cheers,

    Sharky

  22. M3hdi Says:

    hey Sharky, that was it , the solution you gave me was just perfect. can’t thank you enough for the solution and the quick response, you have made my day sir.
    thanks again, and keep up the good work !!

    M3hdi