added forces + damping, k factors
[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                 /* orthonormal basis */
132                 Vec3 vk = hair[i].spawn_dir;
133                 Vec3 vi = Vec3(1, 0, 0);
134                 if(fabs(vk.x > 0.99)) {
135                         vi = Vec3(0, -1, 0);
136                 }
137                 Vec3 vj = normalize(cross(vk, vi));
138                 vi = cross(vj, vk);
139
140                 /* identity when the hair points to the z axis */
141                 Mat4 basis = Mat4(vi, vj, vk);
142
143                 for(int j=0; j<3; j++) {
144                         float angle = (float)j / 3.0 * 2 * M_PI;
145                         /* dir of each anchor relative to hair root */
146                         Vec3 dir = Vec3(cos(angle), sin(angle), 0);
147                         dir = basis * dir;
148                         hair[i].anchor_dirs[j] = hair[i].pos + dir - hair[i].spawn_pt;
149                 }
150         }
151         return true;
152 }
153
154 static Vec3 dbg_force;
155 void Hair::draw() const
156 {
157         glPushAttrib(GL_ENABLE_BIT);
158 //      glDisable(GL_DEPTH_TEST);
159         glDisable(GL_LIGHTING);
160         glPointSize(5);
161         glLineWidth(3);
162
163         glBegin(GL_LINES);
164         for(size_t i=0; i<hair.size(); i++) {
165                 glColor3f(1, 0, 1);
166                 Vec3 p = xform * hair[i].spawn_pt;
167                 glVertex3f(p.x, p.y, p.z);
168                 Vec3 dir = normalize(hair[i].pos - p) * hair_length;
169                 Vec3 end = p + dir;
170                 glVertex3f(end.x, end.y, end.z);
171 /*
172                 glColor3f(1, 1, 0);
173                 glVertex3f(hair[i].pos.x, hair[i].pos.y, hair[i].pos.z);
174                 Vec3 end = hair[i].pos + dbg_force * 2.0;
175                 glVertex3f(end.x, end.y, end.z);
176                 */
177         }
178         glEnd();
179
180         /*
181         glBegin(GL_POINTS);
182         glColor3f(0.5, 1.0, 0.5);
183         for(size_t i = 0; i < hair.size(); i++) {
184                 Vec3 p = xform * (hair[i].spawn_pt + hair[i].spawn_dir * hair_length);
185                 glVertex3f(p.x, p.y, p.z);
186         }
187         glEnd();*/
188
189         glPopAttrib();
190 }
191
192 void Hair::set_transform(Mat4 &xform)
193 {
194         this->xform = xform;
195 }
196
197 void Hair::update(float dt)
198 {
199         for(size_t i = 0; i < hair.size(); i++) {
200                 /* in local space */
201                 Vec3 hair_end = hair[i].spawn_pt + hair[i].spawn_dir * hair_length;
202                 Vec3 anchor = xform * hair_end;
203
204                 Vec3 force = (anchor - hair[i].pos) * K_ANC;
205
206                 Vec3 accel = force; /* mass 1 */
207                 hair[i].velocity += ((-hair[i].velocity * DAMPING) + accel) * dt;
208                 hair[i].pos += hair[i].velocity * dt;
209
210                 dbg_force = force;
211         }
212 }