Skip to content

Commit 89f956b

Browse files
committed
working strand bending!!!
1 parent 6de3033 commit 89f956b

10 files changed

+254
-36
lines changed

.idea/misc.xml

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ macro(package_add_scene FILENAME)
3838
endmacro()
3939
package_add_scene(BunnyDropExplicit)
4040
package_add_scene(StrandDropExplicit)
41-
package_add_scene(StrandTwistExplicit)
41+
package_add_scene(StrandBendExplicit)
4242

4343
add_executable(viewer main.cc)
4444
target_link_libraries(viewer PRIVATE ${OPENGL_LIBRARIES} GLUT::GLUT ${PROJECT_NAME})

Lib/Energy/Strand/DiscreteElasticRod.cc

+20-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
DiscreteElasticRod::DiscreteElasticRod(Mat<Real> vertices)
44
: vertices(std::move(vertices)), nRods(vertices.rows() - 1),
5-
massSpring(new MassSpring(100000, 0.25)) {
5+
massSpring(new MassSpring(100000, 1)) {
66
// At least 3 nodes is required
77
ASSERT(this->vertices.rows() >= 3, "At least 3 nodes are required");
88

@@ -109,10 +109,14 @@ auto DiscreteElasticRod::ComputeCenterlineForcesGeneral() -> Vec<Real> {
109109
auto DiscreteElasticRod::ComputeCenterlineForcesStraight() -> Vec<Real> {
110110
Vec<Real> R = Vec<Real>::Zero(DOFs());
111111

112-
// for (int ii = 0; ii < nRods - 2; ++ii) {
113-
// const Vec3<Real> vertexForce = ComputepEpxi(ii);
114-
// R.segment<3>(3 * ii + 1) += vertexForce;
115-
// }
112+
for (int ii = 0; ii < nRods - 2; ++ii) {
113+
const Vec3<Real> vertexForce = ComputepEpxi(ii);
114+
R.segment<3>(3 * ii + 1) += vertexForce;
115+
}
116+
117+
#ifndef NDEBUG
118+
std::cout << "forces: " << R.transpose() << std::endl;
119+
#endif
116120

117121
// Compute spring-mass forces
118122
for (int ii = 0; ii < nRods; ++ii) {
@@ -286,10 +290,6 @@ auto DiscreteElasticRod::ComputeTwistingForce() -> Vec<Real> {
286290
(thetaDiff1 / restEdges.at(j + 1).length));
287291
}
288292

289-
#ifndef NDEBUG
290-
std::cout << "forces: " << forces.transpose() << std::endl;
291-
#endif
292-
293293
return forces;
294294
}
295295

@@ -329,13 +329,18 @@ void DiscreteElasticRod::ComputeTwistingHessian(Vec<Real> &upper,
329329
}
330330

331331
auto DiscreteElasticRod::ComputepEpxi(int j) -> Vec3<Real> {
332-
const auto scaledTwistContrib = 2 * gTwistingModulus / restEdges.at(j).length;
332+
Mat2<Real> J;
333+
J << 0, -1, 1, 0;
334+
const Mat2<Real> Bhat = Mat2<Real>::Identity() * gBendingModulus;
335+
336+
const auto &restLength = restEdges.at(j).length;
333337
const auto &gradKb = kbGradients.at(j);
334-
const auto &kb = kbs.at(j);
335-
const auto &gradHolo = holonomyGradients.at(j);
336-
const Real thetaDiff = thetas(thetas.rows() - 1) - thetas(0);
337-
return scaledTwistContrib * gradKb.transpose() * kb +
338-
(gBendingModulus * thetaDiff) / totalRestLength * gradHolo;
338+
339+
const auto gradW = ComputeGradOmega(gradKb, m1s.at(j), m2s.at(j),
340+
holonomyGradients.at(j), curvature.at(j));
341+
const Vec2<Real> curvatureDiff = (curvature.at(j) - restCurvature.at(j));
342+
343+
return gradW.transpose() * Bhat * curvatureDiff / restLength;
339344
}
340345

341346
auto DiscreteElasticRod::ComputepEpTheta() -> Real {

Lib/Energy/Strand/DiscreteElasticRod.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <Energy/Spring/MassSpring.h>
55
#include <LibMath.h>
66

7-
constexpr Real gBendingModulus = 0.1;
7+
constexpr Real gBendingModulus = 0.000001;
88
constexpr Real gTwistingModulus = 0.7;
99

1010
class DiscreteElasticRod {

Lib/ForwardEulerStrand.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ class ForwardEulerStrand : public TimestepperStrand {
8484
this->strandMesh->der->UpdateLengths();
8585
this->strandMesh->der->Computekbs();
8686
this->strandMesh->der->UpdateBishopFrames();
87-
this->strandMesh->der->UpdateQuasistaticMaterialFrame();
87+
this->strandMesh->der->UpdateBishopFrames();
88+
this->strandMesh->der->UpdateMaterialCurvatures();
8889
this->strandMesh->der->UpdateKbGradients();
8990
this->strandMesh->der->UpdateHolonomyGradient();
9091
}

Lib/StrandMesh.h

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ class StrandMesh {
1818
[[nodiscard]] INLINE auto DOFs() const -> int { return der->DOFs(); }
1919
INLINE void SetPositions(const Vec<Real> &x) { der->SetPositions(x); }
2020
INLINE auto Positions() const -> Vec<Real> { return der->Positions(); }
21+
INLINE void TranslatePinnedX(Real dx, int ii) {
22+
if (pinned[ii] == 1) {
23+
der->vertices(ii, 0) = der->restVertices(ii, 0) + dx;
24+
}
25+
}
2126
void Draw();
2227

2328
/**

Scenes/StrandTwistExplicit.cc Scenes/StrandBendExplicit.cc

+52-9
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ bool gCameraZooming = false;
1616
bool gCameraPanning = false;
1717
bool gAnimating = false;
1818
bool gSingleStep = false;
19-
bool gShowGrid = true;
20-
bool gShowCenterAxes = true;
19+
bool gShowGrid = false;
20+
bool gShowCenterAxes = false;
2121
bool gSaveFrame = false;
2222

2323
int gSteps = 0;
@@ -182,26 +182,67 @@ void Display() {
182182
glFlush();
183183
}
184184

185+
static Vec<Real> gTranslationStart = Vec<Real>::LinSpaced(5000, 0, 2.5);
186+
static Vec<Real> gTranslationEnd = Vec<Real>::LinSpaced(5000, -2.5, 0);
187+
static int gTranslationIndex = 0;
188+
static int gFramesSaved = 0;
189+
static int gStopFrame = 10000;
185190
static void GlutIdle() {
186191
if (gStopped) {
187192
return;
188193
}
189194

190195
if (gAnimating || gSingleStep) {
191-
Vec3<Real> gravity;
192-
gravity.setZero();
196+
Vec3<Real> gravity(0, -0.981, 0);
193197
++gSteps;
194198

195-
gMesh->der->thetas(0) += 0.01;
196-
gMesh->der->thetas(gMesh->der->thetas.rows() - 1) += 0.01;
199+
gIntegrator->AddGravity(gravity);
197200
gIntegrator->Step();
198201

199202
if (gSingleStep) {
200203
gSingleStep = !gSingleStep;
201204
}
205+
206+
if (gSteps > 1000 && gTranslationIndex < gTranslationStart.rows()) {
207+
gMesh->TranslatePinnedX(gTranslationStart(gTranslationIndex), 0);
208+
gMesh->TranslatePinnedX(
209+
gTranslationEnd.reverse().eval()(gTranslationIndex), 4);
210+
++gTranslationIndex;
211+
}
212+
}
213+
214+
if (gSteps == gStopFrame) {
215+
gAnimating = false;
216+
gStopped = true;
202217
}
203218

204219
if (gSteps % 10 == 0 && gAnimating) {
220+
if (gSaveFrame) {
221+
222+
223+
char filename[512];
224+
sprintf(filename, "/Users/jarredparr/Downloads/output/frame_%05i.obj",
225+
gFramesSaved);
226+
++gFramesSaved;
227+
228+
std::ofstream file(filename);
229+
230+
const auto &vertices = gMesh->der->vertices;
231+
for (int jj = 0; jj < vertices.rows(); ++jj) {
232+
// Write vertices.row(ii) to the file
233+
file << "v " << vertices.row(jj) << std::endl;
234+
}
235+
236+
file << "l ";
237+
for (int jj = 0; jj < vertices.rows(); ++jj) {
238+
int index = (jj + 1);
239+
file << index << " ";
240+
}
241+
242+
file << std::endl;
243+
file.close();
244+
}
245+
205246
glutPostRedisplay();
206247
}
207248
}
@@ -222,12 +263,14 @@ auto main(int argc, char **argv) -> int {
222263
// Set the mesh
223264
Mat<Real> v(5, 3);
224265
for (int ii = 0; ii < v.rows(); ++ii) {
225-
v.row(ii) = Vec3<Real>(ii, 2, 0);
266+
v.row(ii) = Vec3<Real>(ii, 0, 0);
226267
}
227268

228269
gMesh = std::make_shared<StrandMesh>(v);
229-
gIntegrator =
230-
std::make_shared<ForwardEulerStrand>(gMesh, nullptr, 1 / 100'000, 5, 0.3);
270+
gMesh->pinned(0) = 1;
271+
gMesh->pinned(v.rows() - 1) = 1;
272+
gIntegrator = std::make_shared<ForwardEulerStrand>(gMesh, nullptr,
273+
1.0 / 1'000.0, 5, 0.3);
231274

232275
glutInit(&argc, argv);
233276
glutInitDisplayMode(GLUT_DEPTH | GLUT_RGBA);

Scripts/mitsuba.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66

77
app = typer.Typer()
88

9-
scene = """
9+
scene_drop = """
1010
<scene version="3.0.0">
1111
1212
<!-- Defaults, these can be set via the command line: -Darg=value -->
1313
1414
<default name="spp" value="300"/>
15-
<default name="resx" value="1920"/>
16-
<default name="resy" value="1080"/>
15+
<default name="resx" value="1000"/>
16+
<default name="resy" value="800"/>
1717
<default name="max_depth" value="8"/>
1818
1919
@@ -156,11 +156,11 @@ def make_render_scene(folder: str, radius: float):
156156

157157
for file in track(os.listdir(folder)):
158158
# Convert frames to splines in the designated folder
159-
if file.startswith("frame"):
159+
if file.startswith("frame") and file.endswith(".obj"):
160160
load_obj_into_spline(os.path.join(folder, file), radius)
161161

162162
# Now create the scene, first by copying the template
163-
s = scene
163+
s = scene_drop
164164

165165
# Now create the spline entry and dump the scenes
166166
for file in track(os.listdir(folder)):
@@ -170,8 +170,9 @@ def make_render_scene(folder: str, radius: float):
170170
s += make_obj(os.path.join(folder, file))
171171

172172
s += "</scene>\n"
173-
print(s)
174-
return
173+
fn = os.path.splitext(file)[0]
174+
with open(os.path.join(folder, fn + ".xml"), "w") as f:
175+
f.write(s)
175176

176177

177178
if __name__ == "__main__":

0 commit comments

Comments
 (0)