{"id":14,"date":"2025-06-27T13:12:21","date_gmt":"2025-06-27T13:12:21","guid":{"rendered":"https:\/\/blog.metu.edu.tr\/e252216\/?p=14"},"modified":"2025-06-27T13:18:11","modified_gmt":"2025-06-27T13:18:11","slug":"rope-simulation-with-position-based-dynamics","status":"publish","type":"post","link":"https:\/\/blog.metu.edu.tr\/e252216\/2025\/06\/27\/rope-simulation-with-position-based-dynamics\/","title":{"rendered":"Rope Simulation with Position Based Dynamics"},"content":{"rendered":"<p>This post explains how a simple rope simulator works using OpenGL, Position-Based Dynamics (PBD), and compute shaders. The project is written in C++ and runs completely on the GPU.<\/p>\n<p>The goal is to simulate a rope that reacts to forces like gravity, stretches under tension, and can break when pulled too far.<\/p>\n<h2>Features<\/h2>\n<table>\n<tr>\n<th>Feature<\/th>\n<th>Included<\/th>\n<\/tr>\n<tr>\n<td>Position-Based Dynamics<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Compute Shader Acceleration<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Object Dragging\/Interaction<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td>Rope Breaking<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Simple Demo<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Tension Visualization<\/td>\n<td>Yes<\/td>\n<\/tr>\n<tr>\n<td>Advanced Demo (Raylib Integration)<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td>Multiple Rope Interaction<\/td>\n<td>No<\/td>\n<\/tr>\n<\/table>\n<h2>What is Position-Based Dynamics?<\/h2>\n<p>Position-Based Dynamics (PBD) is a method for simulating soft bodies. Instead of using forces and solving for acceleration, PBD directly updates positions to meet certain constraints.<\/p>\n<p>In this case, each rope segment is a constraint that tries to keep a fixed distance between two particles.<\/p>\n<pre><code>struct Particle {\r\n  glm::vec4 pos;   \/\/ xyz = position, w = mass\r\n  glm::vec4 prev;  \/\/ previous position\r\n};\r\n<\/code><\/pre>\n<h2>Compute Shaders<\/h2>\n<p>This project uses OpenGL compute shaders to run both the simulation and constraint solving on the GPU. There are two main compute shaders:<\/p>\n<h3>Integration Shader<\/h3>\n<pre><code>vec3 velocity = p.position.xyz - p.prevPosition.xyz;\r\nvec3 newPos = p.position.xyz + velocity + gravity * dt * dt;\r\n<\/code><\/pre>\n<p>If a particle is selected and dragging is enabled, its position is fixed to the mouse.<\/p>\n<h3>Constraint Solver Shader<\/h3>\n<pre><code>if (dist &gt; segmentLength * breakThreshold) {\r\n    pairs[id] = ivec2(-1, -1); \/\/ mark as broken\r\n}\r\n<\/code><\/pre>\n<h2>Rope Breaking<\/h2>\n<p>When the distance between two connected particles becomes too long, the rope segment breaks.<\/p>\n<p>The break condition is:<\/p>\n<pre><code>#define BREAK_THRESHOLD 1.5f\r\n<\/code><\/pre>\n<p>If the distance becomes more than 1.5 times the original length, the connection is removed.<\/p>\n<h2>Rendering with Geometry Shader<\/h2>\n<p>The rope is drawn using a geometry shader that creates a thick colored line from each segment. The color depends on how much tension the segment is under.<\/p>\n<pre><code>float tension = abs(dist - segmentLength) \/ segmentLength * tensionScale;\r\nfColor = mix(blue, red, tension);\r\n<\/code><\/pre>\n<ul>\n<li>Blue = low tension<\/li>\n<li>Red = high tension<\/li>\n<\/ul>\n<h2>Interaction<\/h2>\n<p>The program lets you interact with the rope through the keyboard:<\/p>\n<ul>\n<li><code>J<\/code> \/ <code>K<\/code> \u2013 Move selection to next\/previous particle<\/li>\n<li><code>W<\/code> \/ <code>S<\/code> \u2013 Increase or decrease mass<\/li>\n<li><code>P<\/code> \u2013 Pin or unpin the selected particle<\/li>\n<li><code>Space<\/code> \u2013 Toggle dragging (not fully implemented)<\/li>\n<\/ul>\n<p>Dragging with the mouse is not finished, but the selected particle is highlighted.<\/p>\n<h2>Updating Rope Segments<\/h2>\n<p>When a segment breaks, the rope structure changes. The program updates the index buffer to reflect these changes and re-renders only the connected parts.<\/p>\n<h2>How It Works<\/h2>\n<ol>\n<li>A number of particles are initialized in a straight line.<\/li>\n<li>Constraints are added between each pair of particles.<\/li>\n<li>On each frame:\n<ul>\n<li>The compute shader updates particle positions.<\/li>\n<li>The constraint shader corrects distances and breaks segments if needed.<\/li>\n<li>The index buffer is rebuilt to reflect which segments are still connected.<\/li>\n<\/ul>\n<\/li>\n<li>The rope is rendered using geometry and fragment shaders.<\/li>\n<\/ol>\n<figure class=\"wp-block-embed wp-block-embed-youtube is-type-video is-provider-youtube epyt-figure\"><div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\"  id=\"_ytid_93759\"  width=\"750\" height=\"422\"  data-origwidth=\"750\" data-origheight=\"422\" src=\"https:\/\/www.youtube.com\/embed\/N-w18rY0Cxw?enablejsapi=1&autoplay=0&cc_load_policy=0&cc_lang_pref=&iv_load_policy=1&loop=0&rel=1&fs=1&playsinline=0&autohide=2&theme=dark&color=red&controls=1&disablekb=0&\" class=\"__youtube_prefs__  no-lazyload\" title=\"YouTube player\"  allow=\"fullscreen; accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen data-no-lazy=\"1\" data-skipgform_ajax_framebjll=\"\"><\/iframe><\/div><\/figure>\n<h2>Summary<\/h2>\n<p>This rope simulation project shows how to combine GPU compute shaders and modern OpenGL to simulate and render a dynamic rope. It includes features like:<\/p>\n<ul>\n<li>Position-Based Dynamics for stable simulation<\/li>\n<li>GPU-based constraint solving<\/li>\n<li>Rope breaking under stress<\/li>\n<li>Visual tension feedback<\/li>\n<\/ul>\n<p>Although dragging and multiple ropes are not yet implemented, the system is flexible and can be extended further.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post explains how a simple rope simulator works using OpenGL, Position-Based Dynamics (PBD), and compute shaders. The project is written in C++ and runs completely on the GPU. The goal is to simulate a rope that reacts to forces like gravity, stretches under tension, and can break when pulled too far. Features Feature Included&hellip; <a class=\"more-link\" href=\"https:\/\/blog.metu.edu.tr\/e252216\/2025\/06\/27\/rope-simulation-with-position-based-dynamics\/\">Continue reading <span class=\"screen-reader-text\">Rope Simulation with Position Based Dynamics<\/span><\/a><\/p>\n","protected":false},"author":7766,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[1],"tags":[],"class_list":["post-14","post","type-post","status-publish","format-standard","hentry","category-uncategorized","entry"],"_links":{"self":[{"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/posts\/14","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/users\/7766"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/comments?post=14"}],"version-history":[{"count":0,"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/posts\/14\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/media?parent=14"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/categories?post=14"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.metu.edu.tr\/e252216\/wp-json\/wp\/v2\/tags?post=14"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}