Cylinder collision

Started by
8 comments, last by Sagito 17 years, 11 months ago
Hi everyone... I'm trying to do a simulation of a ball falling through a pipe. The pipe has constant radius (which is 10), but may have an "S" shape. But, I can't find a way of doing the collision detection of the ball falling. As I'm using DirectX 9.0c, the cylinder is a mesh loaded from a .x file. So, I tried to lock it's vertex buffer and try to find the cylinder's center, but I can't get it right. What I'm doing is:

Vertex* v = 0;
D3DXVECTOR3 Diameter, Center;

for (int i = 1; i < 1600; i++)
{
   for (int a = 0; a < 1599; a++)
   {
      Diameter.x = v[a].x - v.x;
      Diameter.y = v[a].y - v.y;
      Diameter.z = v[a].z - v.z;
   }
   
   double nD = sqrt(pow(Diameter.x, 2) + pow(Diameter.y, 2) + pow(Diameter.z, 2));

   if (nD == 10.0) //10.0 is the pipe radius
      Center = Diameter / 2.0;
}

So, I think Center could be a vector to the last center it finds, but turns out it doesn't. (Can't figure out why). Is there any other way of finding the center so I can check if there was a collision? Thanks...
http://sagito.wordpress.com
Advertisement
Hm, I couldn't quite figure out your example there. You're setting 'v' to 0, but then indexing it, which shouldn't work (maybe you left out the code where 'v' is allocated and filled in).

I kind of see what you're doing - checking the length of the vector between every unique pair of verts against the radius. But shouldn't that be 20 (the diameter)? That is, if you're looking for vectors that span the cylinder. In any case, testing for equality isn't going to do you any good; the distance computation will rarely if ever return that exact value. A <= test would probably suffer from similar problems.

Anyway, a couple other ways you could go would be a) doing per-triangle coldet with the cylinder mesh, using spatial subdivisions to accelerate the test, or b) representing the cylinder mathematically in some way and performing the sphere-cylinder (actually, a generalized cylinder) test in that context.
Sorry, you are completely right... I was wrong when I said the radius is 10. The diameter is 10, and the radius is 5. Also, I forgot to post the initialization for v, which is:

Pipe->LockVertexBuffer(0, (void**)&v);

Hmm, you suggested to try to represent the cylinder mathematically, but that would be harder, I think, because the pipe won't be regular. I mean, it is supposed to have various shapes, turns, rects, loops, etc... Finding a mathematical expression would be painful... =S

Well, I made a file with every vertex value, and the result is very strange... I'll post part of it here as code (to be easier to read):

 5.87785, -8.09017, -200 -0.587785, 0.809017, 0 0, 0.8, 0.554366 0.809017, -4.63294e-007, 0.587785 -3.82877e-007, -1, -3.35584e-007 3.09017, -9.51056, -200 -0.309017, 0.951056, 0 0, 0.75, 0.554366 0.951057, 1.51688e-008, 0.309017 -1.17676e-008, -1, -5.61486e-008 5.87785, -8.09017, 200 -0.587785, 0.809017, 0 0, 0.8, 0.809014 0.809017, 2.15265e-008, 0.587785 9.35104e-009, -1, -5.06137e-008 3.09017, -9.51057, 200 -0.309017, 0.951056, 0 0, 0.75, 0.809014 0.951057, -2.17496e-008, 0.309017 -4.68791e-008, -1, -6.7557e-008 0, -10, -200 0, 0.5, 0.554366 0.309017, 7.48703e-008, -0.951057 -3.3241e-008, -1, -4.35631e-008 -8.09017, -5.87785, 200... 3.08286e-044, 0, 1.83686e-040 -1.#QNAN, 7.42218e+009, 2.84811e-039 3.08286e-044, 4.2039e-045, 9.86076e-032 2.8026e-045, 0, 0 1.43493e-042, 1.43493e-042, 0 0, 0, 0 0, 0, 0 0, 0, 0 0, 0, 0 0, 0, 0 0, 0, 0 0, 0, 0 0, 0, 9.80909e-045 7.83663e-039, 1.77495e-029, 0 0, 0, -1.21979e-012 -1.21979e-012, 0, 0 3.48977e-039, 2.57414e-039, 0 1.12104e-044, 2.84829e-039, 2.84838e-039 2.84851e-039, 2.8486e-039, 2.84874e-039 2.84883e-039, 2.84896e-039, 2.84905e-039 2.84919e-039, 2.84928e-039, 2.84941e-039 0, 0, 0 0, 0, 0 -1.21979e-012, -1.21979e-012, -1.5884e+038 0, 0, 1.19388e-039 2.57416e-039, 0, 0 0, 0, 0 0, 0, 4.48416e-044


Some values are repeated over and over again, and I get this reading: -1.#QNAN, 7.42218e+009, 2.84811e-039. I believe these strange values are the reason why I can't find the center... =\ What do you think?

Thanks again for the help...
http://sagito.wordpress.com
Well, the obvious answer to me is to test the current 'section' of pipe mathematically. Assuming the pipe is a series of connected segments, each of which is a simple shape to do a sphere-shape calculation with, that should be faster than a mesh test.

A cylindrical section is defined by two parameters: a line segment (itself two points) and a radius. The collision test is simply
testVec = [(ballCentre - segmentStart)×(segmentEnd - segmentStart)] / |segmentEnd - segmentStart|²;// collision occurs if |testVec| > radius// yes that's a cross product in there


Edit: The collision will always 'bounce' a ball towards the centre of the cylinder. This direction is given by -testVec×(segmentEnd - segmentStart). The magnitude of the impulse of course will depend on the ball's velocity if you're doing the physics properly.

Edit again: tags

[Edited by - Bob Janova on May 7, 2006 1:55:22 PM]

Hmm...

"A cylindrical section is defined by two parameters: a line segment (itself two points) and a radius."

This line segment you mentioned is a diameter of the cylinder or a segment starting in the ball, and going to the cylinder center, right? If it is, the problem I have is that I can't trust the vertexes values, in the vertex buffer, because they turn out to be wrong for some reason. So, I can't find the center of the section to create that segment... =S

I really loved your suggestion, and would like to use it, but I can't do it without the center, can I?

Thx...
http://sagito.wordpress.com
@The OP: I don't think your current algorithm is going to work (re-read the part of my post about floating-point comparisons). The two most viable options would seem to be arbitrary per-tri coldet, or find another representation for the cylinder (more of a tube, actually).

If you have to work with the mesh you've been given, you're right that it may be a bit difficult to formulate a mathematical representation such as a curve or spline. But if you know how the vertices in the mesh are arranged, you could do something like this:

1. Take each 'ring' of verts
2. Find the average (center)
3. Represent the tube as these points and the line segments that connect them

At which point this starts to look a bit like Bob's solution, above.

Making a ball fall down an irregular tube really isn't that easy of a problem to solve. If it were my project, I'd at least try finding the medial segments of the tube, and then constraining the ball to stay within a certain distance of this series of segments. I couldn't really say whether this would give the desired behavior without trying it, but it might work. Beyond that, I think you're looking at a more general physics-based approach (perhaps using a third-party physics engine).
Quote:Original post by Sagito
This line segment you mentioned is a diameter of the cylinder or a segment starting in the ball, and going to the cylinder center, right? If it is, the problem I have is that I can't trust the vertexes values, in the vertex buffer, because they turn out to be wrong for some reason. So, I can't find the center of the section to create that segment... =S
I think the line segment Bob had in mind was a medial line segment, running through the center of the tube.
Quote:I really loved your suggestion, and would like to use it, but I can't do it without the center, can I?
If the vertex values are chaotic or irregular, I'm not sure off the top of my head how you'd convert it into the suggested representation.

Probably, the vertex problem comes from the Maya .x Exporter, but that's just an hypothesis.

I'll try to implement your idea, I think it's very fast and easy to implement (as soon as I have the vertexes locked correctly).

Thanks a lot, again... =D
http://sagito.wordpress.com
Quote:I think the line segment Bob had in mind was a medial line segment, running through the center of the tube

That is correct. It goes from the middle of the (virtual) circular end of the cylinder, down its (presumably long) axis to the middle of the other end.

My post was made in the assumption that you are in control of your map format, i.e. you can specify your pipe to be made up of various segments in various orientations. You wouldn't try to post-process a mesh into primitives, instead you'd construct a mesh for rendering purposes from the primitives.

It also occurs to me that the method above doesn't account for the size of the ball. Instead of testing for |testVec|>radius, test for |testVec|>(radius+ball_radius).

Ok, I solved the problem I had finding the center! =D Vertex values are a lot better now. Somehow, the exporter mixed things up... =S So, now I will try to build the segment you sugested and try to use that formula... ;)

Thanks a lot for all the help! =D
http://sagito.wordpress.com

This topic is closed to new replies.

Advertisement