X-Git-Url: http://git.mutantstargoat.com?p=hair;a=blobdiff_plain;f=src%2Fhair.cc;h=b99d133994ac0028d5fde2b6f13bf7db68f4634e;hp=e4843fb0c9168a058946e31cb6e1e45c6e68d5ef;hb=a65a977df6fa8fee831c91cdc754d62e023b6630;hpb=da5cbacf755273da510c37c819a59c7fe9894c4e diff --git a/src/hair.cc b/src/hair.cc index e4843fb..b99d133 100644 --- a/src/hair.cc +++ b/src/hair.cc @@ -1,3 +1,6 @@ +#include + +#include #include #include #include @@ -5,13 +8,24 @@ #include "kdtree.h" #include "hair.h" +/* spring constant */ + +#define K_ANC 4.0 +#define DAMPING 1.5 + struct Triangle { Vec3 v[3]; Vec3 n[3]; }; -Hair::Hair() {} -Hair::~Hair() {} +Hair::Hair() +{ + hair_length = 0.5; +} + +Hair::~Hair() +{ +} static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary) { @@ -25,7 +39,7 @@ static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary) float c = 1 - (u + v); - Vec3 rp = u * tr.v[0] + v * tr.v[1] + c * tr.v[3]; + Vec3 rp = u * tr.v[0] + v * tr.v[1] + c * tr.v[2]; bary->x = u; bary->y = v; @@ -36,11 +50,18 @@ static Vec3 calc_rand_point(const Triangle &tr, Vec3 *bary) static void get_spawn_triangles(const Mesh *m, float thresh, std::vector *faces) { + if (!m) { + fprintf(stderr, "Func: %s, invalid mesh.\n", __func__); + exit(1); + } + float min_y = FLT_MAX; + float max_y = -FLT_MAX; + for(size_t i=0; iindices.size() / 3; i++) { bool is_spawn = true; int idx[3]; for(int j=0; j<3; j++) { - idx[j] = i * 3 + j; + idx[j] = m->indices[i * 3 + j]; float c = (m->colors[idx[j]].x + m->colors[idx[j]].y + m->colors[idx[j]].z) / 3; if (c >= thresh) { is_spawn = false; @@ -53,10 +74,15 @@ static void get_spawn_triangles(const Mesh *m, float thresh, std::vectorvertices[idx[j]]; t.n[j] = m->normals[idx[j]]; + if(t.v[j].y < min_y) + min_y = t.v[j].y; + if(t.v[j].y > max_y) + max_y = t.v[j].y; } faces->push_back(t); } } +/* printf("spawn tri AABB: min y: %f max y: %f\n", min_y, max_y);*/ } bool Hair::init(const Mesh *m, int max_num_spawns, float thresh) @@ -65,6 +91,11 @@ bool Hair::init(const Mesh *m, int max_num_spawns, float thresh) kdtree *kd = kd_create(3); const float min_dist = 0.05; + if(!m) { + fprintf(stderr, "Func %s: invalid mesh.\n", __func__); + return false; + } + get_spawn_triangles(m, thresh, &faces); for(int i = 0; i < max_num_spawns; i++) { @@ -75,24 +106,109 @@ bool Hair::init(const Mesh *m, int max_num_spawns, float thresh) Vec3 rpoint = calc_rand_point(rtriangle, &bary); kdres *res = kd_nearest3f(kd, rpoint.x, rpoint.y, rpoint.z); - if (!kd_res_end(res)) { + + if (res && !kd_res_end(res)) { Vec3 nearest; kd_res_item3f(res, &nearest.x, &nearest.y, &nearest.z); if(distance_sq(rpoint, nearest) < min_dist * min_dist) continue; } + HairStrand strand; /* weighted sum of the triangle's vertex normals */ - Vec3 spawn_dir = rtriangle.n[0] * bary.x + rtriangle.n[1] * bary.y + rtriangle.n[2] * bary.z; - spawn_directions.push_back(normalize(spawn_dir)); - spawn_points.push_back(rpoint); + strand.spawn_dir = normalize(rtriangle.n[0] * bary.x + rtriangle.n[1] * bary.y + rtriangle.n[2] * bary.z); + strand.spawn_pt = rpoint; + hair.push_back(strand); + kd_insert3f(kd, rpoint.x, rpoint.y, rpoint.z, 0); } kd_free(kd); + + for(size_t i=0; ixform = xform; +} + +void Hair::update(float dt) +{ + for(size_t i = 0; i < hair.size(); i++) { + /* in local space */ + Vec3 hair_end = hair[i].spawn_pt + hair[i].spawn_dir * hair_length; + Vec3 anchor = xform * hair_end; + + Vec3 force = (anchor - hair[i].pos) * K_ANC; + + Vec3 accel = force; /* mass 1 */ + hair[i].velocity += ((-hair[i].velocity * DAMPING) + accel) * dt; + Vec3 new_pos = hair[i].pos + hair[i].velocity * dt; + + hair[i].pos = handle_collision(new_pos); + + dbg_force = force; + } +} + +void Hair::add_collider(CollSphere *cobj) { + colliders.push_back(cobj); +} + +Vec3 Hair::handle_collision(const Vec3 &v) const +{ + /* if we transform the center and the radius of the collider sphere + * we might end up with a spheroid, so better just multiply the + * position with the inverse transform before check for collisions :*/ + + Vec3 new_v = inverse(xform) * v; + + for(size_t i=0; icontains(new_v)) { + new_v = colliders[i]->project_surf(new_v); + } + } + return xform * new_v; }