cloth2
changeset 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 |
files | .hgignore Makefile src/cloth.cc src/cloth.h src/main.cc src/object.cc src/object.h src/opengl.h |
diffstat | 8 files changed, 496 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Mon Jan 11 16:51:16 2016 +0200 1.3 @@ -0,0 +1,4 @@ 1.4 +\.swp$ 1.5 +\.o$ 1.6 +\.d$ 1.7 +^cloth$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/Makefile Mon Jan 11 16:51:16 2016 +0200 2.3 @@ -0,0 +1,19 @@ 2.4 +src = $(wildcard src/*.cc) 2.5 +obj = $(src:.cc=.o) 2.6 +bin = cloth 2.7 + 2.8 +sys := $(shell uname -s | tr '[:upper:]' '[:lower:]' | sed 's/mingw.*/mingw/') 2.9 + 2.10 +CXXFLAGS = -pedantic -Wall -g 2.11 +LDFLAGS = $(libgl_$(sys)) -lgmath 2.12 + 2.13 +libgl_linux = -lGL -lGLU -lglut -lGLEW 2.14 +libgl_darwin = -framework OpenGL -framework GLUT -lGLEW 2.15 +libgl_mingw = -lopengl32 -lglu32 -lglut32 -lglew32 2.16 + 2.17 +$(bin): $(obj) 2.18 + $(CXX) -o $@ $(obj) $(LDFLAGS) 2.19 + 2.20 +.PHONY: clean 2.21 +clean: 2.22 + rm -f $(obj) $(bin)
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/cloth.cc Mon Jan 11 16:51:16 2016 +0200 3.3 @@ -0,0 +1,173 @@ 3.4 +#include <stdio.h> 3.5 +#include <float.h> 3.6 +#include "cloth.h" 3.7 +#include "object.h" 3.8 +#include "opengl.h" 3.9 + 3.10 +Cloth::Cloth() 3.11 +{ 3.12 + mass = 1.0; 3.13 + elast = 0.8; 3.14 + spring_k = 1.0; 3.15 + grav = Vector3(0, -9, 0); 3.16 +} 3.17 + 3.18 +void Cloth::create_rect(int x, int y, float width, float height) 3.19 +{ 3.20 + int num = x * y; 3.21 + float dx = width / (float)x; 3.22 + float dy = height / (float)y; 3.23 + 3.24 + masses.resize(num); 3.25 + conn.resize(num); 3.26 + for(int i=0; i<num; i++) { 3.27 + conn[i].resize(num); 3.28 + } 3.29 + 3.30 + int idx = 0; 3.31 + for(int i=0; i<y; i++) { 3.32 + for(int j=0; j<x; j++) { 3.33 + // position the mass 3.34 + masses[idx].pos.x = (float)j * dx - width / 2.0; 3.35 + masses[idx].pos.y = 0; 3.36 + masses[idx].pos.z = (float)i * dy - height / 2.0; 3.37 + masses[idx].fixed = i == 0 && (j == 0 || j == x - 1); // XXX debug hack 3.38 + ++idx; 3.39 + } 3.40 + } 3.41 + 3.42 + idx = 0; 3.43 + for(int i=0; i<y; i++) { 3.44 + for(int j=0; j<x; j++) { 3.45 + // not connected to itself 3.46 + conn[idx][idx] = -1; 3.47 + 3.48 + // connect node to its neighbors 3.49 + for(int ni=0; ni<5; ni++) { 3.50 + for(int nj=0; nj<5; nj++) { 3.51 + int nx = j + nj - 2; 3.52 + int ny = i + ni - 2; 3.53 + 3.54 + if(!nx && !ny) continue; 3.55 + if(nx < 0 || nx >= x || ny < 0 || ny >= y) continue; 3.56 + 3.57 + int nidx = ny * x + nx; 3.58 + float dist = length(masses[idx].pos - masses[nidx].pos); 3.59 + 3.60 + conn[idx][nidx] = conn[nidx][idx] = dist; 3.61 + } 3.62 + } 3.63 + 3.64 + ++idx; 3.65 + } 3.66 + } 3.67 +} 3.68 + 3.69 +void Cloth::transform(const Matrix4x4 &xform) 3.70 +{ 3.71 + for(size_t i=0; i<masses.size(); i++) { 3.72 + masses[i].pos = masses[i].pos * xform; 3.73 + } 3.74 +} 3.75 + 3.76 +void Cloth::add_collider(Object *o) 3.77 +{ 3.78 + colliders.push_back(o); 3.79 +} 3.80 + 3.81 +void Cloth::step(float dt) 3.82 +{ 3.83 + int num_masses = (int)masses.size(); 3.84 + 3.85 + for(int i=0; i<num_masses; i++) { 3.86 + if(masses[i].fixed) continue; 3.87 + 3.88 + Vector3 newpos = masses[i].pos + masses[i].vel * dt; 3.89 + 3.90 + Vector3 force = grav + forces; 3.91 + 3.92 + for(int j=0; j<num_masses; j++) { 3.93 + if(conn[i][j] <= 0.0) continue; // skip unconnected 3.94 + 3.95 + Vector3 dir = masses[j].pos - masses[i].pos; 3.96 + float dist = length(dir); 3.97 + 3.98 + // apply an impulse based on the displacement from the original state 3.99 + force += dir * (dist - conn[i][j]) * spring_k; 3.100 + } 3.101 + 3.102 + // update the velocity by integrating the accumulation of all forces 3.103 + masses[i].vel += force * dt; 3.104 + 3.105 + Ray ray; 3.106 + ray.origin = masses[i].pos; 3.107 + ray.dir = newpos - masses[i].pos; 3.108 + 3.109 + HitPoint pt; 3.110 + if(find_collision(ray, &pt)) { 3.111 + newpos = pt.pos; 3.112 + masses[i].vel = reflect(masses[i].vel, pt.normal) * elast; // TODO collider elasticity 3.113 + } 3.114 + masses[i].pos = newpos; 3.115 + } 3.116 +} 3.117 + 3.118 +bool Cloth::find_collision(const Ray &ray, HitPoint *hit) const 3.119 +{ 3.120 + HitPoint nearest; 3.121 + nearest.obj = 0; 3.122 + nearest.t = FLT_MAX; 3.123 + 3.124 + for(size_t i=0; i<colliders.size(); i++) { 3.125 + if(colliders[i]->intersect(ray, hit) && hit->t < nearest.t) { 3.126 + nearest = *hit; 3.127 + } 3.128 + } 3.129 + 3.130 + if(nearest.obj) { 3.131 + *hit = nearest; 3.132 + return true; 3.133 + } 3.134 + return false; 3.135 +} 3.136 + 3.137 +void Cloth::draw() const 3.138 +{ 3.139 + glPushAttrib(GL_ENABLE_BIT); 3.140 + 3.141 + glPointSize(7.0); 3.142 + glEnable(GL_POINT_SMOOTH); 3.143 + 3.144 + glEnable(GL_BLEND); 3.145 + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 3.146 + 3.147 + // draw masses 3.148 + glBegin(GL_POINTS); 3.149 + for(size_t i=0; i<masses.size(); i++) { 3.150 + if(masses[i].fixed) { 3.151 + glColor3f(1, 0, 0); 3.152 + } else { 3.153 + glColor3f(1, 0.4, 0.2); 3.154 + } 3.155 + glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z); 3.156 + } 3.157 + glEnd(); 3.158 + 3.159 + glBlendFunc(GL_SRC_ALPHA, GL_ONE); 3.160 + 3.161 + // draw neighbor connection lines 3.162 + glBegin(GL_LINES); 3.163 + glColor4f(0, 1, 0, 0.25); 3.164 + 3.165 + for(size_t i=0; i<masses.size(); i++) { 3.166 + for(size_t j=0; j<masses.size(); j++) { 3.167 + if(i == j || conn[i][j] <= 0.0) continue; 3.168 + 3.169 + glVertex3f(masses[i].pos.x, masses[i].pos.y, masses[i].pos.z); 3.170 + glVertex3f(masses[j].pos.x, masses[j].pos.y, masses[j].pos.z); 3.171 + } 3.172 + } 3.173 + glEnd(); 3.174 + 3.175 + glPopAttrib(); 3.176 +}
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/cloth.h Mon Jan 11 16:51:16 2016 +0200 4.3 @@ -0,0 +1,42 @@ 4.4 +#ifndef CLOTH_H_ 4.5 +#define CLOTH_H_ 4.6 + 4.7 +#include <vector> 4.8 +#include <gmath/gmath.h> 4.9 +#include "object.h" 4.10 + 4.11 +using namespace gph; 4.12 + 4.13 +struct ClothMass { 4.14 + Vector3 pos, vel; 4.15 + bool fixed; 4.16 +}; 4.17 + 4.18 +class Cloth { 4.19 +private: 4.20 + float mass, elast; // global mass attributes 4.21 + float spring_k; // spring constant for all springs 4.22 + Vector3 grav, forces; 4.23 + 4.24 + std::vector<ClothMass> masses; 4.25 + std::vector<std::vector<float> > conn; // spring lengths, <0 means not connected 4.26 + 4.27 + std::vector<Object*> colliders; 4.28 + 4.29 + bool find_collision(const Ray &ray, HitPoint *hit) const; 4.30 + 4.31 +public: 4.32 + Cloth(); 4.33 + 4.34 + void create_rect(int x, int y, float width, float height); 4.35 + 4.36 + void transform(const Matrix4x4 &xform); 4.37 + 4.38 + void add_collider(Object *o); 4.39 + 4.40 + void step(float dt); 4.41 + 4.42 + void draw() const; 4.43 +}; 4.44 + 4.45 +#endif // CLOTH_H_
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/main.cc Mon Jan 11 16:51:16 2016 +0200 5.3 @@ -0,0 +1,142 @@ 5.4 +#include <stdio.h> 5.5 +#include <stdlib.h> 5.6 +#include <assert.h> 5.7 +#include <GL/glew.h> 5.8 +#ifdef __APPLE__ 5.9 +#include <GLUT/glut.h> 5.10 +#else 5.11 +#include <GL/glut.h> 5.12 +#endif 5.13 +#include "object.h" 5.14 +#include "cloth.h" 5.15 + 5.16 +bool init(); 5.17 +void cleanup(); 5.18 +void display(); 5.19 +void idle(); 5.20 +void reshape(int x, int y); 5.21 +void keyboard(unsigned char key, int x, int y); 5.22 +void mouse(int bn, int st, int x, int y); 5.23 +void motion(int x, int y); 5.24 + 5.25 +float cam_theta, cam_phi, cam_dist = 8; 5.26 + 5.27 +Cloth cloth; 5.28 + 5.29 +int main(int argc, char **argv) 5.30 +{ 5.31 + glutInit(&argc, argv); 5.32 + glutInitWindowSize(800, 600); 5.33 + glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 5.34 + glutCreateWindow("foo"); 5.35 + 5.36 + glutDisplayFunc(display); 5.37 + glutIdleFunc(idle); 5.38 + glutReshapeFunc(reshape); 5.39 + glutKeyboardFunc(keyboard); 5.40 + glutMouseFunc(mouse); 5.41 + glutMotionFunc(motion); 5.42 + 5.43 + if(!init()) { 5.44 + return 1; 5.45 + } 5.46 + atexit(cleanup); 5.47 + 5.48 + glutMainLoop(); 5.49 +} 5.50 + 5.51 + 5.52 +bool init() 5.53 +{ 5.54 + glewInit(); 5.55 + 5.56 + glEnable(GL_DEPTH_TEST); 5.57 + glEnable(GL_CULL_FACE); 5.58 + //glEnable(GL_LIGHTING); 5.59 + glEnable(GL_LIGHT0); 5.60 + 5.61 + cloth.create_rect(32, 32, 10, 10); 5.62 + 5.63 + Matrix4x4 xform = Matrix4x4(1, 0, 0, 0, 5.64 + 0, 1, 0, 0, 5.65 + 0, 0, 1, 0, 5.66 + 0, 1, 0, 1); 5.67 + cloth.transform(xform); 5.68 + 5.69 + 5.70 + return true; 5.71 +} 5.72 + 5.73 +void cleanup() 5.74 +{ 5.75 +} 5.76 + 5.77 +void display() 5.78 +{ 5.79 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 5.80 + 5.81 + glMatrixMode(GL_MODELVIEW); 5.82 + glLoadIdentity(); 5.83 + glTranslatef(0, 0, -cam_dist); 5.84 + glRotatef(cam_phi, 1, 0, 0); 5.85 + glRotatef(cam_theta, 0, 1, 0); 5.86 + 5.87 + cloth.draw(); 5.88 + 5.89 + glutSwapBuffers(); 5.90 + assert(glGetError() == GL_NO_ERROR); 5.91 +} 5.92 + 5.93 +void idle() 5.94 +{ 5.95 + glutPostRedisplay(); 5.96 +} 5.97 + 5.98 +void reshape(int x, int y) 5.99 +{ 5.100 + glViewport(0, 0, x, y); 5.101 + 5.102 + glMatrixMode(GL_PROJECTION); 5.103 + glLoadIdentity(); 5.104 + gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); 5.105 +} 5.106 + 5.107 +void keyboard(unsigned char key, int x, int y) 5.108 +{ 5.109 + switch(key) { 5.110 + case 27: 5.111 + exit(0); 5.112 + } 5.113 +} 5.114 + 5.115 +static bool bnstate[16]; 5.116 +static int prev_x, prev_y; 5.117 + 5.118 +void mouse(int bn, int st, int x, int y) 5.119 +{ 5.120 + prev_x = x; 5.121 + prev_y = y; 5.122 + bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN; 5.123 +} 5.124 + 5.125 +void motion(int x, int y) 5.126 +{ 5.127 + int dx = x - prev_x; 5.128 + int dy = y - prev_y; 5.129 + prev_x = x; 5.130 + prev_y = y; 5.131 + 5.132 + if(!dx && !dy) return; 5.133 + 5.134 + if(bnstate[0]) { 5.135 + cam_theta += dx * 0.5; 5.136 + cam_phi += dy * 0.5; 5.137 + 5.138 + if(cam_phi < -90) cam_phi = -90; 5.139 + if(cam_phi > 90) cam_phi = 90; 5.140 + } 5.141 + if(bnstate[2]) { 5.142 + cam_dist += dy * 0.1; 5.143 + if(cam_dist < 0.0) cam_dist = 0.0; 5.144 + } 5.145 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/object.cc Mon Jan 11 16:51:16 2016 +0200 6.3 @@ -0,0 +1,27 @@ 6.4 +#include "object.h" 6.5 +#include "opengl.h" 6.6 + 6.7 +Object::~Object() 6.8 +{ 6.9 +} 6.10 + 6.11 +Triangle::Triangle() 6.12 +{ 6.13 +} 6.14 + 6.15 +Triangle::Triangle(const Vector3 &a, const Vector3 &b, const Vector3 &c) 6.16 +{ 6.17 + v[0] = a; 6.18 + v[1] = b; 6.19 + v[2] = c; 6.20 + normal = normalize(cross(b - a, c - a)); 6.21 +} 6.22 + 6.23 +bool Triangle::intersect(const Ray &ray, HitPoint *pt) const 6.24 +{ 6.25 + return false; 6.26 +} 6.27 + 6.28 +void Triangle::draw() const 6.29 +{ 6.30 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/object.h Mon Jan 11 16:51:16 2016 +0200 7.3 @@ -0,0 +1,37 @@ 7.4 +#ifndef OBJECT_H_ 7.5 +#define OBJECT_H_ 7.6 + 7.7 +#include <gmath/gmath.h> 7.8 + 7.9 +using namespace gph; 7.10 + 7.11 +class Object; 7.12 + 7.13 +struct HitPoint { 7.14 + float t; 7.15 + Vector3 pos, normal; 7.16 + Ray ray; 7.17 + Object *obj; 7.18 +}; 7.19 + 7.20 +class Object { 7.21 +public: 7.22 + virtual ~Object(); 7.23 + 7.24 + virtual bool intersect(const Ray &ray, HitPoint *pt) const = 0; 7.25 + virtual void draw() const = 0; 7.26 +}; 7.27 + 7.28 +class Triangle : public Object { 7.29 +public: 7.30 + Vector3 v[3]; 7.31 + Vector3 normal; 7.32 + 7.33 + Triangle(); 7.34 + Triangle(const Vector3 &a, const Vector3 &b, const Vector3 &c); 7.35 + 7.36 + virtual bool intersect(const Ray &ray, HitPoint *pt) const; 7.37 + virtual void draw() const; 7.38 +}; 7.39 + 7.40 +#endif
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/opengl.h Mon Jan 11 16:51:16 2016 +0200 8.3 @@ -0,0 +1,52 @@ 8.4 +/* 8.5 +Stereoscopic tunnel for iOS. 8.6 +Copyright (C) 2011-2015 John Tsiombikas <nuclear@member.fsf.org> 8.7 + 8.8 +This program is free software: you can redistribute it and/or modify 8.9 +it under the terms of the GNU General Public License as published by 8.10 +the Free Software Foundation, either version 3 of the License, or 8.11 +(at your option) any later version. 8.12 + 8.13 +This program is distributed in the hope that it will be useful, 8.14 +but WITHOUT ANY WARRANTY; without even the implied warranty of 8.15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8.16 +GNU General Public License for more details. 8.17 + 8.18 +You should have received a copy of the GNU General Public License 8.19 +along with this program. If not, see <http://www.gnu.org/licenses/>. 8.20 +*/ 8.21 + 8.22 + 8.23 +#ifndef OPENGL_H_ 8.24 +#define OPENGL_H_ 8.25 + 8.26 +#ifdef HAVE_CONFIG_H_ 8.27 +#include "config.h" 8.28 +#endif 8.29 + 8.30 +#if defined(IPHONE) || defined(__IPHONE__) 8.31 +#include <OpenGLES/ES2/gl.h> 8.32 + 8.33 +#define glClearDepth glClearDepthf 8.34 +#define GLDEF 8.35 +#include "sanegl.h" 8.36 + 8.37 +#elif defined(ANDROID) 8.38 +#include <GLES2/gl2.h> 8.39 +#include <GLES2/gl2ext.h> 8.40 +#define GLDEF 8.41 +#include "sanegl.h" 8.42 + 8.43 +#else 8.44 + 8.45 +#include <GL/glew.h> 8.46 + 8.47 +#ifdef __APPLE__ 8.48 +#include <GLUT/glut.h> 8.49 +#else 8.50 +#include <GL/glut.h> 8.51 +#endif /* __APPLE__ */ 8.52 + 8.53 +#endif /* IPHONE */ 8.54 + 8.55 +#endif /* OPENGL_H_ */