# Simulating hair physics

This topic is 2856 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi, I'd like to ask some help and suggestions about simulating hair physics (so basically pulling hair vertices around, and smoothly disposing the adjacent ones).

Please take a look at the embedded video (which shows an application tha can do it): the hair displayed there is made of 15 vertices; once the user drags the active vertices (those inside the circular cursor area), all the hair vertices are moved and repositioned accordingly. To notice that hair length remain the same during the process.

Thanks for any help.

[media]
[/media]

##### Share on other sites
Sorry, I had troubles embedding the YT movie, now it's there.

Well, probably "simulating physics" was not really appropriate, since there is no gravity or dynamic forces that I need to apply to that hair. Nonetheless, I need to pull out vertices just as you would with a normal hair... Edited by Alessandro

##### Share on other sites
Are you looking for a solution in 2d or 3d?

##### Share on other sites

Are you looking for a solution in 2d or 3d?

That would be 3d!

##### Share on other sites
You could probably use the same method used here (though you could simplify it a lot since you won't be simulating full 3D bodies, just hair). Just make a "rope" of vertices, each one attached to the one before and after it, set a min/max distance between each pair of vertices, and then use Verlet integration and a simple constraint solver to handle the constraints. You could add gravity or not, it's up to you.

##### Share on other sites

You could probably use the same method used here (though you could simplify it a lot since you won't be simulating full 3D bodies, just hair). Just make a "rope" of vertices, each one attached to the one before and after it, set a min/max distance between each pair of vertices, and then use Verlet integration and a simple constraint solver to handle the constraints. You could add gravity or not, it's up to you.

I already have a "rope" of vertices, all attached to each other. I've read the paper and honestly didn't understand much of it.
Would it be possible to get some pseudo-code that would show how, for example, having a rope of 5 vertices, move those around while maintaining a fixed distance between each vertex?

##### Share on other sites
Sure. Note that this code doesn't use a Verlet integrator because I'm not doing anything with gravity, and I'm not giving any momentum/velocity to the vertices. I appologize if some of the variable names aren't the clearest; rename them if it helps you understand things better. Most of this comes from page two of that article I linked. It's been awhile since I've done any of this and thought it might be a fun challenge. Yes, it's 2D, but the concepts are exactly the same for 3D.

#include <SFML/Window.hpp> #include <SFML/Graphics.hpp> #include <iostream> #include <cmath> // Some settings. Adjust these to play around float distance = 20.0f; int numVerts = 20; float circleRadius = 50.0f; int numIterations = 10; std::vector<sf::Vector2f> verts; sf::Vector2f mousePos; int main(int argc, char* argv[]) { sf::RenderWindow renderWindow(sf::VideoMode(800, 600), "Meh title"); // Initialize the list of vertices for (int i = 0; i < numVerts; ++i) { sf::Vector2f v(renderWindow.GetWidth() / 2, i * distance); verts.push_back(v); } std::clock_t lastUpdate = std::clock(); while (renderWindow.IsOpened()) { // ~60 FPS if (std::clock() - lastUpdate >= 1000 / 60) { lastUpdate = std::clock(); // Capture mouse position sf::Vector2i mp = sf::Mouse::GetPosition(renderWindow); mousePos.x = mp.x; mousePos.y = mp.y; renderWindow.Clear(); // THIS IS WHERE YOU WANT TO START PAYING ATTENTION // This section just uses a couple of simple constraint solvers. The first one forces vertices inside the circle's mouse to outside it. // The second one forces the root to stay at a fixed location. The third one forces the vertices to be a fixed distance from each other. // More iterations in the constraint solver means greater accuracy. The cost is speed, of course. for (int iterationCounter = 0; iterationCounter < numIterations; ++iterationCounter) { // First constraint: Interact with the circle for (std::size_t i = 0; i < verts.size(); ++i) { sf::Vector2f dif = verts - mousePos; if (dif.x * dif.x + dif.y * dif.y < circleRadius * circleRadius) { float length = std::sqrt(dif.x * dif.x + dif.y * dif.y); float dist = circleRadius - length; dif /= length; dif *= dist; verts += dif; } } // Second constraint: Fix the root verts[0] = sf::Vector2f(renderWindow.GetWidth() / 2, 0); // Third constraint: Fix the distance constraint of the verts for (std::size_t i = 0; i < verts.size() - 1; ++i) { sf::Vector2f dif = verts - verts[i + 1]; if (dif.x * dif.x + dif.y * dif.y != distance * distance) { float length = std::sqrt(dif.x * dif.x + dif.y * dif.y); float dist = distance - length; dif /= length; dif *= dist * 0.5f; // each vert gets half the distance verts += dif; verts[i + 1] -= dif; } } } // YOU CAN STOP PAYING ATTENTION HERE // Draw the line/rope/hair and the vertices for (std::size_t i = 0; i < verts.size() - 1; ++i) { sf::Shape line = sf::Shape::Line(verts, verts[i + 1], 1.0f, sf::Color::Red); renderWindow.Draw(line); sf::Shape circle = sf::Shape::Circle(verts, 2.0f, sf::Color::Yellow, 1.0f, sf::Color::Yellow); circle.EnableFill(false); renderWindow.Draw(circle); } // Draw the circle around the mouse sf::Shape circle = sf::Shape::Circle(mousePos, circleRadius, sf::Color::Green, 1.0f, sf::Color::Green); circle.EnableFill(false); renderWindow.Draw(circle); renderWindow.Display(); } sf::Event event; if (renderWindow.PollEvent(event)) { if (event.Type == sf::Event::Closed) { renderWindow.Close(); } } } }

Do source tags no longer do automatic syntax highlighting? And how do I specify the language in source tags?

##### Share on other sites
Dear CornsTalks, thanks so much for this code you provided; very much appreciated as I believe you spent quite some time on it. Thanks again, I'm now going to study it and report

Sure. Note that this code doesn't use a Verlet integrator because I'm not doing anything with gravity, and I'm not giving any momentum/velocity to the vertices. I appologize if some of the variable names aren't the clearest; rename them if it helps you understand things better. Most of this comes from page two of that article I linked. It's been awhile since I've done any of this and thought it might be a fun challenge. Yes, it's 2D, but the concepts are exactly the same for 3D.

#include <SFML/Window.hpp> #include <SFML/Graphics.hpp> #include <iostream> #include <cmath> // Some settings. Adjust these to play around float distance = 20.0f; int numVerts = 20; float circleRadius = 50.0f; int numIterations = 10; std::vector<sf::Vector2f> verts; sf::Vector2f mousePos; int main(int argc, char* argv[]) { sf::RenderWindow renderWindow(sf::VideoMode(800, 600), "Meh title"); // Initialize the list of vertices for (int i = 0; i < numVerts; ++i) { sf::Vector2f v(renderWindow.GetWidth() / 2, i * distance); verts.push_back(v); } std::clock_t lastUpdate = std::clock(); while (renderWindow.IsOpened()) { // ~60 FPS if (std::clock() - lastUpdate >= 1000 / 60) { lastUpdate = std::clock(); // Capture mouse position sf::Vector2i mp = sf::Mouse::GetPosition(renderWindow); mousePos.x = mp.x; mousePos.y = mp.y; renderWindow.Clear(); // THIS IS WHERE YOU WANT TO START PAYING ATTENTION // This section just uses a couple of simple constraint solvers. The first one forces vertices inside the circle's mouse to outside it. // The second one forces the root to stay at a fixed location. The third one forces the vertices to be a fixed distance from each other. // More iterations in the constraint solver means greater accuracy. The cost is speed, of course. for (int iterationCounter = 0; iterationCounter < numIterations; ++iterationCounter) { // First constraint: Interact with the circle for (std::size_t i = 0; i < verts.size(); ++i) { sf::Vector2f dif = verts - mousePos; if (dif.x * dif.x + dif.y * dif.y < circleRadius * circleRadius) { float length = std::sqrt(dif.x * dif.x + dif.y * dif.y); float dist = circleRadius - length; dif /= length; dif *= dist; verts += dif; } } // Second constraint: Fix the root verts[0] = sf::Vector2f(renderWindow.GetWidth() / 2, 0); // Third constraint: Fix the distance constraint of the verts for (std::size_t i = 0; i < verts.size() - 1; ++i) { sf::Vector2f dif = verts - verts[i + 1]; if (dif.x * dif.x + dif.y * dif.y != distance * distance) { float length = std::sqrt(dif.x * dif.x + dif.y * dif.y); float dist = distance - length; dif /= length; dif *= dist * 0.5f; // each vert gets half the distance verts += dif; verts[i + 1] -= dif; } } } // YOU CAN STOP PAYING ATTENTION HERE // Draw the line/rope/hair and the vertices for (std::size_t i = 0; i < verts.size() - 1; ++i) { sf::Shape line = sf::Shape::Line(verts, verts[i + 1], 1.0f, sf::Color::Red); renderWindow.Draw(line); sf::Shape circle = sf::Shape::Circle(verts, 2.0f, sf::Color::Yellow, 1.0f, sf::Color::Yellow); circle.EnableFill(false); renderWindow.Draw(circle); } // Draw the circle around the mouse sf::Shape circle = sf::Shape::Circle(mousePos, circleRadius, sf::Color::Green, 1.0f, sf::Color::Green); circle.EnableFill(false); renderWindow.Draw(circle); renderWindow.Display(); } sf::Event event; if (renderWindow.PollEvent(event)) { if (event.Type == sf::Event::Closed) { renderWindow.Close(); } } } }

Do source tags no longer do automatic syntax highlighting? And how do I specify the language in source tags?

• ### Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 19
• 36
• 9
• 16
• 75