Advertisement

conservative advancement help

Started by February 24, 2016 10:35 PM
0 comments, last by LorenzoGatti 8 years, 11 months ago

Hello Everyone,

I am not quite sure I understand a topic called "conservative advancement" and how it's applied. From what I managed to cobble over the internet (including Erin Catto's slides) for two non-rotating and for the case of simplicity two circles, conservative advancement might look like this.


bool conservativeAdvance(Circle *c1, Circle *c2){//from c1 perspective
 
 Vec2 rel_vel=c2->vel-c1->vel;
 float t=0.0f; 
 const float TOLERANCE=0.1f;//some arbitrary number
 float vel_bound;//not sure what this is

 float distance=distBetweenCircles(c1,c2);
 
 while(abs(distance)>TOLERANCE){
  float delta=abs(distance)/vel_bound;
  t+=delta;
  c1->pos=c1->pos+rel_vel*t;  
  distance=distBetweenCircles(c1,c2);
  if(t<0.0f || t>1.0f)
   return false;
  else
   return true;//collision at time t and handle response


 }
 


}

I know I probably completely bungled it, but if someone could tell me explain to me the correct way to do this it would be greatly appreciated.

Thanks,

Mike

It seems that the purpose of your function is to "move" c1 and c2 from their state at time t0 (by altering their pos members) returning true if they have a collision, and in that case advance them only until they touch.

At first sight it's reasonable, but you discard the most important piece of information: when do c1 and c2 collide? Instead, you should return t, how long c1 and c2 were able to move without colliding.

Given the maximum advancement time step T (it can be a constant, or a relatively read-only global variable, rather than an argument of your function, but hardcoding T=1.0 like you do is quite messy) the calling code knows that If t = T the circles can advance without colliding; while if t < T they collide after moving for a time t.

The other great misunderstanding is that there are more than two objects. Conservative advancement is advancing the simulation from an initial state to when the next collision happens or by the target time step T, whichever happens first; then resolving the collision (causing some objects to change velocity, cease to exist, etc.) and repeating until the sum of the conservative advancements reaches T and you can draw the next frame. Clearly the t values you use need to be the minimum of all pairwise collision times, and you cannot commit an advancement until you know no collisions precede its end time: if c2 hits c3 before when it would hit c1 if c3 didn't exist, the collision time between c1 and c2 is invalid.

Other logical errors, like having a while loop, not initializing vel_bound, using distances between circles rather than between capsules, moving only c1 but not c2, using relative velocity rather than the actual velocities of c1 and c2, while serious, are quite irrelevant.

Suggested changes, assuming pointLineDistance() takes three Vec2 arguments, the single point P and the endpoints A, B of the segment, and returns the distance between P and AB and p such that the closest point to P on the segment is A+p*(B-A); 0.0<=p<=1.0.


//add const and constexpr to taste
double possibleAdvancement(Circle *c1, Circle *c2, double T){ 
    Vec2 rel_vel=c2->vel-c1->vel;//c1 remains still
    std::pair<double,double> distance=pointLineDistance(c1->pos,c2->pos,c1->pos+T*rel_vel);
    if (distance.first<(c1->radius+c2->radius)){
        return distance.second*T;
    }else{
        return T;
    }
}

Omae Wa Mou Shindeiru

This topic is closed to new replies.

Advertisement