TWiki . Team4 . CodeTemp

#include "cBall.h" #include #include #include

using namespace std;

cBall::cBall() { position_ = cVector(0, 15, 7.00001); // a face collision velocity_ = cVector(0, -2, 0); radius_ = 1; }

cBall::~cBall() { /* Nothing to do */ }

void cBall::update(float dt, cStaticTriangleMesh& staticObjects) {

if(position_.y_ < -5) // just for the demo { float a = ((float)(rand()%100))/100.0f; float b = ((float)(rand()%100))/100.0f; float c = ((float)(rand()%100))/100.0f; float d = ((float)(rand()%100))/100.0f; float e = ((float)(rand()%100))/100.0f; float f = ((float)(rand()%100))/100.0f; position_ = cVector((a-.5)*20, 8, (c-.5)*20.0); //position_ = cVector((a-.5), 15, (a-.5)); velocity_ = cVector((d-.5)/10, -2, (f-.5)/10); radius_ = .5;//b/2 + .1; }

/* if(position_.y_ < -5) { velocity_ = cVector(0, 0, 0); //position_ = cVector(0, 15, 7.0000); // parallel to face drop (height = +5) //position_ = cVector(0, 15, 9.00001); // parallel to face drop (height = +5) //position_ = cVector(1.5, 15, 2); // single face collision (height = +5) //position_ = cVector(0, 15, 3); // direct edge drop (height = +5) position_ = cVector(4, 8, 11); // double face collision (height = -5) //position_ = cVector(1.5, 15, 2); // single face collision (height = -5)

//position_ = cVector(0, 10, 6); // vertex collision (height = +5) //velocity_ = cVector(0, -2, 0);

//position_ = cVector(2, 10, 4); // vertex collision (height = +5) //velocity_ = cVector(-1, -2, 1.5);

//position_ = cVector(0, 9, 8); // vertex collision (height = +5) //velocity_ = cVector(0, -2, -1);

//position_ = cVector(4, 9, 2); // edge collision (height = +5) //velocity_ = cVector(-2, -2, -1);

//position_ = cVector(15, 10, 7.00001); // edge collision (height = +5) //velocity_ = cVector(-3, 0, 0);

//position_ = cVector(15, 10, 7.00001); // edge collision parallel to face (height = +5) //velocity_ = cVector(-3, 0, 0); } */

if(dt == 0) return; //nothing to do

cVector newPosition = position_ + dt * velocity_;

// the overall closest intersection cIntersectionResult closestIntersection(false, 1); // no intersection yet cVector normal; // the normal at the closest point of intersection int numForwardFaces = 0; // the total number of faces contributing to the normal

// find closest face intersection and update the normal for(int i = 0; i < staticObjects.numTriangles_; ++i) { cIntersectionResult result = intersectsFace(position_, newPosition, staticObjects.faces_[i]);

if(!result.intersected_) continue;

// in case we intersect two faces at the same time if( abs(result.beta_ - closestIntersection.beta_) < .0001 ) { normal = (normal * numForwardFaces + staticObjects.faces_[i].triangle_->getNormal()); normal.normalize(); ++numForwardFaces; } else if( result.beta_ < closestIntersection.beta_ ) { closestIntersection = result; normal = staticObjects.faces_[i].triangle_->getNormal(); numForwardFaces = 1; } }

// find closest vertex intersection and update the normal for(int i = 0; i < staticObjects.numVertices_; ++i) { cIntersectionResult result = intersectsVertex(position_, newPosition, staticObjects.vertices_[i]); if(!result.intersected_) continue;

cVector newNormal; int numNewForwardFaces = 0; if(result.beta_ <= closestIntersection.beta_) { cVector incident = newPosition - position_; numNewForwardFaces = staticObjects.vertices_[i].getAvgForwardFacingNormal(incident, newNormal); }

// if there are 0 forward faces and we have intersected, it means // that update has been called recursively after moving the ball // so that it is exactly touching the vertex and now the ball's // velocity is away from the vertex, so we should ignore it

if(numNewForwardFaces == 0 ) continue;

if(result.beta_ < closestIntersection.beta_) { numForwardFaces = numNewForwardFaces; normal = newNormal; closestIntersection = result; }

if(result.beta_ == closestIntersection.beta_) { normal = numForwardFaces * normal + numNewForwardFaces * newNormal; normal.normalize(); numForwardFaces += numNewForwardFaces; closestIntersection = result; } }

// find closest edge intersection for(int i = 0; i < staticObjects.numEdges_; ++i) { cIntersectionResult result = intersectsEdge(position_, newPosition, staticObjects.edges_[i]);

if(!result.intersected_) continue;

cVector newNormal; int numNewForwardFaces = 0; if(result.beta_ <= closestIntersection.beta_) { cVector incident = newPosition - position_; numNewForwardFaces = staticObjects.edges_[i].getAvgForwardFacingNormal(incident, newNormal); }

if(numNewForwardFaces == 0 ) continue;

if(result.beta_ < closestIntersection.beta_) { numForwardFaces = numNewForwardFaces; normal = newNormal; closestIntersection = result; }

if(result.beta_ == closestIntersection.beta_) { normal = numForwardFaces * normal + numNewForwardFaces * newNormal; normal.normalize(); numForwardFaces += numNewForwardFaces; closestIntersection = result; } }

// there was no intersection with anything if(closestIntersection.intersected_ == false) { position_ = newPosition; velocity_ += cVector(0, -1, 0) * dt; return; }

position_ += closestIntersection.beta_ * dt * velocity_;

cVector reflectedVelocity = velocity_ - 2 * (normal.dot(velocity_)) * normal; velocity_ = .7 * reflectedVelocity; // damping

update((1-closestIntersection.beta_) * dt, staticObjects);

// if the ball is not moving very fast, and it is touching something, dont add gravity // later it will slide if(closestIntersection.beta_ < .00001 && velocity_.length() < .00001) return;

velocity_ += cVector(0, -1, 0) * dt * closestIntersection.beta_; // add gravity }

void cBall::draw() { glColor3f(1,1,1);

glPushMatrix(); glTranslatef(position_.x_,position_.y_,position_.z_);

// draw a sphere using 30 stacks and slices glutSolidSphere(radius_,10,10);

glPopMatrix(); }

cIntersectionResult cBall::intersectsFace(cVector &start, cVector &end, cFace &face) { if(start.y_ == end.y_) return cIntersectionResult(false, 1); // get the standardized triangle and // transform the start and end vectors into standardized space cStandardizedTriangle standard = face.triangle_->getStandardized(); float* transform = face.triangle_->getStandardVertexTranform(); cVector standardStart = start.matrixMultiply(transform); cVector standardEnd = end.matrixMultiply(transform);

// no collision occurs if the ball is within distance radius_ from the xz plane //if( standardStart.y_ < radius_ || standardStart.y_ <= standardEnd.y_ ) return cIntersectionResult(false, 1); if(standardStart.y_ <= standardEnd.y_) return cIntersectionResult(false, 1);

// calculate beta such that the center of the ball is radius above the xz plane float beta = (radius_ - standardStart.y_) / (standardEnd.y_ - standardStart.y_);

// if beta is not within [0,1] no intersection occurs if( beta < 0 || 1 < beta ) return cIntersectionResult(false, 1);

// otherwise, compute projection of ball's position at y = radius onto the xz plane cVector qPrime = standardStart + beta * (standardEnd - standardStart); qPrime.y_ = 0;

// check the edge v2-v0 if( qPrime.z_ <= 0 ) return cIntersectionResult(false, 1); // check that z is positive

// check the edge v0-v1 if( (standard.v1_.x_ = 0) && (qPrime.x_ < 0) ) // if edge on the z-axis return cIntersectionResult(false, 1);

if( qPrime.x_ <= (standard.v1_.x_ * (qPrime.z_ / standard.v1_.z_)) ) return cIntersectionResult(false, 1);

// check edge v1-v2 if( qPrime.x_ >= standard.v2_.x_ + (standard.v1_.x_ - standard.v2_.x_) * (qPrime.z_ - standard.v2_.z_) / (standard.v1_.z_ - standard.v2_.z_)) return cIntersectionResult(false, 1);

return cIntersectionResult(true, beta); } cIntersectionResult cBall::intersectsEdge(cVector &start, cVector &end, cEdge &edge) { // get the standardized edge and // transform the start and end vectors into standardized space float* transform = edge.getStandardEdgeTransform(); cVector standardStart = start.matrixMultiply(transform); cVector standardEnd = end.matrixMultiply(transform);

// checking if velocity is parallel to the edge if( standardStart.y_ = 0 && standardEnd.z_ = 0) return cIntersectionResult(false,1);

float A = (standardEnd.y_- standardStart.y_)*(standardEnd.y_- standardStart.y_) + (standardEnd.z_-standardStart.z_)*(standardEnd.z_-standardStart.z_); float B = 2 * ((standardStart.y_ * (standardEnd.y_- standardStart.y_)) + (start.z_ * (standardEnd.z_- standardStart.z_))) ; float C = (standardStart.y_*standardStart.y_) + (standardStart.z_*standardStart.z_) - (radius_*radius_); cIntersectionResult result = quadratic(A,B,C);

//checking to see if beta is actually on the edge not just x-axis if( !result.intersected_) return result; if(standardStart.x_ + result.beta_* (standardEnd.x_ - standardStart.x_) < edge.standardizedX_ && standardStart.x_ + result.beta_* (standardEnd.x_ - standardStart.x_) > 0) return result;

return cIntersectionResult(false, 1);

}

cIntersectionResult cBall::intersectsVertex(cVector &start, cVector &end, cVertex &vertex) { // the ball is moving toward the vertex, solve this quadratic float A = (end.x_-start.x_)*(end.x_-start.x_) + (end.y_-start.y_)*(end.y_-start.y_) + (end.z_-start.z_)*(end.z_-start.z_);

float B = 2*( (end.x_-start.x_)*(start.x_-vertex.x_) + (end.y_-start.y_)*(start.y_-vertex.y_) + (end.z_-start.z_)*(start.z_-vertex.z_));

float C = (start.x_-vertex.x_)*(start.x_-vertex.x_)+(start.y_-vertex.y_)*(start.y_-vertex.y_) +(start.z_-vertex.z_)*(start.z_-vertex.z_)- (radius_*radius_);

return quadratic(A,B,C); }

cIntersectionResult cBall::quadratic(float A, float B, float C) { float discr = (B*B) - (4*A*C); if( discr <= 0.0000001) return cIntersectionResult(false, 1);

discr = sqrt(discr); float beta1 = (-1*B + discr)/ (2 * A); float beta2 = (-1*B - discr)/(2 * A);

float minBeta = 1; bool inRange = false; if(beta2 > 0 && beta2 <= 1) { minBeta = beta2; inRange = true; } if(beta1 > 0 && beta2 <= 1) { inRange = true; if(beta1 < minBeta) minBeta = beta1; }

if(inRange) return cIntersectionResult(true, minBeta); else return cIntersectionResult(false, 1);

}

----- Revision r1.1 - 09 Mar 2004 - 08:59 GMT - AndrewKim
Copyright © 1999-2003 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback.