cloth2

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