quick backup, commented out some printfs
[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 struct Triangle {
12         Vec3 v[3];
13         Vec3 n[3];
14 };
15
16 Hair::Hair()
17 {
18         hair_length = 0.5;
19 }
20
21 Hair::~Hair()
22 {
23 }
24
25 static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary)
26 {
27         float u = (float)rand() / (float)RAND_MAX;
28         float v = (float)rand() / (float)RAND_MAX;
29
30         if(u + v > 1) {
31                 u = 1 - u;
32                 v = 1 - v;
33         }
34
35         float c = 1 - (u + v);
36
37         Vec3 rp = u * tr.v[0] + v * tr.v[1] + c * tr.v[2];
38
39         bary->x = u;
40         bary->y = v;
41         bary->z = c;
42
43         return rp;
44 }
45
46 static void get_spawn_triangles(const Mesh *m, float thresh, std::vector<Triangle> *faces)
47 {
48         if (!m) {
49                 fprintf(stderr, "Func: %s, invalid mesh.\n", __func__);
50                 exit(1);
51         }
52         float min_y = FLT_MAX;
53         float max_y = -FLT_MAX;
54
55         for(size_t i=0; i<m->indices.size() / 3; i++) {
56                 bool is_spawn = true;
57                 int idx[3];
58                 for(int j=0; j<3; j++) {
59                         idx[j] = m->indices[i * 3 + j];
60                         float c = (m->colors[idx[j]].x + m->colors[idx[j]].y + m->colors[idx[j]].z) / 3;
61                         if (c >= thresh) {
62                                 is_spawn = false;
63                                 break;
64                         }
65                 }
66
67                 if(is_spawn) {
68                         Triangle t;
69                         for(int j=0; j<3; j++) {
70                                 t.v[j] = m->vertices[idx[j]];
71                                 t.n[j] = m->normals[idx[j]];
72                                 if(t.v[j].y < min_y)
73                                         min_y = t.v[j].y;
74                                 if(t.v[j].y > max_y)
75                                         max_y = t.v[j].y;
76                         }
77                         faces->push_back(t);
78                 }
79         }
80 /*      printf("spawn tri AABB: min y: %f max y: %f\n", min_y, max_y);*/
81 }
82
83 bool Hair::init(const Mesh *m, int max_num_spawns, float thresh)
84 {
85         std::vector<Triangle> faces;
86         kdtree *kd = kd_create(3);
87         const float min_dist = 0.05;
88
89         if(!m) {
90                 fprintf(stderr, "Func %s: invalid mesh.\n", __func__);
91                 return false;
92         }
93
94         get_spawn_triangles(m, thresh, &faces);
95
96         for(int i = 0; i < max_num_spawns; i++) {
97                 // Poisson
98                 int rnum = (float)((float)rand() / (float)RAND_MAX) * faces.size();
99                 Triangle rtriangle = faces[rnum];
100                 Vec3 bary;
101                 Vec3 rpoint = calc_rand_point(rtriangle, &bary);
102
103                 kdres *res = kd_nearest3f(kd, rpoint.x, rpoint.y, rpoint.z);
104
105                 if (res && !kd_res_end(res)) {
106                         Vec3 nearest;
107                         kd_res_item3f(res, &nearest.x, &nearest.y, &nearest.z);
108                         if(distance_sq(rpoint, nearest) < min_dist * min_dist)
109                                 continue;
110                 }
111
112                 HairStrand strand;
113                 /* weighted sum of the triangle's vertex normals */
114                 strand.spawn_dir = normalize(rtriangle.n[0] * bary.x + rtriangle.n[1] * bary.y + rtriangle.n[2] * bary.z);
115                 strand.spawn_pt = rpoint;
116                 hair.push_back(strand);
117
118                 kd_insert3f(kd, rpoint.x, rpoint.y, rpoint.z, 0);
119         }
120
121         kd_free(kd);
122
123         for(size_t i=0; i<hair.size(); i++) {
124                 hair[i].pos = hair[i].spawn_pt + hair[i].spawn_dir * hair_length;
125                 
126                 /* orthonormal basis */
127                 Vec3 vk = hair[i].spawn_dir;
128                 Vec3 vi = Vec3(1, 0, 0);
129                 if(fabs(vk.x > 0.99)) {
130                         vi = Vec3(0, -1, 0);
131                 }
132                 Vec3 vj = normalize(cross(vk, vi));
133                 vi = cross(vj, vk);
134
135                 /* identity when the hair points to the z axis */
136                 Mat4 basis = Mat4(vi, vj, vk);
137
138                 for(int j=0; j<3; j++) {
139                         float angle = (float)j / 3.0 * 2 * M_PI;
140                         /* dir of each anchor relative to hair end */
141                         Vec3 dir = Vec3(cos(angle), sin(angle), 0);
142                         dir = basis * dir;
143                         hair[i].anchor_dirs[j] = hair[i].pos + dir - hair[i].spawn_pt;
144                 }
145         }
146         return true;
147 }
148
149 void Hair::draw() const
150 {
151         glPushAttrib(GL_ENABLE_BIT);
152 //      glDisable(GL_DEPTH_TEST);
153         glDisable(GL_LIGHTING);
154         glPointSize(5);
155         glLineWidth(2);
156
157         glBegin(GL_LINES);
158         for(size_t i=0; i<hair.size(); i++) {
159                 glColor3f(1, 0, 1);
160                 glVertex3f(hair[i].pos.x, hair[i].pos.y, hair[i].pos.z);
161                 Vec3 p = hair[i].spawn_pt;
162                 glVertex3f(p.x, p.y, p.z);
163         }
164         glEnd();
165
166         glBegin(GL_POINTS);
167         glColor3f(0.5, 1.0, 0.5);
168         for(size_t i=0; i<hair.size(); i++) {
169                 for(int j=0; j<3; j++) {
170                         Vec3 p = hair[i].spawn_pt + hair[i].anchor_dirs[j];
171                         glVertex3f(p.x, p.y, p.z);
172                 }
173         }
174         glEnd();
175
176         glPopAttrib();
177 }
178
179 void Hair::set_transform(Mat4 &xform)
180 {
181         this->xform = xform;
182 }