// calculate the damping force for collision springs void dampingForceCollision(const point& a, const point& b, const point& va, const point& vb, double kDamp, point& n, point& f) { // initialize temp force f f.x = 0; f.y = 0; f.z = 0; point diff; point diffVelocity; point normalizedDiff; double diffLength; double elasticForceScalar; double cosF; // let diff be the vector pointing from b to a pDIFFERENCE(a, b, diff); diffLength = sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z); // here va and vb are velocities of points a and b pDIFFERENCE(va, vb, diffVelocity); elasticForceScalar = (-kDamp) * ((diffVelocity.x * diff.x + diffVelocity.y * diff.y + diffVelocity.z * diff.z) / diffLength); // normalized vector diff normalizedDiff.x = diff.x / diffLength; normalizedDiff.y = diff.y / diffLength; normalizedDiff.z = diff.z / diffLength; pMULTIPLY(normalizedDiff, elasticForceScalar, f); DOTPRODUCTp(f, n, cosF); pMULTIPLY(n, cosF, f); }
/* Function: PenaltyPushBack * Description: Responds to the collision that is detected and performs penalty method for model spheres * Input: cur - current model structure * p2 - center of the other model * r1 - radius of the other model * Output: void */ void PenaltyPushBack(pModel *cur, pModel *next) { point distCI, distIC, inter, velDir, cVel; double length; pDIFFERENCE(cur->cModel, next->cModel, inter); pNORMALIZE(inter); pCPY(next->pObj->avgVel, velDir); pNORMALIZE(velDir); pCPY(cur->pObj->avgVel, cVel); pNORMALIZE(cVel); pMULTIPLY(inter, next->radius, inter); for (unsigned int index = STARTFROM; index <= cur->pObj->model->numvertices; index++) { point cP = vMake(cur->pObj->model->vertices[3*index], cur->pObj->model->vertices[3*index + 1], cur->pObj->model->vertices[3*index + 2]); length = vecLeng(cP, inter); point pForce = penaltyForce(cP, cur->pObj->velocity[index], inter, velDir, cur->pObj->kSphere, cur->pObj->dSphere); // Add the forces to the collided vertex pMULTIPLY(pForce, (1.0 / (length * length)) * cur->pObj->mass[index], pForce); pSUM(cur->pObj->extForce[index] , pForce, cur->pObj->extForce[index]); point nP = vMake(next->pObj->model->vertices[3*index], next->pObj->model->vertices[3*index + 1], next->pObj->model->vertices[3*index + 2]); length = vecLeng(nP, inter); point nForce = penaltyForce(nP, next->pObj->velocity[index], inter, cVel, next->pObj->kSphere, next->pObj->dSphere); // Add the forces to the collided vertex pMULTIPLY(nForce, -(1.0 / (length * length)) * next->pObj->mass[index], nForce); pSUM(next->pObj->extForce[index], nForce, next->pObj->extForce[index]); } }
/* Function: computeHooksForce * Description: Compute Hook's Law in 3D * Input: index - index of the vertex which collided * wallP - point on the wall where the vertex is colliding * Output: Computed hooks force */ point computeHooksForce(int index, point B, phyzx *phyzxObj) { point L, unitV; double mag = 0; double restLength = 0, length; point hooksForce, A; memset( (void*)&L, 0, sizeof(L)); memset( (void*)&unitV, 0, sizeof(unitV)); memset( (void*)&hooksForce, 0, sizeof(hooksForce)); memset( (void*)&A, 0, sizeof(A)); A = vMake(phyzxObj->model->vertices[3*index], phyzxObj->model->vertices[3*index + 1], phyzxObj->model->vertices[3*index + 2]); pDIFFERENCE(A, B, L); pCPY(L, unitV); pNORMALIZE(unitV); //xxx /*length = A.y - B.y; unitV.x = 0; unitV.y = 1; unitV.z = 0;*/ pMULTIPLY(unitV, -(phyzxObj->kWall) * length * phyzxObj->mass[index], hooksForce); //pMULTIPLY(unitV, -(phyzxObj->kWall) * length, hooksForce); return hooksForce; }
/* Function: AreaOfTri * Description: Computes the area of a triangle * Input: inputModel - three vertices of the triangle * Output: Area */ double AreaOfTri(point A, point B, point C) { double mside1, mside2; point side1, side2; double dot = 0.0; pDIFFERENCE(A, B, side1); pDIFFERENCE(C, B, side2); mside1 = vecLeng(A, B); mside2 = vecLeng(C, B); dot = dotProd(side1, side2); if(mside1 > mside2) return (sqrt(mside2 * mside2 - dot * dot) * mside1) / 2.0; else return (sqrt(mside1 * mside1 - dot * dot) * mside2) / 2.0; }
bool Pick(int x, int y) { double length; point ray_orig, ray_dir; ViewUnProject(x, y, 0.0f, &ray_orig); ViewUnProject(x, y, 1.0f, &ray_dir); pDIFFERENCE(ray_dir, ray_orig, ray_dir); pNORMALIZE(ray_dir); }
// calculate the hook force for collision springs void hookForceCollision(const point& a, const point& b, double kHook, point& n, point& f) { // initialize temp force f f.x = 0; f.y = 0; f.z = 0; point diff; double elasticForceScalar; // let diff be the vector pointing from b to a pDIFFERENCE(a, b, diff); pMULTIPLY(diff, -kHook, diff); DOTPRODUCTp(diff, n, elasticForceScalar); pMULTIPLY(n, elasticForceScalar, f); }
/* Function: penaltyForce * Description: Computes the penalty force between two points. * Input: p - Coordinates of first point * pV - Velocity of first point * I - Intersection point * V - Velocity of Intersection point * kH - K value for Hook's Law * kD - K value for damping force * Output: Penalty force vector */ point penaltyForce(point p, point pV, point I, point V, double kH, double kD) { double mag, length, dot; point dist, hForce, dForce, pVel, vDiff, pForce; // Initialize force computation variables pDIFFERENCE(p, I, dist); pDIFFERENCE(pV, V, vDiff); dot = dotProd(vDiff, dist); // Compute Hooks Force pNORMALIZE(dist); pMULTIPLY(dist, -(kH * length), hForce); // Compute Damping Forces mag = length; pNORMALIZE(pV); pMULTIPLY(pV, (kD * (dot/length)), dForce); // Compute Penalty Force pSUM(hForce, dForce, pForce); return pForce; } //end penaltyForce
// calculate the hook force between point a and its the next neighbour point b void hookForceBend(const point& a, const point& b, double kHook, point& f) { // initialize temp force f f.x = 0; f.y = 0; f.z = 0; point diff; point normalizedDiff; double diffLength; double elasticForceScalar; // let diff be the vector pointing from b to a pDIFFERENCE(a, b, diff); diffLength = sqrt(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z); // normalized vector diff normalizedDiff.x = diff.x / diffLength; normalizedDiff.y = diff.y / diffLength; normalizedDiff.z = diff.z / diffLength; // the elastic force exerted on a is elasticForceScalar = (-kHook) * (diffLength - restLengthBend); pMULTIPLY(normalizedDiff, elasticForceScalar, f); }
void planeCollisionForce(world * jello, int i, int j, int k, const bool& s, const point& pn, point &a) { if (s == false) // the point collided with the plane { double distance; point normal; double normalLength; point normalizedN; point pointOnPlane; point f; point vPlane; vPlane.x = 0; vPlane.y = 0; vPlane.z = 0; // D = (ax + by + cz + d) / sqrt(a*a + b*b + c*c) distance = (jello->a * jello->p[i][j][k].x + jello->b * jello->p[i][j][k].y + jello->c * jello->p[i][j][k].z + jello->d); distance = distance / sqrt(jello->a * jello->a + jello->b * jello->b + jello->c * jello->c); normalLength = sqrt(pn.x * pn.x + pn.y * pn.y + pn.z * pn.z); // normalized normal, get the orientation of the normal normalizedN.x = (pn.x / normalLength); normalizedN.y = (pn.y / normalLength); normalizedN.z = (pn.z / normalLength); pMULTIPLY(normalizedN, distance, normalizedN); // calculate the point on plane pDIFFERENCE(jello->p[i][j][k], normalizedN, pointOnPlane); // calculate the direction normal.x = (pn.x / normalLength); normal.y = (pn.y / normalLength); normal.z = (pn.z / normalLength); hookForceCollision(jello->p[i][j][k], pointOnPlane, jello->kCollision, normal, f); pSUM(f, a, a); dampingForceCollision(jello->p[i][j][k], pointOnPlane, jello->v[i][j][k], vPlane, jello->dCollision, normal, f); pSUM(f, a, a); } }
void RenderClothSystem(cloth *clothItem, GLuint texId) { double length = 0.0f; struct tex { float u; float v; }; struct tex texture, increment; if(gRenderMode == THREAD) { glLineWidth(1); glPointSize(5); glDisable(GL_LIGHTING); // Render the cloth points glBegin(GL_POINTS); RenderPoints(clothItem); glEnd(); // Render the cloth springs for(int row = 0; row < clothItem->height; row++) { for(int col = 0; col < clothItem->width; col++) { glBegin(GL_LINES); // Render the structural springs RenderSpring(clothItem, nMake(col, row, 0), nMake(1, 0, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(-1, 0, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(0, 1, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(0, -1, 0)); // Render shear springs along the side RenderSpring(clothItem, nMake(col, row, 0), nMake(1, 1, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(1, -1, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(-1, 1, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(-1, -1, 0)); // Render bend springs RenderSpring(clothItem, nMake(col, row, 0), nMake(2, 0, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(-2, 0, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(0, 2, 0)); RenderSpring(clothItem, nMake(col, row, 0), nMake(0, -2, 0)); glEnd(); } } glEnable(GL_LIGHTING); } if(gRenderMode == TRIANGLE) { glDisable(GL_LIGHTING); glDisable(GL_CULL_FACE); glPolygonMode(GL_FRONT, GL_FILL); // Accumulate the normals for all the points in the cloth point len1, len2, len3; int index, index1, index2, index3; for(int row = 0; row < clothItem->height - 1; row++) { for(int col = 0; col < clothItem->width - 1; col ++) { /* index index1 ----------- | /| | T1 / | | / | | / | | / | | / | | / | | / T2 | |/ | ----------- index2 index3 */ index = FindIndexInArray(row, col, clothItem->width); index1 = FindIndexInArray(row, col + 1, clothItem->width); index2 = FindIndexInArray(row + 1, col, clothItem->width); index3 = FindIndexInArray(row + 1, col + 1, clothItem->width); // First triangle - left top pDIFFERENCE(clothItem->positions[index1], clothItem->positions[index], len1); pDIFFERENCE(clothItem->positions[index2], clothItem->positions[index], len2); CROSSPRODUCTp(len1, len2, len3); pNORMALIZE(len3); pSUM(clothItem->normals[index1], len3, clothItem->normals[index1]); clothItem->normalsCount[index1]++; pSUM(clothItem->normals[index2], len3, clothItem->normals[index2]); clothItem->normalsCount[index2]++; pSUM(clothItem->normals[index], len3, clothItem->normals[index]); clothItem->normalsCount[index]++; // Second triangle - right bottom pDIFFERENCE(clothItem->positions[index1], clothItem->positions[index3], len1); pDIFFERENCE(clothItem->positions[index2], clothItem->positions[index3], len2); CROSSPRODUCTp(len1, len2, len3); pNORMALIZE(len3); pSUM(clothItem->normals[index1], len3, clothItem->normals[index1]); clothItem->normalsCount[index1]++; pSUM(clothItem->normals[index2], len3, clothItem->normals[index2]); clothItem->normalsCount[index2]++; pSUM(clothItem->normals[index3], len3, clothItem->normals[index]); clothItem->normalsCount[index3]++; } } texture.u = 0.0; texture.v = 0.0; increment.u = 1.0 / clothItem->width; increment.v = 1.0 / clothItem->height; // Render the triangles for(int row = 0; row < clothItem->height - 1; row++) { glBindTexture(GL_TEXTURE_2D, texId); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBegin(GL_TRIANGLE_STRIP); for(int col = 0; col < clothItem->width - 1; col ++) { //index index 2 index 1 index 3 index = FindIndexInArray(row, col, clothItem->width); index1 = FindIndexInArray(row, col + 1, clothItem->width); index2 = FindIndexInArray(row + 1, col, clothItem->width); index3 = FindIndexInArray(row + 1, col + 1, clothItem->width); // CCW order for the triangle strip // left top (0,0) glNormal3f(clothItem->normals[index].x / clothItem->normalsCount[index], clothItem->normals[index].y / clothItem->normalsCount[index], clothItem->normals[index].z / clothItem->normalsCount[index]); glTexCoord2f(texture.u, texture.v); glVertex3f(clothItem->positions[index].x, clothItem->positions[index].y, clothItem->positions[index].z); // left bottom (0, 1) glNormal3f(clothItem->normals[index2].x / clothItem->normalsCount[index2], clothItem->normals[index2].y / clothItem->normalsCount[index2], clothItem->normals[index2].z / clothItem->normalsCount[index2]); glTexCoord2f(texture.u, texture.v + increment.v); glVertex3f(clothItem->positions[index2].x, clothItem->positions[index2].y, clothItem->positions[index2].z); // right top (1, 0) glNormal3f(clothItem->normals[index1].x / clothItem->normalsCount[index1], clothItem->normals[index1].y / clothItem->normalsCount[index1], clothItem->normals[index1].z / clothItem->normalsCount[index1]); glTexCoord2f(texture.u + increment.u, texture.v); glVertex3f(clothItem->positions[index1].x, clothItem->positions[index1].y, clothItem->positions[index1].z); // right bottom (1, 1) glNormal3f(clothItem->normals[index3].x / clothItem->normalsCount[index3], clothItem->normals[index3].y / clothItem->normalsCount[index3], clothItem->normals[index3].z / clothItem->normalsCount[index3]); glTexCoord2f(texture.u + increment.u, texture.v + increment.v); glVertex3f(clothItem->positions[index3].x, clothItem->positions[index3].y, clothItem->positions[index3].z); texture.u += increment.u; } texture.u = 0.0; texture.v += increment.v; glEnd(); } glEnable(GL_LIGHTING); }// if gRenderMode }// end RenderClothSystem
/* Function: modEuler * Description: Modified Euler Integrator using Implicit and Explicit * vi(t + h) = vi(t) + (ALPHA / h) * (gi(t) - xi(t)) + (h / mi) * Fext(t) * xi(t + h) = xi(t) + h * vi(t + h) * Input: None * Output: None */ void ModEuler(phyzx *phyzxObj, int mIndex, int deformMode) { point vertex, velocity, extVel, position, velDamp; point vDiff, velTotal, newPos, temp; matrix R, matTemp; memset( (void*)&temp, 0, sizeof(temp)); memset((void*)&extVel, 0, sizeof(point)); memset((void*)&velocity, 0, sizeof(point)); memset((void*)&position, 0, sizeof(point)); memset((void*)&vDiff, 0, sizeof(point)); memset((void*)&velTotal, 0, sizeof(point)); memset((void*)&newPos, 0, sizeof(point)); memset((void*)&phyzxObj->avgVel, 0, sizeof(point)); matInit(&R, 0, 0); matInit(&matTemp, 0, 0); if (deformMode == 3) quadDeformRot(&R, phyzxObj); for (unsigned int index = STARTFROM; index <= phyzxObj->model->numvertices; index++) { if (deformMode == 3) { // Compute Quadratic Deformation Goal Positions matMult(R, phyzxObj->q[index], &matTemp); // R(q) temp = matToPoint(matTemp); // Data type conversion pSUM(temp, phyzxObj->cmDeformed, phyzxObj->goal[index]); // g = R(q) + xcm } //end if else { // Compute Goal Positions matMult3331(phyzxObj->R, phyzxObj->relStableLoc[index], &temp); // R(xi0 - xcm0) pSUM(temp, phyzxObj->cmDeformed, phyzxObj->goal[index]); // g = R(xi0 - xcm0) + xcm } //end if vertex.x = phyzxObj->model->vertices[3*index]; vertex.y = phyzxObj->model->vertices[3*index + 1]; vertex.z = phyzxObj->model->vertices[3*index + 2];\ if (stickyFloor == 1) if (vertex.y <= -WALLDIST) continue; // Add user force if (mIndex == iMouseModel && lMouseVal == 2 && objectName != -1)// && index == objectName) { //point uForce; /*GLMnode *node; node = NBVStruct[objectName]; while (node->next != NULL) { pSUM(phyzxObj->extForce[node->index], userForce, phyzxObj->extForce[node->index]); node = node->next; } //end while*/ /*if (index != objectName) { point extPos = vMake(phyzxObj->model->vertices[3*objectName], phyzxObj->model->vertices[3*objectName+1], phyzxObj->model->vertices[3*objectName+2]); double dist = vecLeng(extPos, vertex); //if (dist > 0.04) //{ pMULTIPLY(userForce, (1.0/dist), uForce); pSUM(phyzxObj->extForce[index], uForce, phyzxObj->extForce[index]); //pDisp("user", userForce); //} //end if //else //{ //pSUM(phyzxObj->extForce[index], userForce, phyzxObj->extForce[index]); //} //end else } //end if else {*/ pSUM(phyzxObj->extForce[index], userForce, phyzxObj->extForce[index]); //} //end else } //end if // Explicit Euler Integrator for veloctiy -> vi(t + h) pDIFFERENCE(phyzxObj->goal[index], vertex, vDiff); // gi(t) - xi(t) pMULTIPLY(vDiff, (phyzxObj->alpha / phyzxObj->h), velocity); // vi(h) = (ALPHA / h) * (gi(t) - xi(t)) pMULTIPLY(phyzxObj->extForce[index], (phyzxObj->h / phyzxObj->mass[index]), extVel); // (h / mi) * Fext(t) // pMULTIPLY(phyzxObj->extForce[index], phyzxObj->h, extVel); // (h / mi) * Fext(t) pSUM(velocity, extVel, velTotal); // vi(h) = (ALPHA / h) * (gi(t) - xi(t)) + (h / mi) * Fext(t) pSUM(phyzxObj->velocity[index], velTotal, phyzxObj->velocity[index]); // vi(t + h) = vi(t) + vi(h) // Velocity Damping pMULTIPLY(phyzxObj->velocity[index], -phyzxObj->delta, velDamp); pSUM(phyzxObj->velocity[index], velDamp, phyzxObj->velocity[index]); // Implicity Euler Integrator for position pMULTIPLY(phyzxObj->velocity[index], phyzxObj->h, position); // xi(h) = h * vi(t + h) pSUM(vertex, position, newPos); // xi(t + h) = xi(t) + xi(h) // Store new position into data structure phyzxObj->model->vertices[3*index] = newPos.x; phyzxObj->model->vertices[3*index + 1] = newPos.y; phyzxObj->model->vertices[3*index + 2] = newPos.z; pSUM(phyzxObj->avgVel, phyzxObj->velocity[index], phyzxObj->avgVel); //if (objCollide) CheckForCollision(index, phyzxObj, mIndex); } //end for pMULTIPLY(phyzxObj->avgVel, 1.0 / phyzxObj->model->numvertices, phyzxObj->avgVel); delete[] R.data; delete[] matTemp.data; } //end ModEuler()
/* Function: cameraFreeMove * Description: Free movement camera computations. Allow camera to move * forward, backword, up, down, strafe left, strafe right, * tilt up/down and turn right/left. * Input: dir - Direction of movement * 0. Move Camera Forward * 1. Move Camera Backward * 2. Move Camera Up * 3. Move Camera Down * 4. Move Camera Right * 5. Move Camera Left * 6. Tilt Camera Up (Not Implemented) * 7. Tilt Camera Down (Not Implemented) * 8. Turn Camera Right (Not Implemented) * 9. Turn Camera Left (Not Implemented) * Output: None */ void cameraFreeMove(int dir) { point mouse, vec, pVec, cVec, cPos; double ang, length; pDIFFERENCE(lineOfSight, cameraPos, vec); pNORMALIZE(vec); if (dir == 0) // Move Camera Forward { pMULTIPLY(vec, CAMSPEED, vec); pSUM(cameraPos, vec, cameraPos); pSUM(lineOfSight, vec, lineOfSight); } //end if else if (dir == 1) // Move Camera Backward { pMULTIPLY(vec, CAMSPEED, vec); pDIFFERENCE(cameraPos, vec, cameraPos); pDIFFERENCE(lineOfSight, vec, lineOfSight); } //end else else if (dir == 2) // Move Camera Up { ang = Phi + CAMROT; cPos.x = lineOfSight.x + (R * cos(ang) * cos(Theta)); cPos.y = lineOfSight.y + (R * sin(Theta)); cPos.z = lineOfSight.z + (-R * sin(ang) * cos(Theta)); pDIFFERENCE(cPos, cameraPos, pVec); pNORMALIZE(pVec); CROSSPRODUCTp(pVec, vec, cVec); pMULTIPLY(cVec, CAMSPEED, cVec); pSUM(cameraPos, cVec, cameraPos); pSUM(lineOfSight, cVec, lineOfSight); } //end else else if (dir == 3) // Move Camera Down { ang = Phi + CAMROT; cPos.x = lineOfSight.x + (R * cos(ang) * cos(Theta)); cPos.y = lineOfSight.y + (R * sin(Theta)); cPos.z = lineOfSight.z + (-R * sin(ang) * cos(Theta)); pDIFFERENCE(cPos, cameraPos, pVec); pNORMALIZE(pVec); CROSSPRODUCTp(pVec, vec, cVec); pMULTIPLY(cVec, CAMSPEED, cVec); pDIFFERENCE(cameraPos, cVec, cameraPos); pDIFFERENCE(lineOfSight, cVec, lineOfSight); } //end else else if (dir == 4) // Move Camera Strafe Right { ang = Theta + CAMROT; cPos.x = lineOfSight.x + (R * cos(Phi) * cos(ang)); cPos.y = lineOfSight.y + (R * sin(ang)); cPos.z = lineOfSight.z + (-R * sin(Phi) * cos(ang)); pDIFFERENCE(cPos, cameraPos, pVec); pNORMALIZE(pVec); CROSSPRODUCTp(vec, pVec, cVec); pMULTIPLY(cVec, CAMSPEED, cVec); pSUM(cameraPos, cVec, cameraPos); pSUM(lineOfSight, cVec, lineOfSight); } //end else else if (dir == 5) // Move Camera Strafe Left { ang = Theta + CAMROT; cPos.x = lineOfSight.x + (R * cos(Phi) * cos(ang)); cPos.y = lineOfSight.y + (R * sin(ang)); cPos.z = lineOfSight.z + (-R * sin(Phi) * cos(ang)); pDIFFERENCE(cPos, cameraPos, pVec); pNORMALIZE(pVec); CROSSPRODUCTp(vec, pVec, cVec); pMULTIPLY(cVec, CAMSPEED, cVec); pDIFFERENCE(cameraPos, cVec, cameraPos); pDIFFERENCE(lineOfSight, cVec, lineOfSight); } //end else } //end cameraFreeMove