33bdd0d43f2f41ac91c4d773032ce6d15c619ed2
[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 Hair::~Hair() {}
18
19 static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary)
20 {
21         float u = (float)rand() / (float)RAND_MAX;
22         float v = (float)rand() / (float)RAND_MAX;
23
24         if(u + v > 1) {
25                 u = 1 - u;
26                 v = 1 - v;
27         }
28
29         float c = 1 - (u + v);
30
31         Vec3 rp = u * tr.v[0] + v * tr.v[1] + c * tr.v[2];
32
33         bary->x = u;
34         bary->y = v;
35         bary->z = c;
36
37 //      printf("u %f v %f c %f sum: %f\n", u, v, c, u+v+c);
38         return rp;
39 }
40
41 static void get_spawn_triangles(const Mesh *m, float thresh, std::vector<Triangle> *faces)
42 {
43         if (!m) {
44                 fprintf(stderr, "Func: %s, invalid mesh.\n", __func__);
45                 exit(1);
46         }
47         float min_y = FLT_MAX;
48         float max_y = -FLT_MAX;
49
50         for(size_t i=0; i<m->indices.size() / 3; i++) {
51                 bool is_spawn = true;
52                 int idx[3];
53                 for(int j=0; j<3; j++) {
54                         idx[j] = m->indices[i * 3 + j];
55                         float c = (m->colors[idx[j]].x + m->colors[idx[j]].y + m->colors[idx[j]].z) / 3;
56                         if (c >= thresh) {
57                                 is_spawn = false;
58                                 break;
59                         }
60                 }
61
62                 if(is_spawn) {
63                         Triangle t;
64                         for(int j=0; j<3; j++) {
65                                 t.v[j] = m->vertices[idx[j]];
66                                 t.n[j] = m->normals[idx[j]];
67                                 if(t.v[j].y < min_y)
68                                         min_y = t.v[j].y;
69                                 if(t.v[j].y > max_y)
70                                         max_y = t.v[j].y;
71                         }
72                         faces->push_back(t);
73                 }
74         }
75         printf("spawn tri AABB: min y: %f max y: %f\n", min_y, max_y);
76 }
77
78 bool Hair::init(const Mesh *m, int max_num_spawns, float thresh)
79 {
80         std::vector<Triangle> faces;
81         kdtree *kd = kd_create(3);
82         const float min_dist = 0.05;
83
84         if(!m) {
85                 fprintf(stderr, "Func %s: invalid mesh.\n", __func__);
86                 return false;
87         }
88
89         get_spawn_triangles(m, thresh, &faces);
90
91         for(int i = 0; i < max_num_spawns; i++) {
92                 // Poisson
93                 int rnum = (float)((float)rand() / (float)RAND_MAX) * faces.size();
94                 Triangle rtriangle = faces[rnum];
95                 Vec3 bary;
96                 Vec3 rpoint = calc_rand_point(rtriangle, &bary);
97
98                 kdres *res = kd_nearest3f(kd, rpoint.x, rpoint.y, rpoint.z);
99
100                 if (res && !kd_res_end(res)) {
101                         Vec3 nearest;
102                         kd_res_item3f(res, &nearest.x, &nearest.y, &nearest.z);
103                         if(distance_sq(rpoint, nearest) < min_dist * min_dist)
104                                 continue;
105                 }
106
107                 /* weighted sum of the triangle's vertex normals */
108                 Vec3 spawn_dir = rtriangle.n[0] * bary.x + rtriangle.n[1] * bary.y + rtriangle.n[2] * bary.z;
109                 spawn_directions.push_back(normalize(spawn_dir));
110                 spawn_points.push_back(rpoint);
111                 kd_insert3f(kd, rpoint.x, rpoint.y, rpoint.z, 0);
112         }
113
114         kd_free(kd);
115         return true;
116 }
117
118 void Hair::draw() const
119 {
120         glPushAttrib(GL_ENABLE_BIT);
121         glDisable(GL_DEPTH_TEST);
122         glDisable(GL_LIGHTING);
123         glPointSize(2);
124         glBegin(GL_POINTS);
125         for(size_t i = 0; i < spawn_points.size(); i++) {
126                 glColor3f(1, 1, 0);
127                 glVertex3f(spawn_points[i].x, spawn_points[i].y, spawn_points[i].z);
128         }
129         glEnd();
130         glPopAttrib();
131 }