I am trying to make a robot in a simulation move an exact distance by sending messages with a linear velocity. Right now my implementation doesn't make the robot move an exact distance. This is some sample code:
void Robot::travel(double x, double y)
{
// px and py are the current positions (constantly gets updated as the robot moves in the simulation)
// x and y is the target position that I want to go to
double startx = px;
double starty = py;
double distanceTravelled = 0;
align(x, y);
// This gets the distance from the robot's current position to the target position
double distance = calculateDistance(px, py, x, y);
// Message with velocity
geometry_msgs::Twist msg;
msg.linear.x = 1;
msg.angular.z = 0;
ros::Rate loop_rate(10);
while (distanceTravelled < distance)
{
distanceTravelled = calculateDistance(startx, starty, px, py);
// Publishes message telling the robot to move with the linear.x velocity
RobotVelocity_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
}
I asked around and someone suggested that using a PID controller for a feedback loop would solve this problem, but after reading the Wikipedia page I don't really get how I'd use it in this context. The Wikipedia page has pseudo code for the PID algorithm, but I have no idea what corresponds to what.
previous_error = setpoint - process_feedback
integral = 0
start:
wait(dt)
error = setpoint - process_feedback
integral = integral + (error*dt)
derivative = (error - previous_error)/dt
output = (Kp*error) + (Ki*integral) + (Kd*derivative)
previous_error = error
goto start
How would I implement this in the context of velocities and distances? Is distance error? Or velocity? Can anyone help please? What is the integral? Derivative? Kp? Ki? Kd? e.t.c.
Thanks.
For your problem, the setpoint will be (x,y). process_feedback will be (px,py). and output will be the velocity at which you need to travel. Kp, Ki, and Kd are parameters that you can tune to get the kind of behavior you want. For example, if Kd is too low you could shoot past the target by not slowing down enough as you approach it.
A PID controller takes three things into consideration:
error: where you want to be vs. where you are
This is certainly a big factor. If you are at point A and your target is at point B, then the vector from A to B tells you a lot about how you need to steer, but it isn't the only factor.
derivative: how fast you are approaching
If you are approaching the target quickly and you are close to it, you actually need to slow down. The derivative helps take that into consideration.
integral: alignment error
Your robot may not actually do exactly what you tell it to do. The integral helps determine how much you need to compensate for that.
Related
I want to teach myself some basic physics programming by creating a simple 2d platformer with SDL 2. It seems I'm falling at the first hurdle though, because I can't get movement using both velocity and acceleration per time unit, rather than per frame, to work.
I start by calculating the time per frame in the usual way:
previous_time = current_time;
current_time = SDL_GetTicks();
delta_time = current_time - previous_time;
Then, after the movement flag is set to true by pressing a directional button, this is passed to a function to handle the movement.
//Pass the movement flag and the milliseconds per frame to the right movement function.
if ( player.get_x() <= 740 ) {
player.x_movement_right(delta_time, 1, moving_right);
}
The integer that's passed doesn't do anything yet. Anyway, the function then determines the acceleration based on if the movement flag is set to true, and what the current velocity is:
void Player::x_movement_right(float dt, int direction, bool moving_right) {
dt /= 1000;
if (moving_right == true && _x_velocity <= 200 ) {
_x_acceleration = 50;
}
else if ( moving_right == false && _x_velocity > 0 ) {
_x_acceleration = -50;
}
else {
_x_acceleration = 0;
}
_x_velocity += _x_acceleration * dt;
_x_position += _x_velocity * dt;
}
The same process occurs if the left movement flag is activated, with inverted values of course. Yet after compiling I hit the directional keys and nothing happens.
What I've already tried:
I removed the dt's at the bottom of the movement function. The player avatar moves with incredible speed, since the acceleration is now per frame, rather than per second.
Same thing when I don't divide dt at the beginning of the movement function, since it's now per millisecond rather than per second.
I tried rounding the velocity times dt at the bottom, since I suspected SDL might have trouble calculation positions with floating point numbers rather than integers. Still no movement.
Based on this I suspect it has something to do with the numbers being too small, but I can't quite wrap my head around what the problem is or how to solve it. So, does anyone know what undoubtedly obvious thing I'm missing? Thanks in advance!
There is no way to know with the information shown, but there are several points that may help you:
Are your _x_velocity and the like floating point types? In what units are you measuring distance? It may be that your increment has not enough resolution to be nonzero.
Have you printed the values of each variable or run the program in a debugger?
What do you mean by "SDL might have trouble calculation positions with floating point numbers"? If you are using SDL's basic 2D renderer, you just need to give it the type it needs in whatever units they ask. The conversions are up to you.
Overall, I'd recommend trying to code the simulation outside SDL or graphics in general. Getting acquainted with C++, debugging and floating-point is also a plus.
I am recently working with SFML libraries and I am trying to do a Space Shooter game from scratch. After some time working on it I get something that works fine but I am facing one issue and I do not know exactly how to proceed, so I hope your wisdom can lead me to a good solution. I will try to explain it the best I can:
Enemies following a path: currently in my game, I have enemies that can follow linear paths doing the following:
float vx = (float)m_wayPoints_v[m_wayPointsIndex_ui8].x - (float)m_pos_v.x;
float vy = (float)m_wayPoints_v[m_wayPointsIndex_ui8].y - (float)m_pos_v.y;
float len = sqrt(vx * vx + vy * vy);
//cout << len << endl;
if (len < 2.0f)
{
// Close enough, entity has arrived
//cout << "Has arrived" << endl;
m_wayPointsIndex_ui8++;
if (m_wayPointsIndex_ui8 >= m_wayPoints_v.size())
{
m_wayPointsIndex_ui8 = 0;
}
}
else
{
vx /= len;
vy /= len;
m_pos_v.x += vx * float(m_moveSpeed_ui16) * time;
m_pos_v.y += vy * float(m_moveSpeed_ui16) * time;
}
*m_wayPoints_v is a vector that basically holds the 2d points to be followed.
Related to this small piece of code, I have to say that is sometimes given me problems because getting closer to the next point becomes difficult as the higher the speed of the enemies is.
Is there any other way to be more accurate on path following independtly of the enemy speed? And also related to path following, if I would like to do an introduction of the enemies before each wave movement pattern starts (doing circles, spirals, ellipses or whatever before reaching the final point), for example:
For example, in the picture below:
The black line is the path I want a spaceship to follow before starting the IA pattern (move from left to right and from right to left) which is the red circle.
Is it done hardcoding all and each of the movements or is there any other better solution?
I hope I made myself clear on this...in case I did not, please let me know and I will give more details. Thank you very much in advance!
Way points
You need to add some additional information to the way points and the NPC's position in relationship to the way points.
The code snippet (pseudo code) shows how a set of way points can be created as a linked list. Each way point has a link and a distance to the next way point, and the total distance for this way point.
Then each step you just increase the NPC distance on the set of way points. If that distance is greater than the totalDistance at the next way point, follow the link to the next. You can use a while loop to search for the next way point so you will always be at the correct position no matter what your speed.
Once you are at the correct way point its just a matter of calculating the position the NPC is between the current and next way point.
Define a way point
class WayPoint {
public:
WayPoint(float, float);
float x, y, distanceToNext, totalDistance;
WayPoint next;
WayPoint addNext(WayPoint wp);
}
WayPoint::WayPoint(float px, float py) {
x = px; y = py;
distanceToNext = 0.0f;
totalDistance = 0.0f;
}
WayPoint WayPoint::addNext(WayPoint wp) {
next = wp;
distanceToNext = sqrt((next.x - x) * (next.x - x) + (next.y - y) * (next.y - y));
next.totalDistance = totalDistance + distanceToNext;
return wp;
}
Declaring and linking waypoints
WayPoint a(10.0f, 10.0f);
WayPoint b(100.0f, 400.0f);
WayPoint c(200.0f, 100.0f);
a.addNext(b);
b.addNext(c);
NPC follows way pointy path at any speed
WayPoint currentWayPoint = a;
NPC ship;
ship.distance += ship.speed * time;
while (ship.distance > currentWayPoint.next.totalDistance) {
currentWayPoint = currentWayPoint.next;
}
float unitDist = (ship.distance - currentWayPoint.totalDistance) / currentWayPoint.distanceToNext;
// NOTE to smooth the line following use the ease curve. See Bottom of answer
// float unitDist = sigBell((ship.distance - currentWayPoint.totalDistance) / currentWayPoint.distanceToNext);
ship.pos.x = (currentWayPoint.next.x - currentWayPoint.x) * unitDist + currentWayPoint.x;
ship.pos.y = (currentWayPoint.next.y - currentWayPoint.y) * unitDist + currentWayPoint.y;
Note you can link back to the start but be careful to check when the total distance goes back to zero in the while loop or you will end up in an infinite loop. When you pass zero recalc NPC distance as modulo of last way point totalDistance so you never travel more than one loop of way points to find the next.
eg in while loop if passing last way point
if (currentWayPoint.next.totalDistance == 0.0f) {
ship.distance = mod(ship.distance, currentWayPoint.totalDistance);
}
Smooth paths
Using the above method you can add additional information to the way points.
For example for each way point add a vector that is 90deg off the path to the next.
// 90 degh CW
offX = -(next.y - y) / distanceToNext; // Yes offX = - y
offY = (next.x - x) / distanceToNext; //
offDist = ?; // how far from the line you want to path to go
Then when you calculate the unitDist along the line between to way points you can use that unit dist to smoothly interpolate the offset
float unitDist = (ship.distance - currentWayPoint.totalDistance) / currentWayPoint.distanceToNext;
// very basic ease in and ease out or use sigBell curve
float unitOffset = unitDist < 0.5f ? (unitDist * 2.0f) * (unitDist * 2.0f) : sqrt((unitDist - 0.5f) * 2.0f);
float x = currentWayPoint.offX * currentWayPoint.offDist * unitOffset;
float y = currentWayPoint.offY * currentWayPoint.offDist * unitOffset;
ship.pos.x = (currentWayPoint.next.x - currentWayPoint.x) * unitDist + currentWayPoint.x + x;
ship.pos.y = (currentWayPoint.next.y - currentWayPoint.y) * unitDist + currentWayPoint.y + y;
Now if you add 3 way points with the first offDist a positive distance and the second a negative offDist you will get a path that does smooth curves as you show in the image.
Note that the actual speed of the NPC will change over each way point. The maths to get a constant speed using this method is too heavy to be worth the effort as for small offsets no one will notice. If your offset are too large then rethink your way point layout
Note The above method is a modification of a quadratic bezier curve where the control point is defined as an offset from center between end points
Sigmoid curve
You don't need to add the offsets as you can get some (limited) smoothing along the path by manipulating the unitDist value (See comment in first snippet)
Use the following to function convert unit values into a bell like curve sigBell and a standard ease out in curve. Use argument power to control the slopes of the curves.
float sigmoid(float unit, float power) { // power should be > 0. power 1 is straight line 2 is ease out ease in 0.5 is ease to center ease from center
float u = unit <= 0.0f ? 0.0f : (unit >= 1.0f ? 1.0f: unit); // clamp as float errors will show
float p = pow(u, power);
return p / (p + pow(1.0f - u, power));
}
float sigBell(float unit, float power) {
float u = unit < 0.5f ? unit * 2.0f : 1.0f - (unit - 0.5f) * 2.0f;
return sigmoid(u, power);
}
This doesn't answer your specific question. I'm just curious why you don't use the sfml type sf::Vector2 (or its typedefs 2i, 2u, 2f)? Seems like it would clean up some of your code maybe.
As far as the animation is concerned. You could consider loading the directions for the flight pattern you want into a stack or something. Then pop each position and move your ship to that position and render, repeat.
And if you want a sin-like flight path similar to your picture, you can find an equation similar to the flight path you like. Use desmos or something to make a cool graph that fits your need. Then iterate at w/e interval inputting each iteration into this equation, your results are your position at each iteration.
Well, I think I found one of the problems but I am not sure what the solution can be.
When using the piece of code I posted before, I found that there is a problem when reaching the destination point due to the speed value. Currently to move a space ship fluently, I need to set the speed to 200...which means that in these formulas:
m_pos_v.x += vx * float(m_moveSpeed_ui16) * time;
m_pos_v.y += vy * float(m_moveSpeed_ui16) * time;
The new position might exceed the "2.0f" tolerance so the space ship cannot find the destination point and it gets stuck because the minimum movement that can be done per frame (assuming 60fps) 200 * 1 / 60 = 3.33px. Is there any way this behavior can be avoided?
My particle system's physics update function seems to be incorrect. I'm aiming for all the particles to be attracted towards the mouse.
The particles move towards the mouse pointer just as expected, until they go very near. When they are near, they speed up so much, that they fly far away from the pointer and never return.
Here's the update function:
void updateParticle(particle& p,double time){
const double G=0.000000000066726;
const double POINTERMASS=1000000000000;
double squareDistance=pow(p.coords.x-pointerDevice.x,2)+pow(p.coords.y-pointerDevice.y,2)+pow(p.coords.z-pointerDevice.z,2);
if(squareDistance<0.001)
squareDistance=0.001;//to fix the possible division by zero
coords_3d_f accelerationVector={p.coords.x-pointerDevice.x,p.coords.y-pointerDevice.y,p.coords.z-pointerDevice.z};
accelerationVector=vector_scalar_multiplication(vector_unit(accelerationVector),((G*POINTERMASS)/squareDistance));
accelerationVector=vector_scalar_multiplication(accelerationVector,time);
p.velocity=vector_addition(p.velocity,accelerationVector);
p.coords.x-=p.velocity.x*time;
p.coords.y-=p.velocity.y*time;
p.coords.z-=p.velocity.z*time;
}
When the squareDistance is constant, the program looks OK, but I know it's false.
So, what am I doing wrong?
Force is inversely proportional to the square of the distance, so as the distance approaches 0, force (and acceleration) approach infinity. In other words, if the particles get very close, they also get very fast.
If you want to be physically accurate, make your pointer-object have a finite size, so that particles bounce off of it.
If you don't need to be accurate, you can make the force decrease when the particles are very close.
It's very simple: when particles get in touch with the mouse pointer squareDistance becomes 0 and produces undefined behavior for your particles by ((G*POINTERMASS)/squareDistance) because dividing by zero is illegal.
This might work better for you:
if (squareDistance >= 1.0) // 1.0 is the zero tolerance for your context of pixel distances
{
// proceed normally
accelerationVector=vector_scalar_multiplication(vector_unit(accelerationVector),((G*POINTERMASS)/squareDistance));
accelerationVector=vector_scalar_multiplication(accelerationVector,time);
}
else
{
// no acceleration
accelerationVector=/*{0, 0}*/;
}
When your particle gets very close to the mouse pointer the particle is going to have a very high velocity. When this velocity is multiplied by the time this is when the particle will jump very far away.
You can try to fix this by setting a maximum velocity.
Simulating the equation of motion involve the integration of a function at finite intervals, and so one can only approximate the function. This give rise to instability in the system. An easy and fast solution is to use a fixed-step verlet integration:
void integrate(particle& p, double t2, const particle& mouse)
{
// universal gravitational constant
const double G = 0.000000000066726;
// artificial drag
// set it to 1.0 to not have any drag
// set it to 0.0 to not have any momentum
const double drag = 0.99;
// get direction and distance between the particle and the mouse
dvec3 dir = p.pos - mouse.pos;
double dist2 = dot(dir, dir);
double dist = sqrt(dist2);
dir /= dist;
// calculate relative acceleration vector
dvec3 a = -dir * G * (p.mass + mouse.mass) / dist2;
// verlet integration
dvec3 tmp = p.pos;
p.pos += (p.pos - p.prev_pos) * drag + a * t2;
p.prev_pos = tmp;
}
void update(particle& p, double elapsed, const particle& mouse, double& accumulator)
{
// fixed timestep (arbitrary)
const double timestep = 1.0 / 120.0;
const double timestep2 = timestep * timestep;
// "accumulate" time
accumulator += elapsed;
// "consume" time
while(accumulator > timestep)
{
// perform integration
integrate(p, timestep2, mouse);
accumulator -= timestep;
}
}
Note: It use the GLM math library for clarity.
This question has one major question, and one minor question. I believe I am right in either question from my research, but not both.
For my physics loop, the first thing I do is apply a gravitational force to my TotalForce for a rigid body object. I then check for collisions using my TotalForce and my Velocity. My TotalForce is reset to (0, 0, 0) after every physics loop, although I will keep my velocity.
I am familiar with doing a collision check between a moving sphere and a static plane when using only velocity. However, what if I have other forces besides velocity, such as gravity? I put the other forces into TotalForces (right now I only have gravity). To compensate for that, when I determine that the sphere is not currently overlapping the plane, I do
Vector3 forces = (sphereTotalForces + sphereVelocity);
Vector3 forcesDT = forces * fElapsedTime;
float denom = Vec3Dot(&plane->GetNormal(), &forces);
However, this can be problematic for how I thought was suppose to be resting contact. I thought resting contact was computed by
denom * dist == 0.0f
Where dist is
float dist = Vec3Dot(&plane->GetNormal(), &spherePosition) - plane->d;
(For reference, the obvious denom * dist > 0.0f meaning the sphere is moving away from the plane)
However, this can never be true. Even when there appears to be "resting contact". This is due to my forces calculation above always having at least a .y of -9.8 (my gravity). When when moving towards a plane with a normal of (0, 1, 0) will produce a y of denom of -9.8.
My question is
1) Am I calculating resting contact correctly with how I mentioned with my first two code snippets?
If so,
2) How should my "other forces" such as gravity be used? Is my use of TotalForces incorrect?
For reference, my timestep is
mAcceleration = mTotalForces / mMass;
mVelocity += mAcceleration * fElapsedTime;
Vector3 translation = (mVelocity * fElapsedTime);
EDIT
Since it appears that some suggested changes will change my collision code, here is how i detect my collision states
if(fabs(dist) <= sphereRadius)
{ // There already is a collision }
else
{
Vector3 forces = (sphereTotalForces + sphereVelocity);
float denom = Vec3Dot(&plane->GetNormal(), &forces);
// Resting contact
if(dist == 0) { }
// Sphere is moving away from plane
else if(denom * dist > 0.0f) { }
// There will eventually be a collision
else
{
float fIntersectionTime = (sphereRadius - dist) / denom;
float r;
if(dist > 0.0f)
r = sphereRadius;
else
r = -sphereRadius;
Vector3 collisionPosition = spherePosition + fIntersectionTime * sphereVelocity - r * planeNormal;
}
}
You should use if(fabs(dist) < 0.0001f) { /* collided */ } This is to acocunt for floating point accuracies. You most certainly would not get an exact 0.0f at most angles or contact.
the value of dist if negative, is in fact the actual amount you need to shift the body back onto the surface of the plane in case it goes through the plane surface. sphere.position = sphere.position - plane.Normal * fabs(dist);
Once you have moved it back to the surface, you can optionally make it bounce in the opposite direction about the plane normal; or just stay on the plane.
parallel_vec = Vec3.dot(plane.normal, -sphere.velocity);
perpendicular_vec = sphere.velocity - parallel_vec;
bounce_velocity = parallel - perpendicular_vec;
you cannot blindly do totalforce = external_force + velocity unless everything has unit mass.
EDIT:
To fully define a plane in 3D space, you plane structure should store a plane normal vector and a point on the plane. http://en.wikipedia.org/wiki/Plane_(geometry) .
Vector3 planeToSphere = sphere.point - plane.point;
float dist = Vector3.dot(plane.normal, planeToSphere) - plane.radius;
if(dist < 0)
{
// collided.
}
I suggest you study more Maths first if this is the part you do not know.
NB: Sorry, the formatting is messed up... I cannot mark it as code block.
EDIT 2:
Based on my understanding on your code, either you are naming your variables badly or as I mentioned earlier, you need to revise your maths and physics theory. This line does not do anything useful.
float denom = Vec3Dot(&plane->GetNormal(), &forces);
A at any instance of time, a force on the sphere can be in any direction at all unrelated to the direction of travel. so denom essentially calculates the amount of force in the direction of the plane surface, but tells you nothing about whether the ball will hit the plane. e.g. gravity is downwards, but a ball can have upward velocity and hit a plane above. With that, you need to Vec3Dot(plane.normal, velocity) instead.
Alternatively, Mark Phariss and Gerhard Powell had already give you the physics equation for linear kinematics, you can use those to directly calculate future positions, velocity and time of impact.
e.g. s = 0.5 * (u + v) * t; gives the displacement after future time t. compare that displacement with distance from plane and you get whether the sphere will hit the plane. So again, I suggest you read up on http://en.wikipedia.org/wiki/Linear_motion and the easy stuff first then http://en.wikipedia.org/wiki/Kinematics .
Yet another method, if you expect or assume no other forces to act on the sphere, then you do a ray / plane collision test to find the time t at which it will hit the plane, in that case, read http://en.wikipedia.org/wiki/Line-plane_intersection .
There will always be -9.8y of gravity acting on the sphere. In the case of a suspended sphere this will result in downwards acceleration (net force is non-zero). In the case of the sphere resting on the plane this will result in the plane exerting a normal force on the sphere. If the plane was perfectly horizontal with the sphere at rest this normal force would be exactly +9.8y which would perfectly cancel the force of gravity. For a sphere at rest on a non-horizontal plane the normal force is 9.8y * cos(angle) (angle is between -90 and +90 degrees).
Things get more complicated when a moving sphere hits a plane as the normal force will depend on the velocity and the plane/sphere material properties. Depending what your application requirements are you could either ignore this or try some things with the normal forces and see how it works.
For your specific questions:
I believe contact is more specifically just when dist == 0.0f, that is the sphere and plane are making contact. I assume your collision takes into account that the sphere may move past the plane in any physics time step.
Right now you don't appear to have any normal forces being put on the sphere from the plane when they are making contact. I would do this by checking for contact (dist == 0.0f) and if true adding the normal force to the sphere. In the simple case of a falling sphere onto a near horizontal plane (angle between -90 and +90 degrees) it would just be sphereTotalForces += Vector3D(0, 9.8 * cos(angle), 0).
Edit:
From here your equation for dist to compute the distance from the edge of sphere to the plane may not be correct depending on the details of your problem and code (which isn't given). Assuming your plane goes through the origin the correct equation is:
dist = Vec3Dot(&spherePosition, &plane->GetNormal()) - sphereRadius;
This is the same as your equation if plane->d == sphereRadius. Note that if the plane is not at the origin then use:
D3DXVECTOR3 vecTemp(spherePosition - pointOnPlane);
dist = Vec3Dot(&vecTemp, &plane->GetNormal()) - sphereRadius;
The exact solution to this problem involves some pretty serious math. If you want an approximate solution I strongly recommend developing it in stages.
1) Make sure your sim works without gravity. The ball must travel through space and have inelastic (or partially elastic) collisions with angled frictionless surfaces.
2) Introduce gravity. This will change ballistic trajectories from straight lines to parabolae, and introduce sliding, but it won't have much effect on collisions.
3) Introduce static and kinetic friction (independently). These will change the dynamics of sliding. Don't worry about friction in collisions for now.
4) Give the ball angular velocity and a moment of inertia. This is a big step. Make sure you can apply torques to it and get realistic angular accelerations. Note that realistic behavior of a spinning mass can be counter-intuitive.
5) Try sliding the ball along a level surface, under gravity. If you've done everything right, its angular velocity will gradually increase and its linear velocity gradually decrease, until it breaks into a roll. Experiment with giving the ball some initial spin ("draw", "follow" or "english").
6) Try the same, but on a sloped surface. This is a relatively small step.
If you get this far you'll have a pretty realistic sim. Don't try to skip any of the steps, you'll only give yourself headaches.
Answers to your physics problems:
f = mg + other_f; // m = mass, g = gravity (9.8)
a = f / m; // a = acceleration
v = u + at; // v = new speed, u = old speed, t = delta time
s = 0.5 * (u + v) *t;
When you have a collision, you change the both speeds to 0 (or v and u = -(u * 0.7) if you want it to bounce).
Because speed = 0, the ball is standing still.
If it is 2D or 3D, then you just change the speed in the direction of the normal of the surface to 0, and keep the parallel speed the same. That will result in the ball rolling on the surface.
You must move the ball to the surface if it cuts the surface. You can make collision distance to a small amount (for example 0.001) to make sure it stay still.
http://www.physicsforidiots.com/dynamics.html#vuat
Edit:
NeHe is an amazing source of game engine design:
Here is a page on collision detection with very good descriptions:
http://nehe.gamedev.net/tutorial/collision_detection/17005/
Edit 2: (From NeHe)
double DotProduct=direction.dot(plane._Normal); // Dot Product Between Plane Normal And Ray Direction
Dsc=(plane._Normal.dot(plane._Position-position))/DotProduct; // Find Distance To Collision Point
Tc= Dsc*T / Dst
Collision point= Start + Velocity*Tc
I suggest after that to take a look at erin cato articles (the author of Box2D) and Glenn fiedler articles as well.
Gravity is a strong acceleration and results in strong forces. It is easy to have faulty simulations because of floating imprecisions, variable timesteps and euler integration, very quickly.
The repositionning of the sphere at the plane surface in case it starts to burry itself passed the plane is mandatory, I noticed myself that it is better to do it only if velocity of the sphere is in opposition to the plane normal (this can be compared to face culling in 3D rendering: do not take into account backfaced planes).
also, most physics engine stops simulation on idle bodies, and most games never take gravity into account while moving, only when falling. They use "navigation meshes", and custom systems as long as they are sure the simulated objet is sticking to its "ground".
I don't know of a flawless physics simulator out there, there will always be an integration explosion, a missed collision (look for "sweeped collision").... it takes a lot of empirical fine-tweaking.
Also I suggest you look for "impulses" which is a method to avoid to tweak manually the velocity when encountering a collision.
Also take a look to "what every computer scientist should know about floating points"
good luck, you entered a mine field, randomly un-understandable, finger biting area of numerical computer science :)
For higher fidelity (wouldn't solve your main problem), I'd change your timestep to
mAcceleration = mTotalForces / mMass;
Vector3 translation = (mVelocity * fElapsedTime) + 0.5 * mAcceleration * pow(fElapsedTime, 2);
mVelocity += mAcceleration * fElapsedTime;
You mentioned that the sphere was a rigid body; are you also modeling the plane as rigid? If so, you'd have an infinite point force at the moment of contact & perfectly elastic collision without some explicit dissipation of momentum.
Force & velocity cannot be summed (incompatible units); if you're just trying to model the kinematics, you can disregard mass and work with acceleration & velocity only.
Assuming the sphere is simply dropped onto a horizontal plane with a perfectly inelastic collision (no bounce), you could do [N.B., I don't really know C syntax, so this'll be Pythonic]
mAcceleration = if isContacting then (0, 0, 0) else (0, -9.8, 0)
If you add some elasticity (say half momentum conserved) to the collision, it'd be more like
mAcceleration = (0, -9.8, 0) + if isContacting then (0, 4.9, 0)
I wish to zoom in on the target of an orbiting camera.
The camera is manipulated using a function like this:
moveCamera(x,y,z);
Depending on angle the values x,y,z should be different to get a correct zoom feature but I cant figure out an way to do it.
I use functions like getCameraposx, getTargetposy etc.. to get the coordinates for my target and camera.
Zoom kinda works now after PigBens help but I've run in to a problem. Zooming in is no problem but after zooming in too close zooming out stops working. And with too close I'm still quite far away.
Here is my zoom function.
void Camera::orbZoom(bool Zoo)
{
float x;
float y;
float z;
float xc;
float yc;
float zc;
float zoom;
x=getTargetposx();
y=getTargetposy();
z=getTargetposz();
xc=getCameraposx();
yc=getCameraposy();
zc=getCameraposz();
xc=xc-x;
yc=yc-y;
zc=zc-z;
if ( ivan==true){
zoom = 1.02;
if (xc<1){xc=+1.5;}
else if (yc<1){yc=+1.5;}
else if (zc<1){zc=+1.5;}
xc=xc*zoom;
yc=yc*zoom;
zc=zc*zoom;
}
if(ivan==false) {
zoom = 0.98;
xc=xc*zoom;
yc=yc*zoom;
zc=zc*zoom;
}
xc=xc+x;
yc=yc+y;
zc=zc+z;
camerapos.assign(xc,yc,zc);
}
Ok so the last thing didnt work as I wrote in the last comment. I'm thinking there is something else causing this behavior. The limit for when it stops working is just a bit closer to target than cameras starting position or at starting position, not really sure on that. But if I start with zooming out and dont get any closer than the cameras starting position it's working.
I think the bug is in this part of the code but I could be wrong so if anyone want to see some other part just ask. All my other camera behaviors are working correctly. Two modes, orbit and tumble. Pitch, yaw and roll works for both modes and strafing for tumble mode.
Here are for example two of those functions.
void Camera::strafeUp(float distance)
{
camerapos += upvect * distance;
targetpos += upvect * distance;
}
void Camera::tumbleYaw(float angle)
{
Quaternionf rotation((angle*PIdiv180), upvect);
rightvect = rotation.matrix() * rightvect;
forwardvect = rotation.matrix() * forwardvect;
forwardvect.normalize();
rightvect.normalize();
targetpos = camerapos + forwardvect * cameralength;
}
Subtract the target position from the camera position, then scale it, then add the target position in again.
camera_position -= target_position;
camera_position /= zoom_factor;
camera_position += target_position;
Regarding your second problem. My guess is that it's due to lack of precision in floats. When you get down to a certain point, multiplying by 1.02 is not enough to change the float's value to the next higher representable value, so it doesn't change at all. My tests indicate that this doesn't happen until the float is in the 10e-44 range, so you must be using some pretty gigantic units for this to be a problem. A few possible solutions.
Use doubles instead of floats. You will still have the same problem. But it won't come into play until a much much closer zoom.
Use smaller units. I usually just go with 1.0 = 1 meter and I've never run in to this problem.
Enforce a maximum zoom. You would actually do this in combination with the other 2 above.