void Particle::avoidWalls(float d) { ofPoint desired; desired.set(0, 0); if (pos.x < d) { desired.set(maxSpeed, vel.y); } else if (pos.x > ofGetWidth()-d) { desired.set(-maxSpeed, vel.y); } if (pos.y < d) { desired.set(vel.x, maxSpeed); } else if (pos.y > ofGetHeight()-d) { desired.set(vel.x, -maxSpeed); } if (desired.length() != 0.0) { desired.normalize(); desired *= maxSpeed; ofPoint steer = desired - vel; steer.limit(maxForce); //applyForce(steer); addForce(steer); } }
void Agent::seek(ofVec3f oTarget) { //From Roxlu's Boids code ( www.roxlu.com ) // This is how it works. // 1. We calculate the change in position which would bring // use directly to the target. This is "desired_vel". Though we don't // want to jump directly to this target, but slowly move to it. ofVec3f desiredVelocity = oTarget - position; // 2. Therefore we want to move to this position at the maximum // allowed speed. We do this by normalizing the vector and then // multiplying it with the maximum allowed speed. This is exactly // what ofxVec3f.scale() does. desiredVelocity.scale(maxVelocity); // 3. Now we have the maximum desired velocity at the maximum speed. // Though we need to adjust this speed as we want to go into that direction // at the best we are allowed, which is the remaining velocity. desiredVelocity -= velocity; addForce(desiredVelocity); //cout << "Desired vel: " << desired_vel.x << ", " << desired_vel.y << endl; }
//------------------------------------------------------------ void Particle::addCounterClockwiseForce(Particle *p, float radius, float scale){ // ----------- (1) make a vector of where this Particle p is: ofPoint posOfForce; posOfForce.set(*p); // ----------- (2) calculate the difference & length ofPoint diff = (*this) - posOfForce; float length = diff.length(); // ----------- (3) check close enough bool bAmCloseEnough = true; if (radius > 0){ if (length > radius){ bAmCloseEnough = false; } } // ----------- (4) if so, update force if (bAmCloseEnough == true){ float pct = 1 - (length / radius); // stronger on the inside diff.normalize(); addForce(ofPoint(diff.y * scale * pct, diff.x * scale * pct * -1)); p->addForce(ofPoint(diff.y * scale * pct * -1, diff.x * scale * pct)); } }
void ActorDynamic::update(float f_timeStepInterval){ if (bUpdated){ bActive = true; Actor::update(f_timeStepInterval); } if (bActive){ vShapes[0]->setColour(glm::vec4(0,1,0,0.5f)); vShapes[1]->setColour(glm::vec4(0,1,0,0.5f)); float g = 0.0f; if (parentScene != nullptr){ g = parentScene->getGravity(); if (g != 0.0f){ addForce(glm::vec3(0,g * fMass * f_timeStepInterval,0)); bActive = true; } } if (abs(v3Velocity.x) < 0.1f && abs(v3Velocity.y) == 0.0f && abs(v3Velocity.z) < 0.1f ){ v3Velocity = glm::vec3(0.0f); bActive = false; } else { glm::vec3 OldPos = v3Translate; v3Velocity *= glm::vec3(1.0f); addTranslate(v3Velocity * f_timeStepInterval); ((Line*)vShapes[1])->setDirection(OldPos - v3Translate); ((Line*)vShapes[1])->setDistance(glm::distance(OldPos,v3Translate)); } }else{ vShapes[0]->setColour(glm::vec4(1,0,0,0.5f)); vShapes[1]->setColour(glm::vec4(1,0,0,0.5f)); } }
void Particle::seek( ofPoint dest ) { float maxSpeed = 10.0; float maxForce = 0.4; float slowDownRadius = 200.0; ofPoint desired = dest - pos; if( desired.length() < slowDownRadius ){ float newMag = ofMap( desired.length(), 0, slowDownRadius, 0, maxSpeed); desired.normalize(); desired *= newMag; }else{ desired.normalize(); desired *= maxSpeed; } ofPoint steer = desired - vel; steer.limit( maxForce ); addForce( steer ); }
void Particle::addAttraction(ofPoint _pos, float _rad, float _scale){ ofPoint diff = _pos - pos; if( diff.length() < _rad ){ diff *= 1.0-diff.length()/_rad; addForce(diff*_scale); } }
void Particle::addRepulsionForce( const ofVec2f &fromPos ){ ofVec2f diff = pos - fromPos; float strength = 1- (diff.length() / 200.0); addForce( diff.normalized() * (strength) ); }
/** * Arrive makes the boid slow down when it moves towards its targets. The closer * it gets the slower it will move. The boid only slows down when it is withing a * certain distance of the target. */ void Boid::arrive(ofxVec3f oTarget) { ofxVec3f desired_vel = oTarget - pos; float dist = desired_vel.length(); desired_vel.normalize(); //ofSetColor(0xFF0000); //ofCircle(oTarget.x, oTarget.y, 4); // When we are within the arrive distance, we switch to slow-down mode. if (dist <= arrive_dist) { desired_vel *= ((max_vel * dist / arrive_dist)); ofSetColor(0x00); } // else we continue our journey they same we did when we were seeking else { desired_vel *= max_vel; } // We add a little margin here; // w/o the boid will oversh0ot its target. if (dist > 10) { desired_vel -= vel; addForce(desired_vel); } // When were are within the margin, stop moving. else{ force = 0; vel = 0; } }
void LinearSpring::addFDK(const OdeState& state, Vector* F, Matrix* D, Matrix* K) { Matrix33d De, Ke; // Assembly stage in F. Note that the force calculation does not rely on any matrices. addForce(state, F); // The spring has 2 nodes with positions {x1, x2}, velocities {v1, v2} and force {F1, F2=-F1} // Also note from addForce that the positions and velocities play a symmetric role in the force calculation // i.e. dFi/dx1 = -dFi/dx2 and dFi/dv1 = -dFi/dv2 // The stiffness matrix is K = -dF/dx = (-dF1/dx1 -dF1/dx2) = (-dF1/dx1 dF1/dx1) // (-dF2/dx1 -dF2/dx2) ( dF1/dx1 -dF1/dx1) // The damping matrix is D = -dF/dv = (-dF1/dv1 -dF1/dv2) = (-dF1/dv1 dF1/dv1) // (-dF2/dv1 -dF2/dv2) ( dF1/dv1 -dF1/dv1) // Let's compute De = -dF1/dv1 and Ke = -dF1/dx1 if (!computeDampingAndStiffness(state, &De, &Ke)) { return; } // Assembly stage in K K->block<3, 3>(3 * m_nodeIds[0], 3 * m_nodeIds[0]) += Ke; // -dF1/dx1 = Ke K->block<3, 3>(3 * m_nodeIds[0], 3 * m_nodeIds[1]) -= Ke; // -dF1/dx2 =-Ke K->block<3, 3>(3 * m_nodeIds[1], 3 * m_nodeIds[0]) -= Ke; // -dF2/dx1 =-Ke K->block<3, 3>(3 * m_nodeIds[1], 3 * m_nodeIds[1]) += Ke; // -dF2/dx2 = Ke // Assembly stage in D D->block<3, 3>(3 * m_nodeIds[0], 3 * m_nodeIds[0]) += De; // -dF1/dv1 = De D->block<3, 3>(3 * m_nodeIds[0], 3 * m_nodeIds[1]) -= De; // -dF1/dv2 =-De D->block<3, 3>(3 * m_nodeIds[1], 3 * m_nodeIds[0]) -= De; // -dF2/dv1 =-De D->block<3, 3>(3 * m_nodeIds[1], 3 * m_nodeIds[1]) += De; // -dF2/dv2 = De }
void Particle::addRepulsionForce(ofPoint _pos, float _rad, float _scale){ ofPoint diff = _pos - pos; if( diff.length() < _rad ){ diff *= 1.0-diff.length()/_rad;// PRO way addForce(-diff*_scale); } }
ofxBox& ofxBox::setOrientation(string _orientation){ if (_orientation != orientation) { orientation = _orientation; if (body != NULL){ vel = getVelocity(); addForce(ofVec2f(vel.x*-1,0), 15); } } return * this; };
static void updateForces(int firstStar, int secondStar, struct star* star_array) { if (firstStar > 0){ if (secondStar > 1){ addForce(&star_array[firstStar],&star_array[secondStar]); updateForces(firstStar, secondStar - 1, star_array); }else{ updateForces(firstStar - 1, firstStar - 2, star_array); } } }
void Particle::applyFlockingForce(ofPoint * _offset, float _neighbordhood, float _independece, float _scale){ addForce( ofVec3f(ofSignedNoise(pos.x / _neighbordhood + _offset->x + localOffset.x * _independece, pos.y / _neighbordhood, pos.z / _neighbordhood), ofSignedNoise(pos.x / _neighbordhood, pos.y / _neighbordhood + _offset->y + localOffset.y * _independece, pos.z / _neighbordhood), ofSignedNoise( pos.x / _neighbordhood, pos.y / _neighbordhood, pos.z / _neighbordhood + _offset->z + localOffset.z * _independece)) * _scale ); }
void getForce(int currentPtc) { getInternalForce(currentPtc); //getCollisionForce(currentPtc); M3DVector3f gravity = {0.0f, -ClothLnk[currentPtc].Mass, 0.0f}; m3dScaleVector3(gravity, 0.2f); addForce(currentPtc, gravity); m3dScaleVector3(ClothLnk[currentPtc].force, DampCoefficient); //if (currentPtc==55) // printf("[%d].force {%.1f, %.1f, %.1f} \n", currentPtc, ClothLnk[currentPtc].force[0], ClothLnk[currentPtc].force[1], ClothLnk[currentPtc].force[2]); }
void ComponentSteering::onMessage(const Message& message) { switch (message.type) { case Message::NEW_TARGET: changeTarget(message.target); break; case Message::NEW_FORCE: addForce(message.target); break; } }
////////////////////////////////////////////////////////////////////// // step simulation once ////////////////////////////////////////////////////////////////////// void FLUID_3D::step() { // addSmokeTestCase(_density, _res); // addSmokeTestCase(_heat, _res); wipeBoundaries(); // run the solvers addVorticity(); addBuoyancy(_heat, _density); addForce(); project(); diffuseHeat(); // advect everything advectMacCormack(); // if(_wTurbulence) { // _wTurbulence->stepTurbulenceFull(_dt/_dx, // _xVelocity, _yVelocity, _zVelocity, _obstacles); // _wTurbulence->stepTurbulenceReadable(_dt/_dx, // _xVelocity, _yVelocity, _zVelocity, _obstacles); // } /* // no file output float *src = _density; string prefix = string("./original.preview/density_fullxy_"); writeImageSliceXY(src,_res, _res[2]/2, prefix, _totalSteps); */ // artificial damping -- this is necessary because we use a // collated grid, and at very coarse grid resolutions, banding // artifacts can occur artificialDamping(_xVelocity); artificialDamping(_yVelocity); artificialDamping(_zVelocity); /* // no file output string pbrtPrefix = string("./pbrt/density_small_"); IMAGE::dumpPBRT(_totalSteps, pbrtPrefix, _density, _res[0],_res[1],_res[2]); */ _totalTime += _dt; _totalSteps++; // todo xxx dg: only clear obstacles, not boundaries // memset(_obstacles, 0, sizeof(unsigned char)*_xRes*_yRes*_zRes); // wipe forces // for external forces we can't do it at the beginning of this function but at the end for (int i = 0; i < _totalCells; i++) { _xForce[i] = _yForce[i] = _zForce[i] = 0.0f; } }
void Body::addGlobalForce( Ogre::Vector3& force, Ogre::Vector3& pos ) { Ogre::Vector3 bodypos; Ogre::Quaternion bodyorient; getPositionOrientation( bodyorient, bodypos ); Ogre::Vector3 topoint = pos - bodypos; Ogre::Vector3 torque = topoint.crossProduct( force ); addForce( force ); addTorque( torque ); }
//---------------------------------------------------------------------------- void RigidBody::setEnabled(const bool enabled) { SimComponent().setEnabled(enabled); if(mPhysShape) mPhysShape->setEnable(enabled); // When enabling add a tiniest force, to // prevent body from flying motionless in the air. if(enabled) { addForce(VectorF(0.0001f, 0.0001f, 0.0001f)); } }
void init() { glewExperimental = GL_TRUE; GLenum err = glewInit(); if (GLEW_OK != err) { std::cerr << "Error: " << glewGetErrorString(err) << std::endl; } else { if (GLEW_VERSION_3_3) { std::cout << "Driver supports OpenGL 3.3\nDetails:" << std::endl; std::cout << "Using GLEW " << glewGetString(GLEW_VERSION) << std::endl; std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl; std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl; std::cout << "Version: " << glGetString(GL_VERSION) << std::endl; std::cout << "GLSL: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; } } // FIXME: GLEW Init causes "Invalid enumerant" OpenGL error! // Supressing it now as the pipeline seems working. GLenum error = glGetError(); if (GL_NO_ERROR != error) { // std::cout << "Error: " << gluErrorString(error) << std::endl; } fullscreenQuad = new Quad(); simpleShader = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/simple.frag"); gaussShader = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/gauss.frag"); gaussShaderH = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/gaussH.frag"); gaussShaderV = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/gaussV.frag"); WE_addForce = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/addForce.frag"); WE_iteration_1 = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/iteration.frag"); WE_iteration_2 = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/iteration2.frag"); WE_iteration_3 = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/iteration3.frag"); WE_visualize = new Shader("../src/lab3/shaders/passthrough.vert", "../src/lab3/shaders/visualize.frag"); texture = new Texture2D(); texture->loadFromFile(std::string("../img/lena.jpg")); if (1 == example) { glutReshapeWindow(texture->getWidth(), texture->getHeight()); } computeBuffer[0] = new Framebuffer(texture->getWidth(), texture->getHeight(), 1); computeBuffer[1] = new Framebuffer(texture->getWidth(), texture->getHeight(), 1); WE_computeBuffer[0] = new Framebuffer(600, 600, 1); WE_computeBuffer[1] = new Framebuffer(600, 600, 1); resetWave(); addForce(300, 300); }
//Collide with an outside object (generally the player's location) void Spring :: collide(const vec2 & heroLoc, float collideDist ){ if(dist(heroLoc, global) < collideDist){ vec2 d = heroLoc - global; float angle = atan2(d.y, d.x); vec2 target = vec2(heroLoc.x - cos(angle) * collideDist, heroLoc.y - sin(angle) * collideDist); vec2 force = (target - global) * stiffness * 3.0f; addForce( force ); global = target; springContact = true; //allows parent to see if spring has been contacted } else { springContact = false; } }
void GravityForceGenerator::update(floatType timeDelta_ms) { //iterate over the list of collision components for (auto collisionComponent : this->getRegisteredComponents()) { auto physicsComponent = collisionComponent->getPhysicsRelation(); if (physicsComponent == nullptr) { continue; } //don't calculate if it doesn't have a finite mass const floatType inverseMass = physicsComponent->getInverseMass(); if (inverseMass <= 0) { continue; } physicsComponent->addForce(this->gravity * inverseMass); } }
void Particle::seek( const ofVec2f &dest ) { ofVec2f desired = dest - pos; if( desired.length() < slowDownRadius ){ float newMag = ofMap( desired.length(), 0, slowDownRadius, 0, maxSpeed); desired.normalize(); desired *= newMag; }else{ desired.normalize(); desired *= maxSpeed; } ofVec2f steer = desired - vel; steer.limit( maxForce ); addForce( steer ); }
void Particle::addRepulsion(ofPoint _pos, float _rad, float _scale){ // // if is inside the radius // if( pos.distance(_pos) < _rad ){ // // - calculate de difference // ofPoint diff = pos - _pos; // // // - add like a opposite force // addForce(-diff); // } ofPoint diff = _pos - pos; if( diff.length() < _rad ){ // diff *= ofMap(diff.length(),0,_rad,1.0,0.0); // Easy way diff *= 1.0-diff.length()/_rad;// PRO way addForce(-diff*_scale); } }
void PlinkParticles::init() { sprite.loadImage("feather_sprite.png"); sprite.resize(30,30); emitSize = 1; addForce(ofVec3f(1.02,1.005,1)); emitterPosition = ofVec3f(0,0,0); for(int i = 0; i < emitSize; i ++) { PlinkSimple particle; particle.init(sprite,forces, emitterPosition, target); particles.push_back(particle); } emit(); }
void boid::arrive(ofxVec3f oTarget) { ofxVec3f desired_vel = oTarget - pos; float dist = desired_vel.length(); desired_vel.normalize(); if (dist <= arrive_dist) { desired_vel *= ((max_vel * dist / arrive_dist)); ofSetColor(0x00); } else { desired_vel *= max_vel; } if (dist > 10) { desired_vel -= vel; addForce(desired_vel); } else { force = 0; vel = 0; } }
/*! Convenience function to apply force and torque from one force at contact point. Not sure if this is the right place for it. */ void applyForceAtContactPoint(const Vector3r& force, const Vector3r& contactPoint, const Body::id_t id1, const Vector3r& pos1, const Body::id_t id2, const Vector3r& pos2){ addForce(id1, force,scene); addTorque(id1, (contactPoint-pos1).cross(force),scene); addForce(id2,-force,scene); addTorque(id2,-(contactPoint-pos2).cross(force),scene); }
void ofxParticle::addForce(ofVec2f f) { addForce(f.x,f.y); }
void Boid::applyForce( ofVec2f force ){ acc += force; addForce(force, 1.0); }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool PartEmitter::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // SetBorder ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "SetBorder") == 0) { stack->correctParams(4); int borderX = stack->pop()->getInt(); int borderY = stack->pop()->getInt(); int borderWidth = stack->pop()->getInt(); int borderHeight = stack->pop()->getInt(); stack->pushBool(DID_SUCCEED(setBorder(borderX, borderY, borderWidth, borderHeight))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetBorderThickness ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetBorderThickness") == 0) { stack->correctParams(4); int left = stack->pop()->getInt(); int right = stack->pop()->getInt(); int top = stack->pop()->getInt(); int bottom = stack->pop()->getInt(); stack->pushBool(DID_SUCCEED(setBorderThickness(left, right, top, bottom))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AddSprite ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "AddSprite") == 0) { stack->correctParams(1); const char *spriteFile = stack->pop()->getString(); stack->pushBool(DID_SUCCEED(addSprite(spriteFile))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemoveSprite ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "RemoveSprite") == 0) { stack->correctParams(1); const char *spriteFile = stack->pop()->getString(); stack->pushBool(DID_SUCCEED(removeSprite(spriteFile))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Start ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Start") == 0) { stack->correctParams(1); _overheadTime = stack->pop()->getInt(); stack->pushBool(DID_SUCCEED(start())); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Stop ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Stop") == 0) { stack->correctParams(0); for (uint32 i = 0; i < _particles.size(); i++) { delete _particles[i]; } _particles.clear(); _running = false; stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Pause ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Pause") == 0) { stack->correctParams(0); _running = false; stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Resume ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Resume") == 0) { stack->correctParams(0); _running = true; stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AddGlobalForce ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "AddGlobalForce") == 0) { stack->correctParams(3); const char *forceName = stack->pop()->getString(); float angle = stack->pop()->getFloat(); float strength = stack->pop()->getFloat(); stack->pushBool(DID_SUCCEED(addForce(forceName, PartForce::FORCE_GLOBAL, 0, 0, angle, strength))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AddPointForce ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "AddPointForce") == 0) { stack->correctParams(5); const char *forceName = stack->pop()->getString(); int posX = stack->pop()->getInt(); int posY = stack->pop()->getInt(); float angle = stack->pop()->getFloat(); float strength = stack->pop()->getFloat(); stack->pushBool(DID_SUCCEED(addForce(forceName, PartForce::FORCE_GLOBAL, posX, posY, angle, strength))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemoveForce ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "RemoveForce") == 0) { stack->correctParams(1); const char *forceName = stack->pop()->getString(); stack->pushBool(DID_SUCCEED(removeForce(forceName))); return STATUS_OK; } else { return BaseObject::scCallMethod(script, stack, thisStack, name); } }
/* Law2_ScGeom_ViscElPhys_Basic */ void Law2_ScGeom_ViscElPhys_Basic::go(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I){ const ScGeom& geom=*static_cast<ScGeom*>(_geom.get()); ViscElPhys& phys=*static_cast<ViscElPhys*>(_phys.get()); const int id1 = I->getId1(); const int id2 = I->getId2(); if (geom.penetrationDepth<0) { if (phys.liqBridgeCreated and -geom.penetrationDepth<phys.sCrit and phys.Capillar) { phys.normalForce = -calculateCapillarForce(geom, phys)*geom.normal; if (I->isActive) { addForce (id1,-phys.normalForce,scene); addForce (id2, phys.normalForce,scene); }; return; } else { scene->interactions->requestErase(I); return; }; }; const BodyContainer& bodies = *scene->bodies; const State& de1 = *static_cast<State*>(bodies[id1]->state.get()); const State& de2 = *static_cast<State*>(bodies[id2]->state.get()); /* * This part for implementation of the capillar model. * All main equations are in calculateCapillarForce function. * There is only the determination of critical distance between spheres, * after that the liquid bridge will be broken. */ if (not(phys.liqBridgeCreated) and phys.Capillar) { phys.liqBridgeCreated = true; Sphere* s1=dynamic_cast<Sphere*>(bodies[id1]->shape.get()); Sphere* s2=dynamic_cast<Sphere*>(bodies[id2]->shape.get()); if (s1 and s2) { phys.R = 2 * s1->radius * s2->radius / (s1->radius + s2->radius); } else if (s1 and not(s2)) { phys.R = s1->radius; } else { phys.R = s2->radius; } const Real Vstar = phys.Vb/(phys.R*phys.R*phys.R); const Real Sstar = (1+0.5*phys.theta)*(pow(Vstar,1/3.0) + 0.1*pow(Vstar,2.0/3.0)); // [Willett2000], equation (15), use the full-length e.g 2*Sc phys.sCrit = Sstar*phys.R; } Vector3r& shearForce = phys.shearForce; if (I->isFresh(scene)) shearForce=Vector3r(0,0,0); const Real& dt = scene->dt; shearForce = geom.rotate(shearForce); // Handle periodicity. const Vector3r shift2 = scene->isPeriodic ? scene->cell->intrShiftPos(I->cellDist): Vector3r::Zero(); const Vector3r shiftVel = scene->isPeriodic ? scene->cell->intrShiftVel(I->cellDist): Vector3r::Zero(); const Vector3r c1x = (geom.contactPoint - de1.pos); const Vector3r c2x = (geom.contactPoint - de2.pos - shift2); const Vector3r relativeVelocity = (de1.vel+de1.angVel.cross(c1x)) - (de2.vel+de2.angVel.cross(c2x)) + shiftVel; const Real normalVelocity = geom.normal.dot(relativeVelocity); const Vector3r shearVelocity = relativeVelocity-normalVelocity*geom.normal; // As Chiara Modenese suggest, we store the elastic part // and then add the viscous part if we pass the Mohr-Coulomb criterion. // See http://www.mail-archive.com/[email protected]/msg01391.html shearForce += phys.ks*dt*shearVelocity; // the elastic shear force have a history, but Vector3r shearForceVisc = Vector3r::Zero(); // the viscous shear damping haven't a history because it is a function of the instant velocity // Prevent appearing of attraction forces due to a viscous component // [Radjai2011], page 3, equation [1.7] // [Schwager2007] const Real normForceReal = phys.kn * geom.penetrationDepth + phys.cn * normalVelocity; if (normForceReal < 0) { phys.normalForce = Vector3r::Zero(); } else { phys.normalForce = normForceReal * geom.normal; } Vector3r momentResistance = Vector3r::Zero(); if (phys.mR>0.0) { const Vector3r relAngVel = de1.angVel - de2.angVel; relAngVel.normalized(); if (phys.mRtype == 1) { momentResistance = -phys.mR*phys.normalForce.norm()*relAngVel; // [Zhou1999536], equation (3) } else if (phys.mRtype == 2) { momentResistance = -phys.mR*(c1x.cross(de1.angVel) - c2x.cross(de2.angVel)).norm()*phys.normalForce.norm()*relAngVel; // [Zhou1999536], equation (4) } } const Real maxFs = phys.normalForce.squaredNorm() * std::pow(phys.tangensOfFrictionAngle,2); if( shearForce.squaredNorm() > maxFs ) { // Then Mohr-Coulomb is violated (so, we slip), // we have the max value of the shear force, so // we consider only friction damping. const Real ratio = sqrt(maxFs) / shearForce.norm(); shearForce *= ratio; } else { // Then no slip occurs we consider friction damping + viscous damping. shearForceVisc = phys.cs*shearVelocity; } if (I->isActive) { const Vector3r f = phys.normalForce + shearForce + shearForceVisc; addForce (id1,-f,scene); addForce (id2, f,scene); addTorque(id1,-c1x.cross(f)+momentResistance,scene); addTorque(id2, c2x.cross(f)-momentResistance,scene); } }