cloth2
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/cloth.cc Mon Jan 11 16:51:16 2016 +0200 1.3 @@ -0,0 +1,173 @@ 1.4 +#include <stdio.h> 1.5 +#include <float.h> 1.6 +#include "cloth.h" 1.7 +#include "object.h" 1.8 +#include "opengl.h" 1.9 + 1.10 +Cloth::Cloth() 1.11 +{ 1.12 + mass = 1.0; 1.13 + elast = 0.8; 1.14 + spring_k = 1.0; 1.15 + grav = Vector3(0, -9, 0); 1.16 +} 1.17 + 1.18 +void Cloth::create_rect(int x, int y, float width, float height) 1.19 +{ 1.20 + int num = x * y; 1.21 + float dx = width / (float)x; 1.22 + float dy = height / (float)y; 1.23 + 1.24 + masses.resize(num); 1.25 + conn.resize(num); 1.26 + for(int i=0; i<num; i++) { 1.27 + conn[i].resize(num); 1.28 + } 1.29 + 1.30 + int idx = 0; 1.31 + for(int i=0; i<y; i++) { 1.32 + for(int j=0; j<x; j++) { 1.33 + // position the mass 1.34 + masses[idx].pos.x = (float)j * dx - width / 2.0; 1.35 + masses[idx].pos.y = 0; 1.36 + masses[idx].pos.z = (float)i * dy - height / 2.0; 1.37 + masses[idx].fixed = i == 0 && (j == 0 || j == x - 1); // XXX debug hack 1.38 + ++idx; 1.39 + } 1.40 + } 1.41 + 1.42 + idx = 0; 1.43 + for(int i=0; i<y; i++) { 1.44 + for(int j=0; j<x; j++) { 1.45 + // not connected to itself 1.46 + conn[idx][idx] = -1; 1.47 + 1.48 + // connect node to its neighbors 1.49 + for(int ni=0; ni<5; ni++) { 1.50 + for(int nj=0; nj<5; nj++) { 1.51 + int nx = j + nj - 2; 1.52 + int ny = i + ni - 2; 1.53 + 1.54 + if(!nx && !ny) continue; 1.55 + if(nx < 0 || nx >= x || ny < 0 || ny >= y) continue; 1.56 + 1.57 + int nidx = ny * x + nx; 1.58 + float dist = length(masses[idx].pos - masses[nidx].pos); 1.59 + 1.60 + conn[idx][nidx] = conn[nidx][idx] = dist; 1.61 + } 1.62 + } 1.63 + 1.64 + ++idx; 1.65 + } 1.66 + } 1.67 +} 1.68 + 1.69 +void Cloth::transform(const Matrix4x4 &xform) 1.70 +{ 1.71 + for(size_t i=0; i<masses.size(); i++) { 1.72 + masses[i].pos = masses[i].pos * xform; 1.73 + } 1.74 +} 1.75 + 1.76 +void Cloth::add_collider(Object *o) 1.77 +{ 1.78 + colliders.push_back(o); 1.79 +} 1.80 + 1.81 +void Cloth::step(float dt) 1.82 +{ 1.83 + int num_masses = (int)masses.size(); 1.84 + 1.85 + for(int i=0; i<num_masses; i++) { 1.86 + if(masses[i].fixed) continue; 1.87 + 1.88 + Vector3 newpos = masses[i].pos + masses[i].vel * dt; 1.89 + 1.90 + Vector3 force = grav + forces; 1.91 + 1.92 + for(int j=0; j<num_masses; j++) { 1.93 + if(conn[i][j] <= 0.0) continue; // skip unconnected 1.94 + 1.95 + Vector3 dir = masses[j].pos - masses[i].pos; 1.96 + float dist = length(dir); 1.97 + 1.98 + // apply an impulse based on the displacement from the original state 1.99 + force += dir * (dist - conn[i][j]) * spring_k; 1.100 + } 1.101 + 1.102 + // update the velocity by integrating the accumulation of all forces 1.103 + masses[i].vel += force * dt; 1.104 + 1.105 + Ray ray; 1.106 + ray.origin = masses[i].pos; 1.107 + ray.dir = newpos - masses[i].pos; 1.108 + 1.109 + HitPoint pt; 1.110 + if(find_collision(ray, &pt)) { 1.111 + newpos = pt.pos; 1.112 + masses[i].vel = reflect(masses[i].vel, pt.normal) * elast; // TODO collider elasticity 1.113 + } 1.114 + masses[i].pos = newpos; 1.115 + } 1.116 +} 1.117 + 1.118 +bool Cloth::find_collision(const Ray &ray, HitPoint *hit) const 1.119 +{ 1.120 + HitPoint nearest; 1.121 + nearest.obj = 0; 1.122 + nearest.t = FLT_MAX; 1.123 + 1.124 + for(size_t i=0; i<colliders.size(); i++) { 1.125 + if(colliders[i]->intersect(ray, hit) && hit->t < nearest.t) { 1.126 + nearest = *hit; 1.127 + } 1.128 + } 1.129 + 1.130 + if(nearest.obj) { 1.131 + *hit = nearest; 1.132 + return true; 1.133 + } 1.134 + return false; 1.135 +} 1.136 + 1.137 +void Cloth::draw() const 1.138 +{ 1.139 + glPushAttrib(GL_ENABLE_BIT); 1.140 + 1.141 + glPointSize(7.0); 1.142 + glEnable(GL_POINT_SMOOTH); 1.143 + 1.144 + glEnable(GL_BLEND); 1.145 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 1.146 + 1.147 + // draw masses 1.148 + glBegin(GL_POINTS); 1.149 + for(size_t i=0; i<masses.size(); i++) { 1.150 + if(masses[i].fixed) { 1.151 + glColor3f(1, 0, 0); 1.152 + } else { 1.153 + glColor3f(1, 0.4, 0.2); 1.154 + } 1.155 + glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z); 1.156 + } 1.157 + glEnd(); 1.158 + 1.159 + glBlendFunc(GL_SRC_ALPHA, GL_ONE); 1.160 + 1.161 + // draw neighbor connection lines 1.162 + glBegin(GL_LINES); 1.163 + glColor4f(0, 1, 0, 0.25); 1.164 + 1.165 + for(size_t i=0; i<masses.size(); i++) { 1.166 + for(size_t j=0; j<masses.size(); j++) { 1.167 + if(i == j || conn[i][j] <= 0.0) continue; 1.168 + 1.169 + glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z); 1.170 + glVertex3f(masses[j].pos.x, masses[j].pos.y, masses[j].pos.z); 1.171 + } 1.172 + } 1.173 + glEnd(); 1.174 + 1.175 + glPopAttrib(); 1.176 +}