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_ */