4 #include <gmath/gmath.h>
30 static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary)
32 float u = (float)rand() / (float)RAND_MAX;
33 float v = (float)rand() / (float)RAND_MAX;
40 float c = 1 - (u + v);
42 Vec3 rp = u * tr.v[0] + v * tr.v[1] + c * tr.v[2];
51 static void get_spawn_triangles(const Mesh *m, float thresh, std::vector<Triangle> *faces)
54 fprintf(stderr, "Func: %s, invalid mesh.\n", __func__);
57 float min_y = FLT_MAX;
58 float max_y = -FLT_MAX;
60 for(size_t i=0; i<m->indices.size() / 3; i++) {
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;
74 for(int j=0; j<3; j++) {
75 t.v[j] = m->vertices[idx[j]];
76 t.n[j] = m->normals[idx[j]];
85 /* printf("spawn tri AABB: min y: %f max y: %f\n", min_y, max_y);*/
88 bool Hair::init(const Mesh *m, int max_num_spawns, float thresh)
90 std::vector<Triangle> faces;
91 kdtree *kd = kd_create(3);
92 const float min_dist = 0.05;
95 fprintf(stderr, "Func %s: invalid mesh.\n", __func__);
99 get_spawn_triangles(m, thresh, &faces);
101 for(int i = 0; i < max_num_spawns; i++) {
103 int rnum = (float)((float)rand() / (float)RAND_MAX) * faces.size();
104 Triangle rtriangle = faces[rnum];
106 Vec3 rpoint = calc_rand_point(rtriangle, &bary);
108 kdres *res = kd_nearest3f(kd, rpoint.x, rpoint.y, rpoint.z);
110 if (res && !kd_res_end(res)) {
112 kd_res_item3f(res, &nearest.x, &nearest.y, &nearest.z);
114 if(distance_sq(rpoint, nearest) < min_dist * min_dist)
119 /* weighted sum of the triangle's vertex normals */
120 strand.spawn_dir = normalize(rtriangle.n[0] * bary.x + rtriangle.n[1] * bary.y + rtriangle.n[2] * bary.z);
121 strand.spawn_pt = rpoint;
122 hair.push_back(strand);
124 kd_insert3f(kd, rpoint.x, rpoint.y, rpoint.z, 0);
129 for(size_t i=0; i<hair.size(); i++) {
130 hair[i].pos = hair[i].spawn_pt + hair[i].spawn_dir * hair_length;
135 static Vec3 dbg_force;
136 void Hair::draw() const
138 glPushAttrib(GL_ENABLE_BIT);
139 // glDisable(GL_DEPTH_TEST);
140 glDisable(GL_LIGHTING);
145 for(size_t i=0; i<hair.size(); i++) {
147 Vec3 p = xform * hair[i].spawn_pt;
148 glVertex3f(p.x, p.y, p.z);
149 Vec3 dir = normalize(hair[i].pos - p) * hair_length;
152 glVertex3f(end.x, end.y, end.z);
155 glVertex3f(hair[i].pos.x, hair[i].pos.y, hair[i].pos.z);
156 Vec3 fend = hair[i].pos + dbg_force * 2.0;
157 glVertex3f(fend.x, fend.y, fend.z);
164 glColor3f(0.5, 1.0, 0.5);
165 for(size_t i = 0; i < hair.size(); i++) {
166 Vec3 p = xform * (hair[i].spawn_pt + hair[i].spawn_dir * hair_length);
167 glVertex3f(p.x, p.y, p.z);
174 void Hair::set_transform(Mat4 &xform)
179 void Hair::update(float dt)
181 for(size_t i = 0; i < hair.size(); i++) {
183 Vec3 hair_end = hair[i].spawn_pt + hair[i].spawn_dir * hair_length;
184 Vec3 anchor = xform * hair_end;
186 Vec3 force = (anchor - hair[i].pos) * K_ANC;
188 Vec3 accel = force; /* mass 1 */
189 hair[i].velocity += ((-hair[i].velocity * DAMPING) + accel) * dt;
190 Vec3 new_pos = hair[i].pos + hair[i].velocity * dt;
192 /* collision detection with the head */
193 Vec3 normal = xform.upper3x3() * hair[i].spawn_dir;
194 Vec3 root = xform * hair[i].spawn_pt;
195 Vec3 dir = new_pos - root;
199 /* angle that will cause the hair to be rendered inside the head */
200 float d = dot(dir, normal);
202 new_pos += -d * normal;
205 hair[i].pos = handle_collision(new_pos);
211 void Hair::add_collider(CollSphere *cobj) {
212 colliders.push_back(cobj);
215 Vec3 Hair::handle_collision(const Vec3 &v) const
217 /* if we transform the center and the radius of the collider sphere
218 * we might end up with a spheroid, so better just multiply the
219 * position with the inverse transform before check for collisions :*/
221 Vec3 new_v = inverse(xform) * v;
223 for(size_t i=0; i<colliders.size(); i++) {
224 if(colliders[i]->contains(new_v)) {
225 new_v = colliders[i]->project_surf(new_v);
228 return xform * new_v;