So I have a system with colliding balls that generally works, except for when they collide with similar directions, less than 90 degrees apart.
This is because the ball above tries to collide against the yellow line which is supposedly the collision plane, but it sends it off the wrong direction, and it "follows" the other ball. The general algorithm for the collision is:
dot = direction.surface;
parallel = surface * dot;
perpendicular = direction - parallel;
direction = perpendicular - parallel;
Which negates the component of the direction parallel to the surface normal, which is perpendicular to the collision plane, and the part perpendicular to the surface normal is unchanged.
Does anyone know a fix for this? Have I done something wrong?
Edit: So now I added:
average = (ball1.velocity + ball2.velocity) / 2;
ball1.velocity -= average;
ball2.velocity -= average;
Before doing the calculations above, and after that:
ball1.velocity += average;
ball2.velocity += average;
To get in the right reference frame, according to #Beta's answer. The problem now is that the speeds of the balls aren't maintained, since they both have the same speeds and masses, yet after the collisions they're different. I do not think this is supposed to happen, or is it?
Consider the 1D problem of bouncing a ball off a wall. Simple.
Now watch me bounce a ball off the forward bulkhead of a jet plane in flight. The ball is moving north at 252 m/s, the bulkhead is moving north at 250 m/s. The answer is not obvious. But shift into my coordinate frame (by subtracting the velocity of the bulkhead, 250 m/s, from everything) and the problem is trivial. Solve it, then shift the result back into the ground frame (by adding 250 m/s to everything) and you're done.
Now the 2D problem of a ball bouncing off a wall at an angle. Simple. (But verify that your code does it correctly.)
Now two balls colliding with equal and opposite momenta (I'll assume they have the same mass, for now). You can imagine a yellow wall at the collision plane, and the answer comes easily.
Now two balls colliding, but with velocities that do not add up to zero. There's still a yellow wall, but it's moving. Well, shift into the wall's frame by subtracting the average of the balls' velocities (sum/2) from everything, solve the simpler problem, then shift back by adding that same velocity back to everything, and you're done.
Related
So I am making a simple pool game (no ball to ball collisions only ball to wall) and I'm kind of struggling (especially with an actual ball (diameter>0)). (After I figure out the logic and physics I am going to make it on c++ code)
So basically I have a coordinate system with the 4 edges of the pool table, ball coordinates, direction of hit and power of the hit.
So far I've semi-figured out 2 ways of calculating the end position of the ball when it meets a collision with the wall with a ball with 0 diameter:
A 5 formula algorithm combining vectors and lines to figure out the formula of the result line that the ball will travel on when it has collided with the wall. The problem here is that after I got this line I have no idea how to find the exact end position of the ball on this line(coordinate). (I use a perpendicular to the wall line to calculate the result angle at which its gonna bounce and then using some formulas and sin() cos() of that angle I find a and b for the ax+b = y formula of the line. To be more exact I find the perpendicular line formula with a system of 2 equations, then cos() of angle between 2 vectors, then sin() of that same angle to use it again in the same formulas but reversed in order to find the other coordinate, then using the two points I have I make a line)
I basically find where it's gonna hit the wall and since the power and direction of the hit is given I will just have 8 cases where the ball will hit each of the four walls and check which case I'm in and just reverse whatever x and y I need to. The problem with this is that if the ball has a diameter > 0 (so its an actual ball and not just a point) the ball is going to collide with the wall not at its center but at the side of the ball and I have no idea how to find exactly where the ball will collide with the wall and how that will change the line that it's gonna travel on/angle of the collision and the end position respectfully. (This method is likely to work but it would be really hard to implement, because of 8 cases to check which wall and what direction its going to hit it at also calculate the formulas of the lines of the edges and check where its going to hit exactly and a lot of other stuff) EDIT: This is going to be a little different since I'm changing a few things in the original logic.
Examples(I already made this part on code):
Ball is at (10, 10). A hit is given with direction (20,20) and power 1. Output: End Ball Pos = (20, 20)
Ball is at (10, 10). A hit is given with direction (20,20) and power 2. Output: End Ball Pos = (30, 30)
Example with wall being hit(playing field in this case is (0,0);(320,0);(320,160);(0,160):
Ball(300, 60), hit(250, 30), power 3 diameter 0: Output(150,30) (hits wall(200, 0))
Same case, but diameter 10: Output(150, 40) (hits wall(208.3333333, 5))
I don't need to find where it hits the wall only where the ball is going to end up after a hit(multiple wall collision are possible in one hit).
More info(playing field is always 1:2; isn't always parallel to x and y axis; ball can have any diameter; power ranges from 1 - 10; hitting corner is a different case not included in this question; friction is ignored and I I just need to move the ball to the designated position, doesn't mean that it will travel forever)
TL;DR need to find coordinates of ball after a collision with a wall.
Any help is appreciated! Thanks in advance!
Going from a point-like ball to a ball with a diameter is quite simple.
(I can't prepare images easily, so I must rely on your imagination.)
You have already experimented with a point-like ball bouncing off a wall. For example, if the wall is at x=W, and the "ball" approaches from the x<W side, with positive x-velocity, it will rebound at x=W and take on negative x-velocity.
Now consider a ball with radius r approaching the same wall, again from the x<W side with positive x-velocity. The collision will occur when the center of the ball is at x=W-r. Notice that the center point of the ball will move exactly as if it were a point-like ball striking a wall at x=W-r.
So to get the motion of a ball with radius r, simply move the walls in a distance r, and calculate the motion of a point-like ball. When you have that, draw a ball of radius r centered on that moving point.
This is the first question I've ever asked on here! Apologies in advance if I've done it wrong somehow.
I have written a program which stacks up spheres in three.js.
Each sphere starts with randomly generated (within certain bounds) x and z co-ordinates, and a y co-ordinate high above the ground plane. I casts rays from each of the sphere's vertices to see how far down it can fall before it intersects with an existing mesh.
For each sphere, I test it in 80 different random xz positions, see where it can fall the furthest, and then 'drop' it into that position.
This is intended to create bubble towers like this one:
However, I have noticed that when I make the bubble radius very small and the base dimensions of the tower large, this happens:
If I turn the recursions down from 80, this effect is less apparent. For some reason, three.js seems to think that the spheres can fall further at the corners of the base square. The origin is exactly at the center of the base square - perhaps this is relevant.
When I console log all the fall-distances I'm receiving from the raycaster, they are indeed larger the further away you get from the center of the square... but only at the 11th or 12th decimal place.
This is not so much a problem I am trying to solve (I could just round fall distances to the nearest 10th decimal place before I pick the largest one), but something I am very curious about. Does anyone know why this is happening? Has anybody come across something similar to this before?
EDIT:
I edited my code to shift everything so that the origin is no longer at the center of the base square:
So am I correct in thinking... this phenomenon is something to do with distance from the origin, rather than anything relating to the surface onto which the balls are falling?
Indeed, the pattern you are seeing is exactly because the corners and edges of the bottom of your tower are furthest from the origin where you are dropping the balls. You are creating a right triangle (see image below) in which the vertical "leg" is the line from the origin from which you are dropping the balls down to the point directly below on mesh floor (at a right angle to the floor - thus the name, right triangle). The hypotenuse is always the longest leg of a right triangle, and the futher out your rays cast from the point just below the origin, the longer the hypotenuse will be, and the more your algorithm will favor that longer distance (no matter how fractional).
Increasing the size of the tower base would exaggerate this effect as the hypotenuse measurements can now grow even larger. Reducing the size of the balls would also favor the pattern you are seeing, as now each ball is not taking up as much space, and so the distant measurments to the corners won't fill in as quickly as they would with larger balls so that now more balls will congregate at the edges before filling in the rest of the space.
Moving your dropping origin to one side or another creates longer distances (hypotenuses) to the opposites sides and corners, so that the balls will fill in those distant locations first.
The reason you see less of an effect when you reduce the sample size from 80 to say, 20, is that there are simply fewer chances to detect these more distant locations to which the balls could fall (an odds game).
A right triangle:
A back-of-the-napkin sketch:
Alright, so I'm working on a ray tracer using phong shading. So far, everything is good. I've cast rays that have hit the spheres in my scene, applied phong shading to them, and it looks normal.
Now, I'm calculating shadow rays, which is shooting a ray from the point of intersection from the primary ray to the light source, and seeing if it hits any objects on the way. If it does, then it's in a shadow.
However, when computing whether the shadow ray hits any spheres, there seems to be an error with my discriminant that is calculated, which is odd since it's been correct so far for primary rays.
Here's the setup:
// Origin of ray (x,y,z)
origin: -1.9865333, 1.0925934, -9.8653316
// Direction of ray (x,y,z), already normalized
ray: -0.99069530, -0.13507602, -0.016648887
// Center of sphere (x,y,z)
cCenter: 1.0, 1.0, -10.0
// Radius of the sphere (x,y,z)
cRadius: 1.0
, and here's the code for finding the discriminant:
// A = d DOT d
float a = dotProd(ray, ray);
// B = 2 * (o - c) DOT d
Point temp (2.0*(origin.getX() - cCenter.getX()), 2.0*(origin.getY() - cCenter.getY()), 2.0*(origin.getZ() - cCenter.getZ()));
float b = dotProd(temp, ray);
// C = (o - c) DOT (o - c) - r^2
temp.setAll(origin.getX() - cCenter.getX(), origin.getY() - cCenter.getY(), origin.getZ() - cCenter.getZ());
float c = dotProd(temp, temp);
c -= (cRadius * cRadius);
// Find the discriminant (B^2 - 4AC)
float discrim = (b*b) - 4*a*c;
Clearly, the ray is pointing away from the sphere, yet the discriminant here is positive (2.88) indicating that the ray is hitting the sphere. And this code works fine for primary rays as their discriminants must be correct, yet not for these secondary shadow rays.
Am I missing something here?
So short answer for my problem, in case someone finds this and has the same problem:
The discriminant tells you whether a hit exists for a line (and not for a ray, like I thought). If it's positive, then it has detected a hit somewhere on the line.
So, when calculating the t-value(s) for the ray, check to see if they're negative. If they are, then it's a hit BEHIND the point of origin of the ray (ie. the opposite direction of the ray), so discard it. Only keep the positive values, as they're hits in the direction of the ray.
Even shorter answer: discard negative t-values.
Credit goes to woodchips for making me realize this.
The issue is, the trick to finding the intersection of a line and a sphere requires the solution of a quadratic equation. Such an equation has one of three possibilities as a solution - there are 0, 1, or 2 real solutions to that equation. The sign of the discriminant tells us how many real solutions there are (as well as helping us to solve for those solutions.)
If a unique solution exists, then the line just kisses the surface of the sphere. This happens when the discriminant is exactly zero.
If two solutions exist, then the line passes through the sphere, hitting the surface in TWO distinct points.
If no real solution exists (the case where the discriminant is negative) then the line lies too far away from the sphere to touch it at all.
Having discovered if the line ever goes near the sphere or not, only then do we worry if the ray hits it. For this, we can look at how we define the ray. A ray is a half line, extending to infinity in only one direction. So we look to see where on the line the intersection points happen. Only if the intersection happens on the half of the line that we care about is there a RAY-sphere intersection.
The point is, computation of the discriminant (and simply testing its sign) tells you ONLY about what the line does, not about where an intersection occurs along that line.
Of course, a careful reading of the link you yourself provided would have told you all of this.
Pretty sure "o-c" should be "c-o"
You're shooting a ray off in the wrong direction and finding the intersection on the other side of the sphere.
Hey so after reading this article I've been left with a few questions I hope to resolve here.
My understanding is that the goal of any multi-dimensional collision response is to convert it to a 1D collision be putting the bodies on some kind of shared axis. I've deduced from the article that the steps to responding to a 2d collision between 2 polygons is to
First find the velocity vector of each bodies collision point
Find relative velocity based on each collision point's velocity (see question 1)
Factor in how much of that velocity is along the the "force transfer line (see question 2)"
(which is the only velocity that matters for the collision)
Factor in elasticity
Factor in mass
Find impulse/ new linear velocity based on 2-4
Finally figure out new angular velocity by figuring out how much of the impulse is "rotating around" each object's CM (which is what determines angular acceleration)
All these steps basically figure out how much velocity each point is coming at the other with after each velocity is translated to a new 1D coordinate system, right?
Question 1: The article says relative velocity is meant to find and expression for the velocity with which the colliding points are approaching each other, but to me it seems as though is simply the vector of
CM 1 -> CM 2, with magnitude based on each point's velocity. I don't understand the reasoning behind even including the CMs in the calculations since it is the points colliding, not the CMs. Also, I like visualizing things, so how does relative velocity translate geometrically, and how does it work toward the goal of getting a 1D collision problem.
Question 2: The article states that the only force during the collision is in the direction perpendicular to the impacted edge, but how was this decided? Also how can they're only be force in one direction when each body is supposed to end up bouncing off in 2 different directions.
"All these steps basically figure out how much velocity each point is coming at the other with after each velocity is translated to a new 1D coordinate system, right?"
That seems like a pretty good description of steps 1 and 2.
"Question 1: The article says relative velocity is meant to find and expression for the velocity with which the colliding points are approaching each other, but to me it seems as though is simply the vector of CM 1 -> CM 2, with magnitude based on each point's velocity."
No, imagine both CMs almost stationary, but one rectangle rotating and striking the other. The relative velocity of the colliding points will be almost perpendicular to the displacement vector between CM1 and CM2.
"...How does relative velocity translate geometrically?"
Zoom in on the site of collision, just before impact. If you are standing on the collision point of one body, you see the collision point on the other point approaching you with a certain velocity (in your frame, the one in which you are standing still).
"...And how does it work toward the goal of getting a 1D collision problem?"
At the site of collision, it is a 1D collision problem.
"Question 2: The article states that the only force during the collision is in the direction perpendicular to the impacted edge, but how was this decided?"
It looks like an arbitrary decision to make the surfaces slippery, in order to make the problem easier to solve.
"Also how can [there] only be force in one direction when each body is supposed to end up bouncing off in 2 different directions."
Each body experiences a force in one direction. It departs in a certain direction, rotating with a certain angular velocity. I can't parse the rest of the question.
I'm having trouble wrapping my mind around how to calculate the normal for a moving circle in a 2d space. I've gotten as far as that I'm suppose to calculate the Normal of the Velocity(Directional Speed) of the object, but that's where my college algebra mind over-heats, any I'm working with to 2d Circles that I have the centerpoint, radius, velocity, and position.
Ultimately I'm wanting to use the Vector2.Reflect Method to get a bit more realistic physics out of this exercise.
thanks ahead of time.
EDIT: Added some code trying out suggestion(with no avail), probably misunderstanding the suggestion. Here I'm using a basketball and a baseball, hence base and basket. I also have Position, and Velocity which is being added to position to create the movement.
if ((Vector2.Distance(baseMid, basketMid)) < baseRadius + basketRadius)
{
Vector2 baseNorm = basketMid - baseMid;
baseNorm.Normalize();
Vector2 basketNorm = baseMid - basketMid;
basketNorm.Normalize();
baseVelocity = Vector2.Reflect(baseVelocity, baseNorm);
basketVelocity = Vector2.Reflect(basketVelocity, basketNorm);
}
basePos.Y += baseVelocity.Y;
basePos.X += baseVelocity.X;
basketPos.Y += basketVelocity.Y;
basketPos.X += basketVelocity.X;
basketMid = new Vector2((basketballTex.Width / 2 + basketPos.X), (basketballTex.Height / 2 + basketPos.Y));
baseMid = new Vector2((baseballTex.Width / 2 + basePos.X), (baseballTex.Height / 2 + basePos.Y));
First the reflection. If I'm reading your code right, the second argument to Vector2.Reflect is a normal to a surface. A level floor has a normal of (0,1), and a ball with velocity (4,-3) hits it and flies away with velocity (4,3). Is that right? If that's not right then we'll have to change the body of the if statement. (Note that you can save some cycles by setting basketNorm = -baseNorm.)
Now the physics. As written, when the two balls collide, each bounces off as if it had hit a glass wall tangent to both spheres, and that's not realistic. Imagine playing pool: a fast red ball hits a stationary blue ball dead center. Does the red ball rebound and leave the blue ball where it was? No, the blue ball gets knocked away and the red ball loses most of its speed (all, in the perfect case). How about a cannonball and a golf ball, both moving at the same speed but in opposite directions, colliding head-on. Will they both bounce equally? No, the cannonball will continue, barely noticing the impact, but the golf ball will reverse direction and fly away faster than it came.
To understand these collisions you have to understand momentum (and if you want collisions that aren't perfectly elastic, like when beanbags collide, you also have to understand energy). A basic physics textbook will cover this in an early chapter. If you just want to be able to simulate these things, use the center-of-mass frame:
Vector2 CMVelocity = (basket.Mass*basket.Velocity + base.Mass*base.Velocity)/(basket.Mass + base.Mass);
baseVelocity -= CMVelocity;
baseVelocity = Vector2.Reflect(baseVelocity, baseNorm);
baseVelocity += CMVelocity;
basketVelocity -= CMVelocity;
basketVelocity = Vector2.Reflect(basketVelocity, basketNorm);
basketVelocity += CMVelocity;
The normal of a circle at a given point on its edge is going to be the direction from its center to that point. Assuming that you're working with collisions of circles here, then one easy "shorthand" way to work this out would be that at the time of collision (when the circles are touching), the following will hold true:
Let A be the center of one circle and B the center of the other. The normal for circle A will be normalize(B-A) and the normal for circle B will be normalize(A-B). This is true because the point where they touch will always be colinear with the centers of the two circles.
Caveat: I'm not going to assume that this is completely correct. Physics are not my specialty.
Movement has no effect on a normal. Typically, a normal is just a normalized (length 1) vector indicating a direction, typically the direction that a poly faces on a 3d object.
What I think you want to do is find the collision normal between two circles, yes? If so, one of the cool properties of spheres is that if you find the distance between the centers of them, you can normalize that to get the normal of the sphere.
What seems correct for 2d physics is that you take the velocity * mass (energy) of a sphere, and multiply that by the normalized vector to the other sphere. Add the result to the destination sphere's energy, subtract it from the original sphere's energy, and divide each, individually, by mass to get the resulting velocity. If the other sphere is moving, do the same in reverse. You can probably simplify the math down from there, of course, but it's late and I don't feel like doing it :)
If both spheres are moving, repeat the process for the other sphere (though you could probably simplify that equation to get some more efficient math).
This is just back-of-the-napkin math, but it seems to give the correct results. And, hey, I once derived Euler angles on my own, so sometimes my back-of-the-napkin math actually works out.
This also assumes perfectly elastic collisions.
If I'm incorrect, I'd be happy to find out where :)