cloth2

view src/cloth.cc @ 0:ef0c22554406

cloth sim test, initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 11 Jan 2016 16:51:16 +0200
parents
children dc15b741486c
line source
1 #include <stdio.h>
2 #include <float.h>
3 #include "cloth.h"
4 #include "object.h"
5 #include "opengl.h"
7 Cloth::Cloth()
8 {
9 mass = 1.0;
10 elast = 0.8;
11 spring_k = 1.0;
12 grav = Vector3(0, -9, 0);
13 }
15 void Cloth::create_rect(int x, int y, float width, float height)
16 {
17 int num = x * y;
18 float dx = width / (float)x;
19 float dy = height / (float)y;
21 masses.resize(num);
22 conn.resize(num);
23 for(int i=0; i<num; i++) {
24 conn[i].resize(num);
25 }
27 int idx = 0;
28 for(int i=0; i<y; i++) {
29 for(int j=0; j<x; j++) {
30 // position the mass
31 masses[idx].pos.x = (float)j * dx - width / 2.0;
32 masses[idx].pos.y = 0;
33 masses[idx].pos.z = (float)i * dy - height / 2.0;
34 masses[idx].fixed = i == 0 && (j == 0 || j == x - 1); // XXX debug hack
35 ++idx;
36 }
37 }
39 idx = 0;
40 for(int i=0; i<y; i++) {
41 for(int j=0; j<x; j++) {
42 // not connected to itself
43 conn[idx][idx] = -1;
45 // connect node to its neighbors
46 for(int ni=0; ni<5; ni++) {
47 for(int nj=0; nj<5; nj++) {
48 int nx = j + nj - 2;
49 int ny = i + ni - 2;
51 if(!nx && !ny) continue;
52 if(nx < 0 || nx >= x || ny < 0 || ny >= y) continue;
54 int nidx = ny * x + nx;
55 float dist = length(masses[idx].pos - masses[nidx].pos);
57 conn[idx][nidx] = conn[nidx][idx] = dist;
58 }
59 }
61 ++idx;
62 }
63 }
64 }
66 void Cloth::transform(const Matrix4x4 &xform)
67 {
68 for(size_t i=0; i<masses.size(); i++) {
69 masses[i].pos = masses[i].pos * xform;
70 }
71 }
73 void Cloth::add_collider(Object *o)
74 {
75 colliders.push_back(o);
76 }
78 void Cloth::step(float dt)
79 {
80 int num_masses = (int)masses.size();
82 for(int i=0; i<num_masses; i++) {
83 if(masses[i].fixed) continue;
85 Vector3 newpos = masses[i].pos + masses[i].vel * dt;
87 Vector3 force = grav + forces;
89 for(int j=0; j<num_masses; j++) {
90 if(conn[i][j] <= 0.0) continue; // skip unconnected
92 Vector3 dir = masses[j].pos - masses[i].pos;
93 float dist = length(dir);
95 // apply an impulse based on the displacement from the original state
96 force += dir * (dist - conn[i][j]) * spring_k;
97 }
99 // update the velocity by integrating the accumulation of all forces
100 masses[i].vel += force * dt;
102 Ray ray;
103 ray.origin = masses[i].pos;
104 ray.dir = newpos - masses[i].pos;
106 HitPoint pt;
107 if(find_collision(ray, &pt)) {
108 newpos = pt.pos;
109 masses[i].vel = reflect(masses[i].vel, pt.normal) * elast; // TODO collider elasticity
110 }
111 masses[i].pos = newpos;
112 }
113 }
115 bool Cloth::find_collision(const Ray &ray, HitPoint *hit) const
116 {
117 HitPoint nearest;
118 nearest.obj = 0;
119 nearest.t = FLT_MAX;
121 for(size_t i=0; i<colliders.size(); i++) {
122 if(colliders[i]->intersect(ray, hit) && hit->t < nearest.t) {
123 nearest = *hit;
124 }
125 }
127 if(nearest.obj) {
128 *hit = nearest;
129 return true;
130 }
131 return false;
132 }
134 void Cloth::draw() const
135 {
136 glPushAttrib(GL_ENABLE_BIT);
138 glPointSize(7.0);
139 glEnable(GL_POINT_SMOOTH);
141 glEnable(GL_BLEND);
142 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
144 // draw masses
145 glBegin(GL_POINTS);
146 for(size_t i=0; i<masses.size(); i++) {
147 if(masses[i].fixed) {
148 glColor3f(1, 0, 0);
149 } else {
150 glColor3f(1, 0.4, 0.2);
151 }
152 glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z);
153 }
154 glEnd();
156 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
158 // draw neighbor connection lines
159 glBegin(GL_LINES);
160 glColor4f(0, 1, 0, 0.25);
162 for(size_t i=0; i<masses.size(); i++) {
163 for(size_t j=0; j<masses.size(); j++) {
164 if(i == j || conn[i][j] <= 0.0) continue;
166 glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z);
167 glVertex3f(masses[j].pos.x, masses[j].pos.y, masses[j].pos.z);
168 }
169 }
170 glEnd();
172 glPopAttrib();
173 }