cloth2

view src/cloth.cc @ 1:dc15b741486c

exploding cloth
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 11 Jan 2016 20:24:13 +0200
parents ef0c22554406
children b4b8f736332b
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 damping = 0.01;
13 grav = Vector3(0, -9, 0);
14 }
16 void Cloth::create_rect(int x, int y, float width, float height)
17 {
18 int num = x * y;
19 float dx = width / (float)x;
20 float dy = height / (float)y;
22 masses.resize(num);
23 conn.resize(num);
24 for(int i=0; i<num; i++) {
25 conn[i].resize(num);
26 }
28 int idx = 0;
29 for(int i=0; i<y; i++) {
30 for(int j=0; j<x; j++) {
31 // position the mass
32 masses[idx].pos.x = (float)j * dx - width / 2.0;
33 masses[idx].pos.y = 0;
34 masses[idx].pos.z = (float)i * dy - height / 2.0;
35 masses[idx].fixed = i == 0; // XXX debug hack
36 ++idx;
37 }
38 }
40 idx = 0;
41 for(int i=0; i<y; i++) {
42 for(int j=0; j<x; j++) {
43 // not connected to itself
44 conn[idx][idx] = -1;
46 // connect node to its neighbors
47 for(int ni=0; ni<3; ni++) {
48 for(int nj=0; nj<3; nj++) {
49 int nx = j + nj - 1;
50 int ny = i + ni - 1;
52 if(!nx && !ny) continue;
53 if(nx < 0 || nx >= x || ny < 0 || ny >= y) continue;
55 int nidx = ny * x + nx;
56 float dist = length(masses[idx].pos - masses[nidx].pos);
58 conn[idx][nidx] = conn[nidx][idx] = dist;
59 }
60 }
62 ++idx;
63 }
64 }
65 }
67 void Cloth::set_mass(float m)
68 {
69 mass = m;
70 }
72 void Cloth::set_elasticity(float e)
73 {
74 elast = e;
75 }
77 void Cloth::set_spring_constant(float k)
78 {
79 spring_k = k;
80 }
82 void Cloth::set_damping(float d)
83 {
84 damping = d;
85 }
87 void Cloth::set_gravity(const Vector3 &g)
88 {
89 grav = g;
90 }
92 void Cloth::set_force(const Vector3 &f)
93 {
94 forces = f;
95 }
97 void Cloth::transform(const Matrix4x4 &xform)
98 {
99 for(size_t i=0; i<masses.size(); i++) {
100 masses[i].pos = masses[i].pos * xform;
101 }
102 }
104 void Cloth::add_collider(Object *o)
105 {
106 colliders.push_back(o);
107 }
109 void Cloth::step(float dt)
110 {
111 int num_masses = (int)masses.size();
113 Vector3 *newp = new Vector3[num_masses];
115 for(int i=0; i<num_masses; i++) {
116 if(masses[i].fixed) {
117 newp[i] = masses[i].pos;
118 continue;
119 }
121 Vector3 force = grav + forces;
123 for(int j=0; j<num_masses; j++) {
124 if(i == j || conn[i][j] <= 0.0) {
125 continue; // skip unconnected
126 }
128 Vector3 dir = masses[j].pos - masses[i].pos;
129 float dist = length(dir);
130 float disp = dist - conn[i][j];
131 if(fabs(disp) < 1e-5) disp = 0.0f;
133 // apply an impulse based on the displacement from the original state
134 force += dir * ((disp * spring_k) / dist * 0.5);
135 }
137 // update the velocity by integrating the accumulation of all forces
138 Vector3 accel = force / mass;
139 masses[i].vel = masses[i].vel * (1.0 - damping) + accel * dt;
141 Vector3 newpos = masses[i].pos + masses[i].vel * dt;
143 Ray ray;
144 ray.origin = masses[i].pos;
145 ray.dir = newpos - masses[i].pos;
147 HitPoint pt;
148 if(find_collision(ray, &pt)) {
149 newpos = pt.pos;
150 masses[i].vel = reflect(masses[i].vel, pt.normal) * elast; // TODO collider elasticity
151 }
152 //masses[i].pos = newpos;
153 newp[i] = newpos;
154 }
156 for(int i=0; i<num_masses; i++) {
157 masses[i].pos = newp[i];
158 }
160 delete [] newp;
161 }
163 bool Cloth::find_collision(const Ray &ray, HitPoint *hit) const
164 {
165 HitPoint nearest;
166 nearest.obj = 0;
167 nearest.t = FLT_MAX;
169 for(size_t i=0; i<colliders.size(); i++) {
170 if(colliders[i]->intersect(ray, hit) && hit->t < nearest.t) {
171 nearest = *hit;
172 }
173 }
175 if(nearest.obj) {
176 *hit = nearest;
177 return true;
178 }
179 return false;
180 }
182 void Cloth::draw() const
183 {
184 glPushAttrib(GL_ENABLE_BIT);
186 glPointSize(7.0);
187 glEnable(GL_POINT_SMOOTH);
189 glEnable(GL_BLEND);
190 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
192 // draw masses
193 glBegin(GL_POINTS);
194 for(size_t i=0; i<masses.size(); i++) {
195 if(masses[i].fixed) {
196 glColor3f(1, 0, 0);
197 } else {
198 glColor3f(1, 0.4, 0.2);
199 }
200 glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z);
201 }
202 glEnd();
204 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
206 // draw neighbor connection lines
207 glBegin(GL_LINES);
208 glColor4f(0, 1, 0, 0.25);
210 for(size_t i=0; i<masses.size(); i++) {
211 for(size_t j=0; j<masses.size(); j++) {
212 if(i == j || conn[i][j] <= 0.0) continue;
214 glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z);
215 glVertex3f(masses[j].pos.x, masses[j].pos.y, masses[j].pos.z);
216 }
217 }
218 glEnd();
220 glPopAttrib();
221 }