├── LICENSE ├── assets ├── reset.css └── styles.css ├── index.html ├── lib └── mootools-1.2.4-core-yc.js └── source ├── canvas.js ├── cloth.js ├── constraint.js ├── fast_vector.js └── point.js /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Andrew Hoyer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/reset.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, font, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | dl, dt, dd, ol, ul, li, 7 | fieldset, form, label, legend, 8 | table, caption, tbody, tfoot, thead, tr, th, td { 9 | margin: 0; 10 | padding: 0; 11 | border: 0; 12 | outline: 0; 13 | font-weight: inherit; 14 | font-style: inherit; 15 | font-size: 100%; 16 | font-family: inherit; 17 | vertical-align: baseline; 18 | } 19 | 20 | body { 21 | line-height: 1; 22 | color: black; 23 | background: white; 24 | } 25 | 26 | ol, ul { 27 | list-style: none; 28 | } 29 | 30 | table { 31 | border-collapse: separate; 32 | border-spacing: 0; 33 | vertical-align: middle; 34 | } 35 | 36 | caption, th, td { 37 | text-align: left; 38 | font-weight: normal; 39 | vertical-align: middle; 40 | } 41 | 42 | q, blockquote { 43 | quotes: "" ""; 44 | } 45 | 46 | q:before, q:after, blockquote:before, blockquote:after { 47 | content: ""; 48 | } 49 | 50 | a img { 51 | border: none; 52 | } 53 | -------------------------------------------------------------------------------- /assets/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: lucida grande, lucida, sans-serif; 3 | color: #555; 4 | text-shadow: 0 1px 0px #eee; 5 | line-height: 1.4em; 6 | font-size: 13px; 7 | padding: 20px; 8 | width: 990px; 9 | margin: 0 auto; 10 | letter-spacing: -0.07em; 11 | } 12 | 13 | h1, h3 { 14 | font-weight: normal; 15 | } 16 | 17 | h1, h3 { 18 | margin: 0 0 0.8em 0; 19 | } 20 | 21 | h1 { font-size: 2em; } 22 | h2 { font-size: 1.75em; } 23 | h3 { font-size: 1.5em; } 24 | h4 { font-size: 1.25em; } 25 | h5 { font-size: 1em; } 26 | h6 { font-size: 0.75em; } 27 | 28 | canvas { 29 | border: 1px solid #ddd; 30 | margin: 0; 31 | padding: 0; 32 | } 33 | 34 | div.left-column { 35 | width: 275px; 36 | float: left; 37 | } 38 | 39 | div.right-column { 40 | margin-left: 275px; 41 | padding: 0 20px; 42 | width: 675px; 43 | } 44 | 45 | nav, div.chrome-link, div.experiment, div.social-links { 46 | text-align: center; 47 | } 48 | 49 | nav { 50 | margin: 0.5em 0 1em; 51 | } 52 | 53 | p { 54 | text-indent: 1em; 55 | margin-bottom: 1em; 56 | } 57 | 58 | a, a:visited { 59 | color: #db98d7; 60 | } 61 | 62 | li { 63 | margin: 15px; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 |Every line in the cloth simulation is technically called a constraint and every point is a point mass (an object with no dimension, just location and mass). All the constraints do is control the distance between each point mass. If two points move too far apart, it will pull them closer. If two points are too close together, it will push them apart. The cloth is really then just a collection of constraints and point masses in a never ending struggle.
31 | 32 | 36 | 37 | 40 |Click and drag to move points. Hold down any key to pin them.
48 |Draw Lines Draw Points
What makes this simulation special is the speed at which everything is computed. Javascript (the language this is written in) is not exactly the most efficient language for this type of computation. This being said, much time was spent squeezing out every little detail that slows things down.
54 | 55 |The most computationally expensive part is trying to satisfy the constraints. To do this requires the calculation of distance between two points. This is easy to do with a little math, but that often involves an expensive square root. This is something that cannot simply be thrown out either, so what do you do? You approximate it. There are lots of mathematical tools for approximating functions, in this case I chose the first couple terms of a taylor expansion.
56 | 57 |"Boring!" you say.
58 | 59 |No. Not boring. Beautiful...
60 | 61 |Another pretty neat thing about this simulation is how all the constraints are satisfied. As I mentioned above, a constraint is basically a rule that controls the distance between two points. So for example if a point has moved too far away from its constrained counterpart, the constraint will suck it back in. What makes this a little trickier is the fact that we have several constraints attached to a single point. This means that this point is going to be constantly jerked around when the constraint satisfaction process begins to execute. In terms of visuals, the cloth would become really springy, jittery and all around unnatural looking.
64 | 65 |As it turns out there is a really simple solution to this problem. Instead of satisfying all the constraints just once, you simply satisfy them several times before updating the screen. In the case of this cloth simulation all I needed to do was try satisfying the constraints twice. But for things like simple rope simulations it may be necessary to satisfy several times (maybe 4 or 5). The more times you satisfy, the more rigid the constraint becomes. This process is known as relaxation and is pretty darn cool.
66 | 67 |If you're interested here are some links:
70 | 71 |