void MassSpring1DRepresentation::init1D( const std::vector<Vector3d> nodes, std::vector<size_t> nodeBoundaryConditions, double totalMass, double stiffnessStretching, double dampingStretching, double stiffnessBending, double dampingBending) { std::shared_ptr<SurgSim::Math::OdeState> state; state = std::make_shared<SurgSim::Math::OdeState>(); state->setNumDof(getNumDofPerNode(), nodes.size()); SURGSIM_ASSERT(nodes.size() > 0) << "Number of nodes incorrect: " << nodes.size(); // Initialize the nodes position, velocity and mass // Note: no need to apply the initialPose here, initialize will take care of it ! for (size_t massId = 0; massId < nodes.size(); massId++) { addMass(std::make_shared<Mass>(totalMass / static_cast<double>(nodes.size()))); SurgSim::Math::setSubVector(nodes[massId], massId, 3, &state->getPositions()); } // Initialize the stretching springs if (stiffnessStretching || dampingStretching) { for (size_t massId = 0; massId < nodes.size() - 1; massId++) { addSpring(createLinearSpring(state, massId, massId + 1, stiffnessStretching, dampingStretching)); } } // Initialize the bending springs if (stiffnessBending || dampingBending) { for (size_t massId = 0; massId < nodes.size() - 2; massId++) { addSpring(createLinearSpring(state, massId, massId + 2, stiffnessBending, dampingBending)); } } // Sets the boundary conditions for (auto boundaryCondition = std::begin(nodeBoundaryConditions); boundaryCondition != std::end(nodeBoundaryConditions); boundaryCondition++) { state->addBoundaryCondition(*boundaryCondition); } // setInitialState: Initialize all the states + apply initialPose if any setInitialState(state); }
void form::update() { // we need to get an actually even tesselation! float edgeres = 0.25; vector <ofPolyline> rawpolys = mMasterCurve->getPath()->getOutline(); ofPath path; ofPolyline master = mMasterCurve->getBasePoly().getResampledByCount(mMasterCurve->getBasePoly().getPerimeter()/(mMaxEdgeLen*edgeres)); vector<ofVec3f> mvs = master.getVertices(); for (auto v : mvs) { path.lineTo(v); } ofPolyline slave = mSlaveCurve->getBasePoly().getResampledByCount(mSlaveCurve->getBasePoly().getPerimeter()/(mMaxEdgeLen*edgeres)); vector<ofVec3f> svs = slave.getVertices(); for (auto v : svs) { path.lineTo(v); } path.close(); for (int i=1;i<rawpolys.size();i++) { ofPolyline p = rawpolys[i]; float len = p.getPerimeter(); int segs = ceil(len/(mMaxEdgeLen*edgeres)); if (segs % 2 == 0) segs++; ofPolyline resamp = p.getResampledByCount(segs); vector<ofPoint> vs = resamp.getVertices(); path.moveTo(vs[0]); for (auto v : vs) { path.lineTo(v); } path.close(); } path.setCurveResolution(1); mRawMesh = path.getTessellation(); mRawMesh.enableIndices(); mMesh.enableIndices(); // clear existing mVerts.clear(); mRawFaces.clear(); mFaces.clear(); // fill out with current state mVerts = mRawMesh.getVertices(); vector <ofIndexType> raw_inds = mRawMesh.getIndices(); for (int i=0; i<raw_inds.size(); i += 3) { mRawFaces.push_back(face(raw_inds[i],raw_inds[i+1],raw_inds[i+2])); } // subdivide for (auto f : mRawFaces) { trySubdivide(f); } // make new mesh mMesh.clear(); mMesh.enableIndices(); mMesh.enableNormals(); mMesh.addVertices(mVerts); mMesh.setMode(OF_PRIMITIVE_TRIANGLES); for (auto f : mFaces) { mMesh.addTriangle(f.a, f.b, f.c); } mOuterMesh.clear(); mOuterMesh.enableIndices(); mOuterMesh.enableNormals(); mOuterMesh.addVertices(mVerts); mOuterMesh.setMode(OF_PRIMITIVE_TRIANGLES); for (auto f : mFaces) { mOuterMesh.addTriangle(f.a, f.b, f.c); } //mMesh = mRawMesh; for(auto p : mSprings) p->release(); mSprings.clear(); for(auto p : mParticles) p->release(); mParticles.clear(); for(auto p : mMasterEdgeParticles) delete p; mMasterEdgeParticles.clear(); for(auto p : mSlaveEdgeParticles) delete p; mSlaveEdgeParticles.clear(); for(auto p : mZipperSprings) p->release(); mZipperSprings.clear(); for(auto p : mBottomSprings) p->release(); mBottomSprings.clear(); for(auto p : mBottomParticles) p->release(); mBottomParticles.clear(); for(auto p : mMiddleSprings) p->release(); mMiddleSprings.clear(); mWorld.clear(); float thickness = 10; int ind = 0; for (auto v : mVerts) { msa::physics::Particle3D *p = new msa::physics::Particle3D(v,1,0.01); // pos, mass, diam setIndex(p,master,slave,ind); mParticles.push_back(p); mWorld.addParticle(p); msa::physics::Particle3D *bp = new msa::physics::Particle3D(v+ofVec3f(0,0,thickness),1,0.01); // pos, mass, diam mBottomParticles.push_back(bp); mWorld.addParticle(bp); ind++; } float strength = 0.99; for (auto f : mFaces) { if (unmade(mParticles[f.a],mParticles[f.b])) { float alen = mParticles[f.a]->getPosition().distance(mParticles[f.b]->getPosition()); mSprings.push_back(addSpring(mParticles[f.a],mParticles[f.b],strength,alen)); mBottomSprings.push_back(addSpring(mBottomParticles[f.a],mBottomParticles[f.b],strength,alen)); // add the four middle springs mMiddleSprings.push_back(addSpring(mParticles[f.a],mBottomParticles[f.a],strength,thickness)); //mMiddleSprings.push_back(addSpring(mParticles[f.b],mBottomParticles[f.b],strength,thickness)); float crosslen = mParticles[f.a]->getPosition().distance(mBottomParticles[f.b]->getPosition()); mMiddleSprings.push_back(addSpring(mParticles[f.a],mBottomParticles[f.b],strength,crosslen)); mMiddleSprings.push_back(addSpring(mParticles[f.b],mBottomParticles[f.a],strength,crosslen)); } if (unmade(mParticles[f.b],mParticles[f.c])) { float blen = mParticles[f.b]->getPosition().distance(mParticles[f.c]->getPosition()); mSprings.push_back(addSpring(mParticles[f.b],mParticles[f.c],strength,blen)); mBottomSprings.push_back(addSpring(mBottomParticles[f.b],mBottomParticles[f.c],strength,blen)); // add the four middle springs mMiddleSprings.push_back(addSpring(mParticles[f.b],mBottomParticles[f.b],strength,thickness)); //mMiddleSprings.push_back(addSpring(mParticles[f.c],mBottomParticles[f.c],strength,thickness)); float crosslen = mParticles[f.b]->getPosition().distance(mBottomParticles[f.c]->getPosition()); mMiddleSprings.push_back(addSpring(mParticles[f.b],mBottomParticles[f.c],strength,crosslen)); mMiddleSprings.push_back(addSpring(mParticles[f.c],mBottomParticles[f.b],strength,crosslen)); } if (unmade(mParticles[f.c],mParticles[f.a])) { float clen = mParticles[f.c]->getPosition().distance(mParticles[f.a]->getPosition()); mSprings.push_back(addSpring(mParticles[f.c],mParticles[f.a],strength,clen)); mBottomSprings.push_back(addSpring(mBottomParticles[f.c],mBottomParticles[f.a],strength,clen)); // add the four middle springs mMiddleSprings.push_back(addSpring(mParticles[f.c],mBottomParticles[f.c],strength,thickness)); //mMiddleSprings.push_back(addSpring(mParticles[f.a],mBottomParticles[f.a],strength,thickness)); float crosslen = mParticles[f.c]->getPosition().distance(mBottomParticles[f.a]->getPosition()); mMiddleSprings.push_back(addSpring(mParticles[f.c],mBottomParticles[f.a],strength,crosslen)); mMiddleSprings.push_back(addSpring(mParticles[f.a],mBottomParticles[f.c],strength,crosslen)); } } orderEdge(); mMasterEdgeParticles[0]->part->makeFixed(); mSlaveEdgeParticles[0]->part->makeFixed(); // modify all vertices to be partially rotated into place ofVec3f pivot = mMasterEdgeParticles[0]->part->getPosition(); ofVec3f axis = pivot-mSlaveEdgeParticles[0]->part->getPosition(); axis.normalize(); for (int i=0; i<mParticles.size();i++) { msa::physics::Particle3D *p = mParticles[i]; msa::physics::Particle3D *bp = mBottomParticles[i]; int sign = 1; if (mMasterCurve->getBasePoly().inside(p->getPosition()) || isIn(p,mMasterEdgeParticles)) { sign = -1; } ofVec3f pos = p->getPosition(); pos.rotate(45*sign, pivot, axis); p->moveTo(pos); pos = bp->getPosition(); pos.rotate(45*sign, pivot, axis); bp->moveTo(pos); } for (int i=0; i<mParticles.size();i++) { mMesh.setVertex(i, mParticles[i]->getPosition()); } for (int i=0;i<mMasterEdgeParticles.size();i++) { msa::physics::Particle3D *pm = mMasterEdgeParticles[i]->part; int sind = (1.0-(float)(i)/(float)(mMasterEdgeParticles.size()-1))*(mSlaveEdgeParticles.size()-1); msa::physics::Particle3D *sm = mSlaveEdgeParticles[sind]->part; if (sm->getPosition().distance(pm->getPosition()) > mTol) { pm->retain(); sm->retain(); msa::physics::Spring3D *spring = new msa::physics::Spring3D(pm,sm,strength*0.25,0.0); mZipperSprings.push_back(spring); } } /*msa::physics::Particle3D *stabalizer = new msa::physics::Particle3D(mMesh.getCentroid(),1,1); mWorld.addParticle(stabalizer); for (auto p : mParticles) { mWorld.makeSpring(stabalizer, p, strength*0.1, stabalizer->getPosition().distance(p->getPosition())); }*/ mAtZip = 0; printf("made a mesh with %d vertices and %d faces",mVerts.size(),mFaces.size()); }
void OpenCloth::build( std::shared_ptr<ciri::IGraphicsDevice> device ) { if( _built ) { return; } _device = device; // gpu resources can fail, so create them first if( !createGpuResources() ) { return; } _positions = new cc::Vec3f[_totalPoints]; _lastPositions = new cc::Vec3f[_totalPoints]; _forces = new cc::Vec3f[_totalPoints]; // fill in positions const int u = _divsX+1; const int v = _divsY+1; int count = 0; for( int j = 0; j <= _divsY; ++j ) { for( int i = 0; i <= _divsX; ++i ) { const float x = ((float(i) / (u-1)) * 2.0f - 1.0f) * _horizontalSize; const float y = 0.0f;//_size+1; const float z = ((float(j) / (v-1)) * _size); _positions[count] = cc::Vec3f(x, y, z); _lastPositions[count] = _positions[count]; count++; } } // compute number of springs and allocate space _springCount = v * (u - 1); // horizontal structure springs _springCount += u * (v - 1); // vertical structure springs _springCount += ((v - 1) * (u - 1)) * 2; // shear springs _springCount += (v * (u - 1)); // bend springs 1 _springCount += (u * (v - 1)); // bend springs 2 _springs = new Spring[_springCount]; // tracks which spring we are modifying; is incremented by addspring() int currSpring = 0; // horizontal structure springs for( int l1 = 0; l1 < v; ++l1 ) { for( int l2 = 0; l2 < (u - 1); ++l2 ) { const int a = (l1 * u) + l2; const int b = (l1 * u) + l2 + 1; addSpring(&currSpring, a, b, _ksStruct, _kdStruct); } } // vertical structure springs for( int l1 = 0; l1 < u; ++l1 ) { for( int l2 = 0; l2 < (v - 1); ++l2 ) { const int a = (l2 * u) + l1; const int b = ((l2 + 1) * u) + l1; addSpring(&currSpring, a, b, _ksStruct, _kdStruct); } } // shear springs for( int l1 = 0; l1 < (v - 1); ++l1 ) { for( int l2 = 0; l2 < (u - 1); ++l2 ) { const int a1 = (l1 * u) + l2; const int b1 = ((l1 + 1) * u) + l2 + 1; addSpring(&currSpring, a1, b1, _ksShear, _kdShear); const int a2 = ((l1 + 1) * u) + l2; const int b2 = (l1 * u) + l2 + 1; addSpring(&currSpring, a2, b2, _ksShear, _kdShear); } } // bend springs for( int l1 = 0; l1 < v; ++l1 ) { for( int l2 = 0; l2 < (u - 2); ++l2 ) { const int a1 = (l1 * u) + l2; const int b1 = (l1 * u) + l2 + 2; addSpring(&currSpring, a1, b1, _ksBend, _kdBend); } const int a2 = (l1 * u) + (u - 3); const int b2 = (l1 * u) + (u - 1); addSpring(&currSpring, a2, b2, _ksBend, _kdBend); } for( int l1 = 0; l1 < u; ++l1 ) { for( int l2 = 0; l2 < (v - 2); ++l2 ) { const int a1 = (l2 * u) + l1; const int b1 = ((l2 + 2) * u) + l1; addSpring(&currSpring, a1, b1, _ksBend, _kdBend); } const int a2 = ((v - 3) * u) + l1; const int b2 = ((v - 1) * u) + l1; addSpring(&currSpring, a2, b2, _ksBend, _kdBend); } // create gpu stuff createGpuBuffers(); _built = true; }