• Advertisement
Sign in to follow this  

motion vectors and creases, part 2

This topic is 3729 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Original thread: http://www.gamedev.net/community/forums/topic.asp?topic_id=355676 It above thread there's excerpt from source code, by user jyk:
if (normals.size() > 1)
{
    // For every pair of normals
    for (int i = 0; i < normals.size(); i++)
    {
        for (int j = i + 1; j < normals.size(); j++)
        {
            // Create a vector that follows the 'crease' between the two normals
            Vector3 dir = normals[i].Cross(normals[j]);
            
            // Coplanar normals might produce zero-length cross products, so bail if that happens
            if (dir.LengthSquared() < Math::EPSILON)
                break;
                
            // Normalize the 'crease' vector
            dir.Normalize();

            // Project the original and new velocities into the plane of the crease
            Vector3 ovel = originalvel - dir * originalvel.Dot(dir);
            Vector3 nvel = newvel - dir * newvel.Dot(dir);

            // If velocities are opposed or angle of corner is acute, restrict the velocity to the crease
            if (ovel.Dot(nvel) <= 0.0f || normals[i].Dot(normals[j]) < 0.0f)
                newvel = dir * dir.Dot(newvel);
        }
    }
}

I'm curious if this code works correctly - what if we have 10 normals that form 3 creases? From my understanding of this code 'newvel' will be adjusted according to last crease visited - so it will violate other two creases handled in previous for(i)/for(j) iterations? Or maybe it automagically produces correct output after number of timesteps?

Share this post


Link to post
Share on other sites
Advertisement
It's been a while since I wrote that code, and TBH there might be some other relevant bits that I left out when I posted it. I can say though that the code always worked perfectly for me, and handled obtuse, acute, and multi-polygon corners perfectly.

Also, what do you mean by '10 normals forming 3 creases'? (I can't quite visualize that...)

Share this post


Link to post
Share on other sites
I believe you that it works properly, I just currently can't see how it's possible.

As I understand, during one timestep you accumulate normals in vector 'normals'. So, there can be situation when 'normals' vector contains say 10 normals, among which there are 3 pairs for which angle is acute. In such case(I agree that is somewhat extreme), your code will handle only last crease, violating, two other creases - am I right?

Share this post


Link to post
Share on other sites
I noticed that this is very similar to GPLed Quake swept collision code, whith the difference that I understand what's happening in Quake :)

To cite their code(released under General Public License 2+):


VectorCopy (ent->v.velocity, original_velocity);
VectorCopy (ent->v.velocity, primal_velocity);
numplanes = 0;

time_left = time;

for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
{
for (i=0 ; i<3 ; i++)
end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];

trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);

(...)

if (trace.fraction == 1)
break; // moved the entire distance

(...)

time_left -= time_left * trace.fraction;

// cliped to another plane
if (numplanes >= MAX_CLIP_PLANES)
{ // this shouldn't really happen
VectorCopy (vec3_origin, ent->v.velocity);
return 3;
}

VectorCopy (trace.plane.normal, planes[numplanes]);
numplanes++;

//
// modify original_velocity so it parallels all of the clip planes
//
for (i=0 ; i<numplanes ; i++)
{
ClipVelocity (original_velocity, planes[i], new_velocity, 1);
for (j=0 ; j<numplanes ; j++)
if (j != i)
{
if (DotProduct (new_velocity, planes[j]) < 0)
break; // not ok
}
if (j == numplanes)
break;
}

if (i != numplanes)
{ // go along this plane
VectorCopy (new_velocity, ent->v.velocity);
}
else
{ // go along the crease
if (numplanes != 2)
{
// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
VectorCopy (vec3_origin, ent->v.velocity);
return 7;
}
CrossProduct (planes[0], planes[1], dir);
d = DotProduct (dir, ent->v.velocity);
VectorScale (dir, d, ent->v.velocity);
}

//
// if original velocity is against the original velocity, stop dead
// to avoid tiny occilations in sloping corners
//
if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
{
VectorCopy (vec3_origin, ent->v.velocity);
return blocked;
}
}



So basically they are checking for first collision, adding collision normal to the list, then trying to find clipped velocity that is ok for all stored planes. If good velocity isn't found, then they're taking crease direction for 2-contact situation.
They're also zeroing velocity in following situations:
1) numplanes >= MAX_CLIP_PLANES in too complex places
2) good velocity can't be found and plan num > 2
3) new velocity is opposite to orignal velocity (dot product <=0)

So it seems that you extended somehow step 2 here - by handling more than one crease at once. On the other hand, when I'm trying to visualize situation with more than one crease, it seems to me that the only proper response it to stop player because it's dead end!?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement