added sphere around the head, removed debugging stuff, 90s look
[hair] / src / hair.cc
1 #include <GL/glew.h>
2
3 #include <float.h>
4 #include <gmath/gmath.h>
5 #include <stdlib.h>
6 #include <string>
7
8 #include "kdtree.h"
9 #include "hair.h"
10
11 /* spring constant */
12
13 #define K_ANC 4.0
14 #define DAMPING 1.5
15
16 struct Triangle {
17         Vec3 v[3];
18         Vec3 n[3];
19 };
20
21 Hair::Hair()
22 {
23         hair_length = 0.5;
24 }
25
26 Hair::~Hair()
27 {
28 }
29
30 static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary)
31 {
32         float u = (float)rand() / (float)RAND_MAX;
33         float v = (float)rand() / (float)RAND_MAX;
34
35         if(u + v > 1) {
36                 u = 1 - u;
37                 v = 1 - v;
38         }
39
40         float c = 1 - (u + v);
41
42         Vec3 rp = u * tr.v[0] + v * tr.v[1] + c * tr.v[2];
43
44         bary->x = u;
45         bary->y = v;
46         bary->z = c;
47
48         return rp;
49 }
50
51 static void get_spawn_triangles(const Mesh *m, float thresh, std::vector<Triangle> *faces)
52 {
53         if (!m) {
54                 fprintf(stderr, "Func: %s, invalid mesh.\n", __func__);
55                 exit(1);
56         }
57         float min_y = FLT_MAX;
58         float max_y = -FLT_MAX;
59
60         for(size_t i=0; i<m->indices.size() / 3; i++) {
61                 bool is_spawn = true;
62                 int idx[3];
63                 for(int j=0; j<3; j++) {
64                         idx[j] = m->indices[i * 3 + j];
65                         float c = (m->colors[idx[j]].x + m->colors[idx[j]].y + m->colors[idx[j]].z) / 3;
66                         if (c >= thresh) {
67                                 is_spawn = false;
68                                 break;
69                         }
70                 }
71
72                 if(is_spawn) {
73                         Triangle t;
74                         for(int j=0; j<3; j++) {
75                                 t.v[j] = m->vertices[idx[j]];
76                                 t.n[j] = m->normals[idx[j]];
77                                 if(t.v[j].y < min_y)
78                                         min_y = t.v[j].y;
79                                 if(t.v[j].y > max_y)
80                                         max_y = t.v[j].y;
81                         }
82                         faces->push_back(t);
83                 }
84         }
85 /*      printf("spawn tri AABB: min y: %f max y: %f\n", min_y, max_y);*/
86 }
87
88 bool Hair::init(const Mesh *m, int max_num_spawns, float thresh)
89 {
90         std::vector<Triangle> faces;
91         kdtree *kd = kd_create(3);
92         const float min_dist = 0.05;
93
94         if(!m) {
95                 fprintf(stderr, "Func %s: invalid mesh.\n", __func__);
96                 return false;
97         }
98
99         get_spawn_triangles(m, thresh, &faces);
100
101         for(int i = 0; i < max_num_spawns; i++) {
102                 // Poisson
103                 int rnum = (float)((float)rand() / (float)RAND_MAX) * faces.size();
104                 Triangle rtriangle = faces[rnum];
105                 Vec3 bary;
106                 Vec3 rpoint = calc_rand_point(rtriangle, &bary);
107
108                 kdres *res = kd_nearest3f(kd, rpoint.x, rpoint.y, rpoint.z);
109
110                 if (res && !kd_res_end(res)) {
111                         Vec3 nearest;
112                         kd_res_item3f(res, &nearest.x, &nearest.y, &nearest.z);
113                         if(distance_sq(rpoint, nearest) < min_dist * min_dist)
114                                 continue;
115                 }
116
117                 HairStrand strand;
118                 /* weighted sum of the triangle's vertex normals */
119                 strand.spawn_dir = normalize(rtriangle.n[0] * bary.x + rtriangle.n[1] * bary.y + rtriangle.n[2] * bary.z);
120                 strand.spawn_pt = rpoint;
121                 hair.push_back(strand);
122
123                 kd_insert3f(kd, rpoint.x, rpoint.y, rpoint.z, 0);
124         }
125
126         kd_free(kd);
127
128         for(size_t i=0; i<hair.size(); i++) {
129                 hair[i].pos = hair[i].spawn_pt + hair[i].spawn_dir * hair_length;
130         }
131         return true;
132 }
133
134 static Vec3 dbg_force;
135 void Hair::draw() const
136 {
137         glPushAttrib(GL_ENABLE_BIT);
138 //      glDisable(GL_DEPTH_TEST);
139         glDisable(GL_LIGHTING);
140         glPointSize(5);
141         glLineWidth(3);
142
143         glBegin(GL_LINES);
144         for(size_t i=0; i<hair.size(); i++) {
145                 glColor3f(1, 0, 1);
146                 Vec3 p = xform * hair[i].spawn_pt;
147                 glVertex3f(p.x, p.y, p.z);
148                 Vec3 dir = normalize(hair[i].pos - p) * hair_length;
149                 Vec3 end = p + dir;
150                 glColor3f(1, 1, 0);
151                 glVertex3f(end.x, end.y, end.z);
152 /*
153                 glColor3f(1, 1, 0);
154                 glVertex3f(hair[i].pos.x, hair[i].pos.y, hair[i].pos.z);
155                 Vec3 fend = hair[i].pos + dbg_force * 2.0;
156                 glVertex3f(fend.x, fend.y, fend.z);
157                 */
158         }
159         glEnd();
160
161         /*
162         glBegin(GL_POINTS);
163         glColor3f(0.5, 1.0, 0.5);
164         for(size_t i = 0; i < hair.size(); i++) {
165                 Vec3 p = xform * (hair[i].spawn_pt + hair[i].spawn_dir * hair_length);
166                 glVertex3f(p.x, p.y, p.z);
167         }
168         glEnd();*/
169
170         glPopAttrib();
171 }
172
173 void Hair::set_transform(Mat4 &xform)
174 {
175         this->xform = xform;
176 }
177
178 void Hair::update(float dt)
179 {
180         for(size_t i = 0; i < hair.size(); i++) {
181                 /* in local space */
182                 Vec3 hair_end = hair[i].spawn_pt + hair[i].spawn_dir * hair_length;
183                 Vec3 anchor = xform * hair_end;
184
185                 Vec3 force = (anchor - hair[i].pos) * K_ANC;
186
187                 Vec3 accel = force; /* mass 1 */
188                 hair[i].velocity += ((-hair[i].velocity * DAMPING) + accel) * dt;
189                 Vec3 new_pos = hair[i].pos + hair[i].velocity * dt;
190
191                 /* collision detection with the head */
192                 Vec3 normal = xform.upper3x3() * hair[i].spawn_dir;
193                 Vec3 root = xform * hair[i].spawn_pt;
194                 Vec3 dir = new_pos - root;
195                 
196                 normal.normalize();
197
198                 /* angle that will cause the hair to be rendered inside the head */
199                 float d = dot(dir, normal);
200                 if(d < 0) {
201                         new_pos += -d * normal;
202                 }
203
204                 hair[i].pos = handle_collision(new_pos);
205
206                 dbg_force = force;
207         }
208 }
209
210 void Hair::add_collider(CollSphere *cobj) {
211         colliders.push_back(cobj);
212 }
213
214 Vec3 Hair::handle_collision(const Vec3 &v) const
215 {
216         /* if we transform the center and the radius of the collider sphere
217          * we might end up with a spheroid, so better just multiply the 
218          * position with the inverse transform before check for collisions :*/
219
220         Vec3 new_v = inverse(xform) * v;
221
222         for(size_t i=0; i<colliders.size(); i++) {
223                 if(colliders[i]->contains(new_v)) {
224                         new_v = colliders[i]->project_surf(new_v);
225                 }
226         }
227         return xform * new_v;
228 }