Skip to content

Commit 8b495a8

Browse files
committed
- added substepping
- added OBJ export
1 parent c7180dc commit 8b495a8

16 files changed

+314
-154
lines changed

Changelog.txt

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
1.8.0
2+
- added OBJ export
3+
- added substepping
14
- updated GenericParameters
25
- bufixes
36
- fixed several compiler warnings

Demos/Common/DemoBase.h

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ namespace PBD
114114
std::vector<unsigned int>& getSelectedRigidBodies() { return m_selectedBodies; }
115115
bool getUseCache() const { return m_useCache; }
116116
void setUseCache(bool val) { m_useCache = val; }
117+
std::string getOutputPath() const { return m_outputPath; }
117118

118119
Utilities::SceneLoader::SceneData& getSceneData() { return m_scene; }
119120
};

Demos/PositionBasedElasticRodsDemo/PositionBasedElasticRodsTSC.cpp

+80-64
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ PositionBasedElasticRodsTSC::~PositionBasedElasticRodsTSC()
2121
void PositionBasedElasticRodsTSC::step(SimulationModel &model)
2222
{
2323
TimeManager *tm = TimeManager::getCurrent ();
24-
const Real h = tm->getTimeStepSize();
24+
const Real hOld = tm->getTimeStepSize();
2525
PositionBasedElasticRodsModel &ermodel = (PositionBasedElasticRodsModel&)model;
2626

2727
//////////////////////////////////////////////////////////////////////////
@@ -33,86 +33,102 @@ void PositionBasedElasticRodsTSC::step(SimulationModel &model)
3333
ParticleData &pg = ermodel.getGhostParticles();
3434

3535
const int numBodies = (int)rb.size();
36-
#pragma omp parallel if(numBodies > MIN_PARALLEL_SIZE) default(shared)
37-
{
38-
#pragma omp for schedule(static) nowait
39-
for (int i = 0; i < numBodies; i++)
40-
{
41-
rb[i]->getLastPosition() = rb[i]->getOldPosition();
42-
rb[i]->getOldPosition() = rb[i]->getPosition();
43-
TimeIntegration::semiImplicitEuler(h, rb[i]->getMass(), rb[i]->getPosition(), rb[i]->getVelocity(), rb[i]->getAcceleration());
44-
rb[i]->getLastRotation() = rb[i]->getOldRotation();
45-
rb[i]->getOldRotation() = rb[i]->getRotation();
46-
TimeIntegration::semiImplicitEulerRotation(h, rb[i]->getMass(), rb[i]->getInertiaTensorInverseW(), rb[i]->getRotation(), rb[i]->getAngularVelocity(), rb[i]->getTorque());
47-
rb[i]->rotationUpdated();
48-
}
4936

50-
//////////////////////////////////////////////////////////////////////////
51-
// particle model
52-
//////////////////////////////////////////////////////////////////////////
53-
#pragma omp for schedule(static)
54-
for (int i = 0; i < (int) pd.size(); i++)
37+
Real h = hOld / (Real)m_subSteps;
38+
tm->setTimeStepSize(h);
39+
for (unsigned int step = 0; step < m_subSteps; step++)
40+
{
41+
#pragma omp parallel if(numBodies > MIN_PARALLEL_SIZE) default(shared)
5542
{
56-
pd.getLastPosition(i) = pd.getOldPosition(i);
57-
pd.getOldPosition(i) = pd.getPosition(i);
58-
pd.getVelocity(i) *= (1.0f - m_damping);
43+
#pragma omp for schedule(static) nowait
44+
for (int i = 0; i < numBodies; i++)
45+
{
46+
rb[i]->getLastPosition() = rb[i]->getOldPosition();
47+
rb[i]->getOldPosition() = rb[i]->getPosition();
48+
TimeIntegration::semiImplicitEuler(h, rb[i]->getMass(), rb[i]->getPosition(), rb[i]->getVelocity(), rb[i]->getAcceleration());
49+
rb[i]->getLastRotation() = rb[i]->getOldRotation();
50+
rb[i]->getOldRotation() = rb[i]->getRotation();
51+
TimeIntegration::semiImplicitEulerRotation(h, rb[i]->getMass(), rb[i]->getInertiaTensorInverseW(), rb[i]->getRotation(), rb[i]->getAngularVelocity(), rb[i]->getTorque());
52+
rb[i]->rotationUpdated();
53+
}
54+
55+
//////////////////////////////////////////////////////////////////////////
56+
// particle model
57+
//////////////////////////////////////////////////////////////////////////
58+
#pragma omp for schedule(static)
59+
for (int i = 0; i < (int) pd.size(); i++)
60+
{
61+
pd.getLastPosition(i) = pd.getOldPosition(i);
62+
pd.getOldPosition(i) = pd.getPosition(i);
63+
pd.getVelocity(i) *= (1.0f - m_damping);
5964

60-
TimeIntegration::semiImplicitEuler(h, pd.getMass(i), pd.getPosition(i), pd.getVelocity(i), pd.getAcceleration(i));
61-
}
65+
TimeIntegration::semiImplicitEuler(h, pd.getMass(i), pd.getPosition(i), pd.getVelocity(i), pd.getAcceleration(i));
66+
}
6267

63-
for (int i = 0; i < (int)pg.size(); i++)
64-
{
65-
pg.getLastPosition(i) = pg.getOldPosition(i);
66-
pg.getOldPosition(i) = pg.getPosition(i);
68+
for (int i = 0; i < (int)pg.size(); i++)
69+
{
70+
pg.getLastPosition(i) = pg.getOldPosition(i);
71+
pg.getOldPosition(i) = pg.getPosition(i);
6772

68-
pg.getVelocity(i) *= (1.0f - m_damping);
73+
pg.getVelocity(i) *= (1.0f - m_damping);
6974

70-
TimeIntegration::semiImplicitEuler(h, pg.getMass(i), pg.getPosition(i), pg.getVelocity(i), pg.getAcceleration(i));
75+
TimeIntegration::semiImplicitEuler(h, pg.getMass(i), pg.getPosition(i), pg.getVelocity(i), pg.getAcceleration(i));
76+
}
7177
}
72-
}
7378

74-
positionConstraintProjection(model);
79+
positionConstraintProjection(model);
7580

76-
#pragma omp parallel if(numBodies > MIN_PARALLEL_SIZE) default(shared)
77-
{
78-
// Update velocities
79-
#pragma omp for schedule(static) nowait
80-
for (int i = 0; i < numBodies; i++)
81-
{
82-
if (m_velocityUpdateMethod == 0)
81+
#pragma omp parallel if(numBodies > MIN_PARALLEL_SIZE) default(shared)
82+
{
83+
// Update velocities
84+
#pragma omp for schedule(static) nowait
85+
for (int i = 0; i < numBodies; i++)
86+
{
87+
if (m_velocityUpdateMethod == 0)
88+
{
89+
TimeIntegration::velocityUpdateFirstOrder(h, rb[i]->getMass(), rb[i]->getPosition(), rb[i]->getOldPosition(), rb[i]->getVelocity());
90+
TimeIntegration::angularVelocityUpdateFirstOrder(h, rb[i]->getMass(), rb[i]->getRotation(), rb[i]->getOldRotation(), rb[i]->getAngularVelocity());
91+
}
92+
else
93+
{
94+
TimeIntegration::velocityUpdateSecondOrder(h, rb[i]->getMass(), rb[i]->getPosition(), rb[i]->getOldPosition(), rb[i]->getLastPosition(), rb[i]->getVelocity());
95+
TimeIntegration::angularVelocityUpdateSecondOrder(h, rb[i]->getMass(), rb[i]->getRotation(), rb[i]->getOldRotation(), rb[i]->getLastRotation(), rb[i]->getAngularVelocity());
96+
}
97+
}
98+
99+
// Update velocities
100+
#pragma omp for schedule(static)
101+
for (int i = 0; i < (int) pd.size(); i++)
83102
{
84-
TimeIntegration::velocityUpdateFirstOrder(h, rb[i]->getMass(), rb[i]->getPosition(), rb[i]->getOldPosition(), rb[i]->getVelocity());
85-
TimeIntegration::angularVelocityUpdateFirstOrder(h, rb[i]->getMass(), rb[i]->getRotation(), rb[i]->getOldRotation(), rb[i]->getAngularVelocity());
103+
if (m_velocityUpdateMethod == 0)
104+
TimeIntegration::velocityUpdateFirstOrder(h, pd.getMass(i), pd.getPosition(i), pd.getOldPosition(i), pd.getVelocity(i));
105+
else
106+
TimeIntegration::velocityUpdateSecondOrder(h, pd.getMass(i), pd.getPosition(i), pd.getOldPosition(i), pd.getLastPosition(i), pd.getVelocity(i));
86107
}
87-
else
108+
109+
#pragma omp for schedule(static)
110+
for (int i = 0; i < (int)pg.size(); i++)
88111
{
89-
TimeIntegration::velocityUpdateSecondOrder(h, rb[i]->getMass(), rb[i]->getPosition(), rb[i]->getOldPosition(), rb[i]->getLastPosition(), rb[i]->getVelocity());
90-
TimeIntegration::angularVelocityUpdateSecondOrder(h, rb[i]->getMass(), rb[i]->getRotation(), rb[i]->getOldRotation(), rb[i]->getLastRotation(), rb[i]->getAngularVelocity());
112+
if (m_velocityUpdateMethod == 0)
113+
TimeIntegration::velocityUpdateFirstOrder(h, pg.getMass(i), pg.getPosition(i), pg.getOldPosition(i), pg.getVelocity(i));
114+
else
115+
TimeIntegration::velocityUpdateSecondOrder(h, pg.getMass(i), pg.getPosition(i), pg.getOldPosition(i), pg.getLastPosition(i), pg.getVelocity(i));
91116
}
92-
// update geometry
93-
rb[i]->getGeometry().updateMeshTransformation(rb[i]->getPosition(), rb[i]->getRotationMatrix());
94-
}
117+
}
118+
}
119+
h = hOld;
120+
tm->setTimeStepSize(hOld);
95121

122+
#pragma omp parallel if(numBodies > MIN_PARALLEL_SIZE) default(shared)
123+
{
96124
// Update velocities
97-
#pragma omp for schedule(static)
98-
for (int i = 0; i < (int) pd.size(); i++)
99-
{
100-
if (m_velocityUpdateMethod == 0)
101-
TimeIntegration::velocityUpdateFirstOrder(h, pd.getMass(i), pd.getPosition(i), pd.getOldPosition(i), pd.getVelocity(i));
102-
else
103-
TimeIntegration::velocityUpdateSecondOrder(h, pd.getMass(i), pd.getPosition(i), pd.getOldPosition(i), pd.getLastPosition(i), pd.getVelocity(i));
104-
}
105-
106-
#pragma omp for schedule(static)
107-
for (int i = 0; i < (int)pg.size(); i++)
125+
#pragma omp for schedule(static) nowait
126+
for (int i = 0; i < numBodies; i++)
108127
{
109-
if (m_velocityUpdateMethod == 0)
110-
TimeIntegration::velocityUpdateFirstOrder(h, pg.getMass(i), pg.getPosition(i), pg.getOldPosition(i), pg.getVelocity(i));
111-
else
112-
TimeIntegration::velocityUpdateSecondOrder(h, pg.getMass(i), pg.getPosition(i), pg.getOldPosition(i), pg.getLastPosition(i), pg.getVelocity(i));
128+
if (rb[i]->getMass() != 0.0)
129+
rb[i]->getGeometry().updateMeshTransformation(rb[i]->getPosition(), rb[i]->getRotationMatrix());
113130
}
114-
115-
}
131+
}
116132

117133
if (m_collisionDetection)
118134
m_collisionDetection->collisionDetection(model);

Demos/SceneLoaderDemo/SceneLoaderDemo.cpp

+111
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void buildModel ();
3939
void readScene(const bool readFile);
4040
void render ();
4141
void reset();
42+
void exportOBJ();
4243
void TW_CALL setContactTolerance(const void *value, void *clientData);
4344
void TW_CALL getContactTolerance(void *value, void *clientData);
4445
void TW_CALL setContactStiffnessRigidBody(const void *value, void *clientData);
@@ -60,6 +61,10 @@ CubicSDFCollisionDetection cd;
6061
short clothSimulationMethod = 2;
6162
short solidSimulationMethod = 2;
6263
short bendingMethod = 2;
64+
bool enableExportOBJ = false;
65+
unsigned int exportFPS = 25;
66+
Real nextFrameTime = 0.0;
67+
unsigned int frameCounter = 1;
6368

6469

6570
// main
@@ -129,6 +134,9 @@ void initParameters()
129134

130135
MiniGL::initTweakBarParameters();
131136

137+
TwAddVarRW(MiniGL::getTweakBar(), "ExportOBJ", TW_TYPE_BOOL32, &enableExportOBJ, " label='Export OBJ'");
138+
TwAddVarRW(MiniGL::getTweakBar(), "ExportFPS", TW_TYPE_UINT32, &exportFPS, " label='Export FPS'");
139+
132140
TweakBarParameters::createParameterGUI();
133141
TweakBarParameters::createParameterObjectGUI(base);
134142
TweakBarParameters::createParameterObjectGUI(Simulation::getCurrent());
@@ -138,6 +146,7 @@ void initParameters()
138146

139147
void reset()
140148
{
149+
const Real h = TimeManager::getCurrent()->getTimeStepSize();
141150
Utilities::Timing::printAverageTimes();
142151
Utilities::Timing::reset();
143152

@@ -147,7 +156,11 @@ void reset()
147156
Simulation::getCurrent()->getModel()->cleanup();
148157
Simulation::getCurrent()->getTimeStep()->getCollisionDetection()->cleanup();
149158

159+
nextFrameTime = 0.0;
160+
frameCounter = 1;
161+
150162
readScene(false);
163+
TimeManager::getCurrent()->setTimeStepSize(h);
151164
}
152165

153166
void timeStep ()
@@ -167,6 +180,8 @@ void timeStep ()
167180
START_TIMING("SimStep");
168181
Simulation::getCurrent()->getTimeStep()->step(*model);
169182
STOP_TIMING_AVG;
183+
184+
exportOBJ();
170185
}
171186

172187
// Update visualization models
@@ -1089,6 +1104,101 @@ void readScene(const bool readFile)
10891104
}
10901105
}
10911106

1107+
void exportMeshOBJ(const std::string &exportFileName, const unsigned int nVert, const Vector3r* pos, const unsigned int nTri, const unsigned int* faces)
1108+
{
1109+
// Open the file
1110+
std::ofstream outfile(exportFileName);
1111+
if (!outfile)
1112+
{
1113+
LOG_WARN << "Cannot open a file to save OBJ mesh.";
1114+
return;
1115+
}
1116+
1117+
// Header
1118+
outfile << "# Created by the PositionBasedDynamics library\n";
1119+
outfile << "g default\n";
1120+
1121+
// Vertices
1122+
{
1123+
for (auto j = 0u; j < nVert; j++)
1124+
{
1125+
const Vector3r& x = pos[j];
1126+
outfile << "v " << x[0] << " " << x[1] << " " << x[2] << "\n";
1127+
}
1128+
}
1129+
1130+
// faces
1131+
{
1132+
for (auto j = 0; j < nTri; j++)
1133+
{
1134+
outfile << "f " << faces[3 * j + 0] + 1 << " " << faces[3 * j + 1] + 1 << " " << faces[3 * j + 2] + 1 << "\n";
1135+
}
1136+
}
1137+
outfile.close();
1138+
}
1139+
1140+
1141+
void exportOBJ()
1142+
{
1143+
if (!enableExportOBJ)
1144+
return;
1145+
1146+
if (TimeManager::getCurrent()->getTime() < nextFrameTime)
1147+
return;
1148+
1149+
nextFrameTime += 1.0 / (Real)exportFPS;
1150+
1151+
//////////////////////////////////////////////////////////////////////////
1152+
// rigid bodies
1153+
//////////////////////////////////////////////////////////////////////////
1154+
1155+
std::string exportPath = base->getOutputPath() + "/export";
1156+
FileSystem::makeDirs(exportPath);
1157+
1158+
SimulationModel* model = Simulation::getCurrent()->getModel();
1159+
const ParticleData& pd = model->getParticles();
1160+
for (unsigned int i = 0; i < model->getTriangleModels().size(); i++)
1161+
{
1162+
const IndexedFaceMesh& mesh = model->getTriangleModels()[i]->getParticleMesh();
1163+
const unsigned int offset = model->getTriangleModels()[i]->getIndexOffset();
1164+
const Vector3r* x = model->getParticles().getVertices()->data();
1165+
1166+
std::string fileName = "triangle_model";
1167+
fileName = fileName + std::to_string(i) + "_" + std::to_string(frameCounter) + ".obj";
1168+
std::string exportFileName = FileSystem::normalizePath(exportPath + "/" + fileName);
1169+
1170+
exportMeshOBJ(exportFileName, mesh.numVertices(), &x[offset], mesh.numFaces(), mesh.getFaces().data());
1171+
}
1172+
1173+
for (unsigned int i = 0; i < model->getTetModels().size(); i++)
1174+
{
1175+
const IndexedFaceMesh& mesh = model->getTetModels()[i]->getVisMesh();
1176+
const unsigned int offset = model->getTetModels()[i]->getIndexOffset();
1177+
const Vector3r* x = model->getTetModels()[i]->getVisVertices().getVertices()->data();
1178+
1179+
std::string fileName = "tet_model";
1180+
fileName = fileName + std::to_string(i) + "_" + std::to_string(frameCounter) + ".obj";
1181+
std::string exportFileName = FileSystem::normalizePath(exportPath + "/" + fileName);
1182+
1183+
exportMeshOBJ(exportFileName, mesh.numVertices(), x, mesh.numFaces(), mesh.getFaces().data());
1184+
}
1185+
1186+
for (unsigned int i = 0; i < model->getRigidBodies().size(); i++)
1187+
{
1188+
const IndexedFaceMesh& mesh = model->getRigidBodies()[i]->getGeometry().getMesh();
1189+
const Vector3r *x = model->getRigidBodies()[i]->getGeometry().getVertexData().getVertices()->data();
1190+
1191+
std::string fileName = "rigid_body";
1192+
fileName = fileName + std::to_string(i) + "_" + std::to_string(frameCounter) + ".obj";
1193+
std::string exportFileName = FileSystem::normalizePath(exportPath + "/" + fileName);
1194+
1195+
exportMeshOBJ(exportFileName, mesh.numVertices(), x, mesh.numFaces(), mesh.getFaces().data());
1196+
}
1197+
1198+
1199+
frameCounter++;
1200+
}
1201+
10921202
void TW_CALL setContactTolerance(const void *value, void *clientData)
10931203
{
10941204
const Real val = *(const Real *)(value);
@@ -1158,3 +1268,4 @@ void TW_CALL getSolidSimulationMethod(void *value, void *clientData)
11581268
{
11591269
*(short *)(value) = *((short*)clientData);
11601270
}
1271+

Demos/StiffRodsDemos/StiffRodsSceneLoader.cpp

-2
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,6 @@ void PBD::StiffRodsSceneLoader::readStiffRodsScene(const std::string &fileName,
524524
//////////////////////////////////////////////////////////////////////////
525525
sceneData.m_timeStepSize = static_cast<Real>(0.005);
526526
sceneData.m_gravity = Vector3r(0, -static_cast<Real>(9.81), 0);
527-
sceneData.m_maxIter = 5;
528-
sceneData.m_maxIterVel = 5;
529527
sceneData.m_velocityUpdateMethod = 0;
530528
sceneData.m_triangleModelSimulationMethod = -1;
531529
sceneData.m_triangleModelBendingMethod = -1;

Demos/Visualization/MiniGL.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,8 @@ void MiniGL::display ()
466466
scenefunc ();
467467

468468
TwDraw(); // draw the tweak bar(s)
469-
glutSwapBuffers();
469+
//glutSwapBuffers();
470+
glFlush();
470471
}
471472

472473
void MiniGL::init(int argc, char **argv, const int width, const int height, const int posx, const int posy, const char *name)
@@ -478,7 +479,7 @@ void MiniGL::init(int argc, char **argv, const int width, const int height, cons
478479
scenefunc = NULL;
479480

480481
glutInit (&argc, argv);
481-
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
482+
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
482483

483484
atexit(destroy);
484485

0 commit comments

Comments
 (0)