Okay I'm working on a Space sim and as most space sims I need to work out where the opponents ship will be (the 3d position) when my bullet reaches it. How do I calculate this from the velocity that bullets travel at and the velocity of the opponents ship?
Calculate the relative velocity vector between him and yourself: this could be considered his movement if you were standing still. Calculate his relative distance vector. Now you know that he is already D away and is moving V each time unit. You have V' to calculate, and you know it's length but not it's direction.
Now you are constructing a triangle with these two constraints, his V and your bullet's V'. In two dimensions it'd look like:
Dx+Vx*t = V'x*t
Dy+Vy*t = V'y*t
V'x^2 + V'y^2 = C^2
Which simplifies to:
(Dx/t+Vx)^2 + (Dy/t+Vx)^2 = C^2
And you can use the quadratic formula to solve that. You can apply this technique in three dimensions similarly. There are other ways to solve this, but this is just simple algebra instead of vector calculus.
Collision Detection by Kurt Miller
http://www.gamespp.com/algorithms/collisionDetection.html
Add the negative velocity of the ship to the bullet, so that only the bullet moves. Then calculate the intersection of the ship's shape and the line along which the bullet travels (*pos --> pos + vel * dt*).
The question probably shouldn't be "where the ship will be when the bullet hits it," but IF the bullet hits it. Assuming linear trajectory and constant velocity, calculate the intersection of the two vectors, one representing the projectile path and another representing that of the ship. You can then determine the time that each object (ship and bullet) reach that point by dividing the distance from the original position to the intersection position by the velocity of each. If the times match, you have a collision and the location at which it occurs.
If you need more precise collision detection, you can use something like a simple BSP tree which will give you not only a fast way to determine collisions, but what surface the collision occurred on and, if handled correctly, the exact 3d location of the collision. However, it can be challenging to maintain such a tree in a dynamic environment.
Related
I've had a bit of a sniff around google for a solution but I believe my terminology is wrong, so bear with me here.
I'm working on a simple game where people can build simplistic spaceships and place thrusters willy nilly over the space ship.
Let's call say my space ship's center of mass is V.
The space ship has an arbitrary number of thrusters at arbitrary positions with arbitrary thrust direction vectors with an arbitrary clamp.
I have an input angular velocity vector (angle/axis notation) and world velocity (vector) which i wish the ship to "go" at.
How would I calculate the the ideal thrust for each of the thrusters for the ship to accelerate to the desired velocities?
My current solution works well for uniformly placed thrusters. Essentially what I do is just dot the desired velocity by the thrusters normal for the linear velocity. While for the angular velocity I just cross the angular velocity by the thrusters position and dot the resulting offset velocity by the thrusters normal. Of course if there's any thrusters that do not have a mirror image on the opposite side of the center of mass it'll result in an undesired force.
Like I said, I think it should be a fairly well documented problem but I might just be looking for the wrong terminology.
I think you can break this down into two parts. The first is deciding what your acceleration should be each frame, based on your current and desired velocities. A simple rule for this
acceleration = k * (desired velocity - current velocity)
where k is a constant that determines how "responsive" the system is. In order words, if you're going too slow, speed up (positive acceleration), and if you're going too fast, slow down (negative acceleration).
The second part is a bit harder to visualize; you have to figure out which combination of thrusters gives you the desired accelerations. Let's call c_i the amount that each thruster thrusts. You want to solve a system of coupled equations
sum( c_i * thrust_i ) = mass * linear acceleration
sum( c_i * thrust_i X position_i) = moment of interia * angular acceleration
where X is the cross produxt. My physics might be a bit off, but I think that's right.
That's an equation of 6 equations (in 3D) and N unknowns where N is the number of thusters, but you've got the additional constraint that c_i > 0 (assuming the thrusters can't push backwards).
That's a tricky problem, but you should be able to set it up as a LCP and get an answer using the Projected Gauss Seidel method. You don't need to get the exact answer, just something close, since you'll be solving it again for slightly different values on the next frame.
I hope that helps...
So I have a ship, that has thrusters at the bottom and that can only use these to move forward. It can also rotate itself around its center. Its thrusters gives it acceleration, so it doesn't move at a constant velocity. What I want to do is to tell it "move to point B".
I have come up with a solution but it doesn't work very well and it doesn't rotate smoothly, it moves jerkily and it doesn't end up exactly where it should be, so I have to have a big margin of error.
Is this a normal problem, and if so is there a "standard" way of doing it? Is this an easy problem? I want to make it look like the ship is steering itself to that point, using the constraints (thrusters, rotation) the player has. This excludes just lerping it from point A to B. Or does it?
I'd love some help in solving this problem. Positions are stored in vectors, and it's a 2D problem. Just for reference I'm including my solution, which basically is accelerating the ship until and rotating it to point to the point. I think my implementation of this idea is the problem:
Vector diff = vector_sub(to_point, pos);
float angle = vector_getangle(diff);
float current_angle = vector_getangle(dir);
float angle_diff = rightrange(angle) - rightrange(current_angle);
float len = vector_getlength(diff);
// "Margin of error"
float margin = 15.0;
// Adjust direction, only if we're not stopping the next thing we do (len <= margin)
if ( len > margin && fabs(angle_diff) > 2.0 )
{
dir = vector_setangle(dir, current_angle + (angle_diff)*delta*(MY_PI) - MY_PI/2);
}
else if ( len > margin )
{
dir = vector_normalize(diff);
}
// accelerate ship (if needed)
acc.x = acc.y = speed;
acc = vector_setangle(acc, vector_getangle(dir));
if ( len <= margin )
{
// Player is within margin of error
}
If you are not looking for a very general solution that works online, then there is a simple solution. What I mean by online is continuously re-calculating the actions along the complete trajectory.
Assuming the ship is at rest at start, simply rotate it towards your target point (while still at rest). Now, your ship can reach the target by accelerating for t seconds, rotating back while in motion (for 0.5 seconds as per your constraint), and decelerating for another t seconds. If the distance between current point and destination is d, then the equation you need to solve is:
d = 0.5*a*t^2 + 0.5*a*t + 0.5*a*t^2
The first term is distance traveled while accelerating. The second term is distance traveled while rotating (v*t_rot, v=a*t, t_rot=0.5). The final term is the distance traveled while decelerating. Solve the above for t, and you have your trajectory.
If the ship is moving at start, I would first stop it (just rotate in opposite direction of its speed vector, and decelerate until at rest). Now we know how to reach destination.
The problem with offline trajectory calculation is that it is not very accurate. There is a good chance that you will end up in the vicinity of the target, but not exactly on top of it.
Let's make the problem a little more interesting: the ship cannot rotate without acceleration. Let's call this acceleration vector a_r, a vector that is at a certain angle against the ship's direction (somewhat like having a thruster at an angle at the back). Your task now is to rotate the ship and accelerate in such a direction that the speed component perpendicular to the vector connecting the current position to the target is canceled out. Instead of trying to calculate the vectors offline, I would go with an online approach with this.
The easiest thing to do would be to add the following algorithm calculated at every time interval:
Calculate the vector pointing from ship to destination.
Split your current speed vector into two components: towards the destination, and perpendicular to it.
If perpendicular speed is zero, skip 4
Start rotating towards the negative of the perpendicular vector's direction. If already looking away from it (not exact opposite, but just looking away), also fire main thruster.
This will oscillate a bit, I suspect it will also stabilize after a while. I must admit, I don't know how I would make it stop at destination.
And the final approach is to model the ship's dynamics, and try to linearize it. It will be a non-linear system, so the second step will be necessary. Then convert the model to a discrete time system. And finally apply a control rule to make it reach target point. For this, you can change your state-space from position and speed to error in position and (maybe) error in speed, and finally add a regulation control (a control loop that takes the current state, and generates an input such that the state variables will approach zero).
This last one is fairly difficult in the maths compartment, and you'd probably need to study control engineering a bit to do it. However, you'll get much better results than the above simplistic algorithm - which admittedly might not even work. In addition, you can now apply various optimization rules to it: minimize time to reach target, minimize fuel consumption, minimize distance traveled, etc.
I'm using a Segment to Segment closest approach method which will output the closest distance between two segments of length. Each segment corresponds to a sphere object's origin and destination. The speed is simply from one point, to the other.
Closest Approach can succeed even when there won't be a real collision. So, I'm currently using a 10-step method and calculating the distance between 2 spheres as they move along the two segments. So, basically the length of each segment is the object's traverse in the physics step, and the radius is the objects radius. By stepping, I can tell where they collide, and if they collide (Sort of; for the MOST part.)..
I get the feeling that there could be something better. While I sort of believe that the first closest approach call is required, I think that the method immediately following it is a TAD weak. Can anyone help me out? I can illustrate this if needed.
Thanks alot!
(source: yfrog.com)
(I don't know how to post graphics; bear with me.)
All right, we have two spheres with radii r1 and r2, starting at locations X1 and X2, moving with velocities V1 and V2 (X's and V's are vectors).
The velocity of sphere 1 as seen from sphere 2 is
V = V1-V2
and its direction is
v = V/|V|
The distance sphere 1 must travel (in the frame of sphere 2) to closest approach is
s = Xv
And if X is the initial separation, then the distance of closest approach is
h = |X - Xv|
This is where graphics would help. If h > r1+r2, there will be no collision. Suppose h < r1+r2. At the time of collision, the two sphere centers and the point of closest approach will form a right triangle. The distance from Sphere 1's center to the point of closest approach is
u = sqrt((r1 + r2)^2 - h^2)
So the distance sphere 1 has traveled is
s - u
Now just see if sphere 1 travels that far in the given interval. If so, then you know exactly when and where the spheres were (you must shift back from sphere 2's frame, but that's pretty easy). If not, there's no collision.
Closest approach can be done without simulating time if the position function is invertible and explicit.
Pick a path and object.
Find the point on the path where the two paths are closest. If time has bounds (e.g. paths are line segments), ignore the bounds in this step.
Find the time at which the object is at the point from the previous step.
If time has bounds, limit the picked time by the bounds.
Calculate the position of the other object at the time from the previous step.
Check if the objects overlap.
This won't work for all paths (e.g. some cubic), but should work for linear paths.
I am trying to animate an object, let's say its a car. I want it go from point
x1,y1,z1
to point x2,y2,z2 . It moves to those points, but it appears to be drifting rather than pointing in the direction of motion. So my question is: how can I solve this issue in my updateframe() event? Could you point me in the direction of some good resources?
Thanks.
First off how do you represent the road?
I recently done exactly this thing and I used Catmull-Rom splines for the road. To orient an object and make it follow the spline path you need to interpolate the current x,y,z position from a t that walks along the spline, then orient it along the Frenet Coordinates System or Frenet Frame for that particular position.
Basically for each point you need 3 vectors: the Tangent, the Normal, and the Binormal. The Tangent will be the actual direction you will like your object (car) to point at.
I choose Catmull-Rom because they are easy to deduct the tangents at any point - just make the (vector) difference between 2 other near points to the current one. (Say you are at t, pick t-epsilon and t+epsilon - with epsilon being a small enough constant).
For the other 2 vectors, you can use this iterative method - that is you start with a known set of vectors on one end, and you work a new set based on the previous one each updateframe() ).
You need to work out the initial orientation of the car, and the final orientation of the car at its destination, then interpolate between them to determine the orientation in between for the current timestep.
This article describes the mathematics behind doing the interpolation, as well as some other things to do with rotating objects that may be of use to you. gamasutra.com in general is an excellent resource for this sort of thing.
I think interpolating is giving the drift you are seeing.
You need to model the way steering works .. your update function should 1) move the car always in the direction of where it is pointing and 2) turn the car toward the current target .. one should not affect the other so that the turning will happen and complete more rapidly than the arriving.
In general terms, the direction the car is pointing is along its velocity vector, which is the first derivative of its position vector.
For example, if the car is going in a circle (of radius r) around the origin every n seconds then the x component of the car's position is given by:
x = r.sin(2πt/n)
and the x component of its velocity vector will be:
vx = dx/dt = r.(2π/n)cos(2πt/n)
Do this for all of the x, y and z components, normalize the resulting vector and you have your direction.
Always pointing the car toward the destination point is simple and cheap, but it won't work if the car is following a curved path. In which case you need to point the car along the tangent line at its current location (see other answers, above).
going from one position to another gives an object a velocity, a velocity is a vector, and normalising that vector will give you the direction vector of the motion that you can plug into a "look at" matrix, do the cross of the up with this vector to get the side and hey presto you have a full matrix for the direction control of the object in motion.
How do I correct for floating point error in the following physical simulation:
Original point (x, y, z),
Desired point (x', y', z') after forces are applied.
Two triangles (A, B, C) and (B, C, D), who share edge BC
I am using this method for collision detection:
For each Triangle
If the original point is in front of the current triangle, and the desired point is behind the desired triangle:
Calculate the intersection point of the ray (original-desired) and the plane (triangle's normal).
If the intersection point is inside the triangle edges (!)
Respond to the collision.
End If
End If
Next Triangle
The problem I am having is that sometimes the point falls into the grey area of floating point math where it is so close to the line BC that it fails to collide with either triangle, even though technically it should always collide with one or the other since they share an edge. When this happens the point passes right between the two edge sharing triangles. I have marked one line of the code with (!) because I believe that's where I should be making a change.
One idea that works in very limited situations is to skip the edge testing. Effectively turning the triangles into planes. This only works when my meshes are convex hulls, but I plan to create convex shapes.
I am specifically using the dot product and triangle normals for all of my front-back testing.
This is an inevitable problem when shooting a single ray against some geometry with edges and vertices. It's amazing how physical simulations seem to seek out the smallest of numerical inaccuracies!
Some of the explanations and solutions proposed by other respondents will not work. In particular:
Numerical inaccuracy really can cause a ray to "fall through the gap". The problem is that we intersect the ray with the plane ABC (getting the point P, say) before testing against line BC. Then we intersect the ray with plane BCD (getting the point Q, say) before testing against line BC. P and Q are both represented by the closest floating-point approximation; there's no reason to expect that these exactly lie on the planes that they are supposed to lie on, and so every possibility that you can have both P to the left of BC and Q to the right of BC.
Using less-than-or-equal test won't help; it's inaccuracy in the intersection of the ray and the plane that's the trouble.
Square roots are not the issue; you can do all of the necessary computations using dot products and floating-point division.
Here are some genuine solutions:
For convex meshes, you can just test against all the planes and ignore the edges and vertices, as you say (thus avoiding the issue entirely).
Don't intersect the ray with each triangle in turn. Instead, use the scalar triple product. (This method makes the exact same sequence of computations for the ray and the edge BC when considering each triangle, ensuring that any numerical inaccuracy is at least consistent between the two triangles.)
For non-convex meshes, give the edges and vertices some width. That is, place a small sphere at each vertex in the mesh, and place a thin cylinder along each edge of the mesh. Intersect the ray with these spheres and cylinders as well as with the triangles. These additional geometric figures stop the ray passing through edges and vertices of the mesh.
Let me strongly recommend the book Real-Time Collision Detection by Christer Ericson. There's a discussion of this exact problem on pages 446–448, and an explanation of the scalar triple product approach to intersecting a ray with a triangle on pages 184–188.
It sounds like you ain't including testing if it's ON the edge (you're writing "Inside triangle edges"). Try changing code to "less than or equal" (inside, or overlapping).
I find it somewhat unlikely that your ray would fall exactly between the triangles in a way that the floating point precision would take effect. Are you absolutely positive that this is indeed the problem?
At any rate, a possible solution is instead of shooting just one ray to shoot three that are very close to each other. If one falls exactly in between that atleast one of the other two is guaranteed to fall on a triangle.
This will atleast allow you to test if the problem is really the floating point error or something more likely.
#Statement: I am indeed already using a "greater than or equal to" comparison in my code, thank you for the suggestion. +1
My current solution is to add a small nudge amount to the edge test. Basically when each triangle is tested, its edges are pushed out by a very small amount to counteract the error in floating point. Sort of like testing if the result of a floating point calculation is less than 0.01 rather than testing for equality with zero.
Is this a reasonable solution?
If you are doing distance measurements, watch out for square roots. They have a nasty habit of throwing away half of your precision. If you stack a few of these calculations up, you can get in big trouble fast. Here is a distance function I have used.
double Distance(double x0, double y0, double x1, double y1)
{
double a, b, dx, dy;
dx = abs(x1 - x0);
dy = abs(y1 - y0);
a = max(dx, dy));
if (a == 0)
return 0;
b = min(dx, dy);
return a * sqrt( 1 + (b*b) / (a*a) );
}
Since the last operation isn't a square root, you don't lose the precision any more.
I discovered this in a project I was working on. After studying it and figuring out what it did I tracked down the programmer who I thought was responsible to congratulate him, but he had no idea what I was talking about.