I've been implementing the collision detection and response detailed in this paper:http://www.peroxide.dk/papers/collision/collision.pdf I've got it mostly working now, but the collision response is a bit jumpy. I've only implemented collision inside the triangle but for what I've testing it against, it doesn't make a difference. Here is my code:
bool physicsObject::onSameSide(glm::vec3 point, glm::vec3 p1, glm::vec3 p2, glm::vec3 p3)
{
glm::vec3 cross1 = glm::cross(p3-p2, point-p2);
glm::vec3 cross2 = glm::cross(p3-p2, p1-p2);
if (glm::dot(cross1, cross2) >= 0.0)
return true;
else return false;
}
collisionResponsePacket physicsObject::checkTriangle(unsigned int i)
{
collisionResponsePacket packetToReturn;
glm::vec3 velocity = playerESpace.vecInElipsoidSpace( glm::vec3(-camx,-camy,-camz)-glm::vec3(-lcamx,-lcamy,-lcamz));
glm::vec3 basePos = playerESpace.vecInElipsoidSpace(glm::vec3(-lcamx,-lcamy,-lcamz));
//for now, we're just going to check the one triangle.
//.obj stores vertexes in counter-clockwise order, so we're going to swap the positions.
glm::vec3 p1 =playerESpace.vecInElipsoidSpace( (glm::vec3(ModelRegistry.models[model].m.obj[i].x3,ModelRegistry.models[model].m.obj[i].y3,ModelRegistry.models[model].m.obj[i].z3)));
glm::vec3 p2 = playerESpace.vecInElipsoidSpace((glm::vec3(ModelRegistry.models[model].m.obj[i].x2,ModelRegistry.models[model].m.obj[i].y2,ModelRegistry.models[model].m.obj[i].z2)));
glm::vec3 p3 = playerESpace.vecInElipsoidSpace((glm::vec3(ModelRegistry.models[model].m.obj[i].x1,ModelRegistry.models[model].m.obj[i].y1,ModelRegistry.models[model].m.obj[i].z1)));
//get the normal
glm::vec3 normal = glm::normalize(glm::cross(p2-p1, p3-p1));
//get signed distance
float distance = glm::dot(normal, basePos) - ((normal.x*p1.x)+(normal.y*p1.y)+(normal.z*p1.z));
//normal dot velocity
float ndv = glm::dot(normal, velocity);
//times of intersection
float time1 = (1.0 - distance)/ndv;
float time2 = (-1.0 - distance)/ndv;
if (time1 > time2)
{
float temp = time2;
time2 = time1;
time1 = temp;
}
if (time1 > 1.0 || time2 < 0.0)
{
//do something to say there wasn't a collision here
}
else
{
if (time2 > 10)
time2 = 0;
if (time1 < 0.0)
time1 = 0;
//get the point where we think that the sphere is going to collide
glm::vec3 intersectionPoint = (basePos + (time1*velocity*(float)0.95)) - normal;
//now we need to check if this collided
if (onSameSide(intersectionPoint, p1, p2, p3) && onSameSide(intersectionPoint, p2, p1, p3) && onSameSide(intersectionPoint, p3, p1, p2))
{
//there was a collision inside the triangle, so wer're done here.
packetToReturn.intersectionPoint = intersectionPoint;
packetToReturn.time0 = time1;
packetToReturn.time1 = time2;
packetToReturn.collided = true;
}
else
{
//temp, I just want to be able to check more complex meshes
return packetToReturn;
//there wasn't a collision inside the triangle so now for the fin stuff, we get to check the collision for the edges and points.
//this is also called the sweep test
//first we check collisions with the vertexes
}
}
return packetToReturn;
}
void physicsObject::testCollisionMeshWithElipsoid(double time)
{
//some of the vectors we require for the response
glm::vec3 velocity = playerESpace.vecInElipsoidSpace( glm::vec3(-camx,-camy,-camz)-glm::vec3(-lcamx,-lcamy,-lcamz));
glm::vec3 basePos = playerESpace.vecInElipsoidSpace(glm::vec3(-lcamx,-lcamy,-lcamz));
glm::vec3 destination = playerESpace.vecInElipsoidSpace(glm::vec3(-camx,-camy,-camz));
std::vector<collisionResponsePacket>results;
for (int i = 0; i < ModelRegistry.models[model].m.obj.size(); i++)
//we chech each triangle
results.push_back(checkTriangle(i));
//now we find which one we are going to respond against, then do it
for (int i = 0; i < results.size(); i++)
{
if (results[i].collided == true)
{
//we found the droids we are looking for ;)
glm::vec3 newPosition = basePos + (velocity*results[i].time0*0.9f);
glm::vec3 intersectionPoint = results[i].intersectionPoint - (velocity*results[i].time0*0.9f);
glm::vec3 slingingPlaneOrigin = intersectionPoint;
glm::vec3 slidingPlaneNormal = glm::normalize(newPosition - intersectionPoint);
float distance = glm::dot(slidingPlaneNormal, destination) - ((slidingPlaneNormal.x*slingingPlaneOrigin.x)+(slidingPlaneNormal.y*slingingPlaneOrigin.y)+(slidingPlaneNormal.z*slingingPlaneOrigin.z));
destination = destination - (distance)*slidingPlaneNormal;
//convert the new point back into what the camera will take
// lcamx = results[i].intersectionPoint.x;
//lcamy = results[i].intersectionPoint.y;
//lcamz = results[i].intersectionPoint.z;
//now we can update everything
camx = -destination.x*ELIPSE_X;
camz = -destination.z*ELIPSE_Z;
camy = -destination.y*ELIPSE_Y;
break;
}
}
results.clear();
}
I know its very inefficient, but I want the functionality there first. I've looked at the sample code in the paper but I haven't been able to work out whats wrong. I'm not recursing, but when I do, the camera warps to different places. What I want to know what is wrong with the length of the velocities, etc that would cause this kind of problem. Any help or information would be appreciated.
EDIT:
I've tried dividing the distance variable, this one: "destination - (distance)*slidingPlaneNormal;" and that seems to smooth it out but it seems to cause inaccuracies in the response and causing the camera to clip through the world.