diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..8a5f669
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,246 @@
+---
+Language: Cpp
+# BasedOnStyle: Mozilla
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveAssignments:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: true
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveMacros:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+AlignConsecutiveShortCaseStatements:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCaseColons: false
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments:
+ Kind: Always
+ OverEmptyLines: 0
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowBreakBeforeNoexceptSpecifier: Never
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortCompoundRequirementOnASingleLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: TopLevel
+AlwaysBreakAfterReturnType: TopLevel
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: Yes
+AttributeMacros:
+ - __capability
+BinPackArguments: false
+BinPackParameters: false
+BitFieldColonSpacing: Both
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: true
+ AfterControlStatement: Never
+ AfterEnum: true
+ AfterExternBlock: true
+ AfterFunction: true
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: false
+ SplitEmptyNamespace: true
+BreakAdjacentStringLiterals: true
+BreakAfterAttributes: Leave
+BreakAfterJavaFieldAnnotations: false
+BreakArrays: true
+BreakBeforeBinaryOperators: None
+BreakBeforeConceptDeclarations: Always
+BreakBeforeBraces: Mozilla
+BreakBeforeInlineASMColon: OnlyMultiline
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeComma
+BreakInheritanceList: BeforeComma
+BreakStringLiterals: true
+ColumnLimit: 120
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: false
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: false
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseBlocks: false
+IndentCaseLabels: true
+IndentExternBlock: AfterExternBlock
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentRequiresClause: true
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+InsertBraces: false
+InsertNewlineAtEOF: false
+InsertTrailingCommas: None
+IntegerLiteralSeparator:
+ Binary: 0
+ BinaryMinDigits: 0
+ Decimal: 0
+ DecimalMinDigits: 0
+ Hex: 0
+ HexMinDigits: 0
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+KeepEmptyLinesAtEOF: false
+LambdaBodyIndentation: Signature
+LineEnding: DeriveLF
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 4
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: true
+ObjCSpaceBeforeProtocolList: false
+PackConstructorInitializers: BinPack
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakScopeResolution: 500
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyIndentedWhitespace: 0
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+PPIndentWidth: -1
+QualifierAlignment: Leave
+ReferenceAlignment: Pointer
+ReflowComments: true
+RemoveBracesLLVM: false
+RemoveParentheses: Leave
+RemoveSemicolon: false
+RequiresClausePosition: OwnLine
+RequiresExpressionIndentation: OuterScope
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SkipMacroDefinitionBody: false
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: LexicographicNumeric
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: false
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDefinitionName: false
+ AfterFunctionDeclarationName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ AfterPlacementOperator: true
+ AfterRequiresInClause: false
+ AfterRequiresInExpression: false
+ BeforeNonEmptyParentheses: false
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceBeforeSquareBrackets: false
+SpaceInEmptyBlock: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInContainerLiterals: true
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParens: Never
+SpacesInParensOptions:
+ InCStyleCasts: false
+ InConditionalStatements: false
+ InEmptyParentheses: false
+ Other: false
+SpacesInSquareBrackets: false
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 4
+UseTab: Never
+VerilogBreakBetweenInstancePorts: true
+WhitespaceSensitiveMacros:
+ - BOOST_PP_STRINGIZE
+ - CF_SWIFT_NAME
+ - NS_SWIFT_NAME
+ - PP_STRINGIZE
+ - STRINGIZE
+...
+
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 9514767..71ab9b8 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -12,7 +12,7 @@ jobs:
steps:
- name: clone
- uses: actions/checkout@v4 # Action to check out your repository
+ uses: actions/checkout@v4
- name: dependencies
run: |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d26e645..34fecf3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,7 +7,7 @@ project(cloth_sim_tutorial LANGUAGES CXX)
option(CLOTH_DEBUG "run with debug options" OFF)
option(CLOTH_TESTING_ONLY "only compile unit tests" OFF)
-set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
add_definitions(-DCLOTH_ROOT_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/README.md b/README.md
index 20c8b21..0cefcb6 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@ This results in a block-sparse linear system for which the velocity deltas are s
The B&W method is conceptually straight forward. However, there are numerous gotchas not apparent in the original references.
In particular, working out the Jacobians of some models can be nontrivial. Even when correct, the derivatives can still produce hard-to-debug instabilities.
-The [dynamic deformables course notes](https://doi.org/10.1145/3388769.3407490) describes this well, and I highly recommend reviewing the later chapters on cloth simulation for a thorough review of the topic.
+The [dynamic deformables course notes](https://doi.org/10.1145/3388769.3407490) describes this well, and I highly recommend reviewing the later chapters on cloth simulation.
Nonetheless, implicit time integration remains a valuable and sometimes necessary tool for modern graphics applications.
Recently, optimization-based methods have grown in popularity. This approach formulates the Eqs. of motion as an [iteratively minimized objective function](https://en.wikipedia.org/wiki/Optimization_problem).
@@ -26,6 +26,8 @@ Below we describe a simple implicit solver for mass-spring systems using gradien
This is meant solely as a tutorial to optimization-based time stepping, and not for practical applications.
For that, you'll want to consider higher-order optimization algorithms or [local-global type solvers](https://github.com/alecjacobson/computer-graphics-mass-spring-systems).
+

+
## Implementation
The objective we aim to minimize is the sum of internal elastic energy potentials plus a quadratic penalty of linear momentum:
@@ -34,7 +36,7 @@ $`\bar{x} = x + hv + h^2 M^{-1} f_{ext}`$,
$`g(x) = \frac{1}{2h^2}\|M^{1/2}(x-\bar{x})\|^2 + \sum E(x)`$,
-for vertex locations $x$, time step (sec) $h$, diagonal mass matrix $M$, velocities $v$, and external forces (gravity, wind, etc...)
+for vertex locations $x$, time step (seconds) $h$, diagonal mass matrix $M$, velocities $v$, and external forces (gravity, wind, etc...)
$`f_{ext}`$. The term $`\bar{x}`$ is the *explicit predictor*
that is computed at the beginning of the time step. Computing a frame of animation amounts to iteratively minimizing the above objective until some convergence criteria is met
(e.g., the norm of the gradient is below some threshold).
@@ -91,4 +93,5 @@ There are many ways to improve the solver illustrated above:
- Collision against triangle meshes with a [signed distance field](https://github.com/InteractiveComputerGraphics/TriangleMeshDistance)
- Better energy models with triangular elements ([Dynamic Deformables appendix D](https://doi.org/10.1145/3388769.3407490))
- Preconditioning or accelerated versions of gradient descent
+- Non-conservative forces like friction
- Optimizers with better convergence like [L-BFGS](https://en.wikipedia.org/wiki/Limited-memory_BFGS) or [projected Newton](https://doi.org/10.1145/1073368.1073394)
diff --git a/data/sphere.png b/data/sphere.png
new file mode 100644
index 0000000..08b8b8e
Binary files /dev/null and b/data/sphere.png differ
diff --git a/src/ClothAssert.hpp b/src/ClothAssert.hpp
index 7975731..11b7441 100644
--- a/src/ClothAssert.hpp
+++ b/src/ClothAssert.hpp
@@ -4,29 +4,28 @@
#ifndef CLOTHASSERT_HPP
#define CLOTHASSERT_HPP 1
-#include
-#include
+#include
#include
+#include
-namespace cloth
-{
+namespace cloth {
-static inline void AssertHandler(bool cond, const std::string& file, const int& line)
+static inline void
+AssertHandler(bool cond, const std::string& file, const int& line)
{
- if (!cond)
- {
- std::string err_msg = "Assertion failed in "+file+" line "+std::to_string(line);
- throw std::runtime_error(err_msg.c_str());
- }
+ if (!cond) {
+ std::string err_msg = "Assertion failed in " + file + " line " + std::to_string(line);
+ throw std::runtime_error(err_msg.c_str());
+ }
}
-static inline void AssertHandlerMsg(bool cond, const std::string& file, const int& line, const std::string &msg)
+static inline void
+AssertHandlerMsg(bool cond, const std::string& file, const int& line, const std::string& msg)
{
- if (!cond)
- {
- std::string err_msg = "Assertion failed in "+file+" line "+std::to_string(line)+": "+msg;
- throw std::runtime_error(err_msg.c_str());
- }
+ if (!cond) {
+ std::string err_msg = "Assertion failed in " + file + " line " + std::to_string(line) + ": " + msg;
+ throw std::runtime_error(err_msg.c_str());
+ }
}
}
@@ -37,12 +36,9 @@ static inline void AssertHandlerMsg(bool cond, const std::string& file, const in
#define ClothAssert_withmsg(cond, msg) AssertHandlerMsg(cond, std::string(__FILE__), __LINE__, msg)
#define ClothAssert_nomsg(cond) AssertHandler(cond, std::string(__FILE__), __LINE__)
-#define ClothAssert_stripargs(xx,cond,msg,FUNC, ...) FUNC
+#define ClothAssert_stripargs(xx, cond, msg, FUNC, ...) FUNC
-#define ClothAssert(...) \
- ClothAssert_stripargs(,##__VA_ARGS__,\
- ClothAssert_withmsg(__VA_ARGS__),\
- ClothAssert_nomsg(__VA_ARGS__),\
- )
+#define ClothAssert(...) \
+ ClothAssert_stripargs(, ##__VA_ARGS__, ClothAssert_withmsg(__VA_ARGS__), ClothAssert_nomsg(__VA_ARGS__), )
#endif
diff --git a/src/ClothMesh.hpp b/src/ClothMesh.hpp
index 214ab9d..1a60b88 100644
--- a/src/ClothMesh.hpp
+++ b/src/ClothMesh.hpp
@@ -8,131 +8,116 @@
#include
#include