cloth2

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