/* * given a triangle a,b,c, create 4 triangles: * * a * / \ * / \ * d-------e * /\ /\ * / \ / \ * / \ / \ * / \ \ * b-------f-------c * * a,d,e, e,d,f, d,b,f, and e,f,c * */ static void subdivide_triangle(struct mesh *m, int tri) { struct vertex d, e, f, *pa, *pb, *pc, *pd, *pe, *pf; union vec3 vd, ve, vf; int shared, t; pa = m->t[tri].v[0]; pb = m->t[tri].v[1]; pc = m->t[tri].v[2]; vd.v.x = (pa->x + pb->x) / 2.0; vd.v.y = (pa->y + pb->y) / 2.0; vd.v.z = (pa->z + pb->z) / 2.0; ve.v.x = (pa->x + pc->x) / 2.0; ve.v.y = (pa->y + pc->y) / 2.0; ve.v.z = (pa->z + pc->z) / 2.0; vf.v.x = (pb->x + pc->x) / 2.0; vf.v.y = (pb->y + pc->y) / 2.0; vf.v.z = (pb->z + pc->z) / 2.0; vec3_normalize_self(&vd); vec3_normalize_self(&ve); vec3_normalize_self(&vf); d.x = vd.v.x; d.y = vd.v.y; d.z = vd.v.z; e.x = ve.v.x; e.y = ve.v.y; e.z = ve.v.z; f.x = vf.v.x; f.y = vf.v.y; f.z = vf.v.z; pd = lookup_maybe_add_vertex(m, &d, &shared); pe = lookup_maybe_add_vertex(m, &e, &shared); pf = lookup_maybe_add_vertex(m, &f, &shared); /* replace initial triangle with central triangle, e,d,f */ m->t[tri].v[0] = pe; m->t[tri].v[1] = pd; m->t[tri].v[2] = pf; /* add 3 surrounding triangles a,d,e, d,b,f, and e,f,c */ t = m->ntriangles; m->t[t].v[0] = pa; m->t[t].v[1] = pd; m->t[t].v[2] = pe; t++; m->t[t].v[0] = pd; m->t[t].v[1] = pb; m->t[t].v[2] = pf; t++; m->t[t].v[0] = pe; m->t[t].v[1] = pf; m->t[t].v[2] = pc; t++; m->ntriangles = t; }
/* For the +z face of a cubemapped unit sphere, returns tangent and bitangent vectors * See: http://www.iquilezles.org/www/articles/patchedsphere/patchedsphere.htm */ void cubemapped_sphere_tangent_and_bitangent(float x, float y, union vec3 *u, union vec3 *v) { u->v.x = -(1.0f + y * y); u->v.y = x * y; u->v.z = x; vec3_normalize_self(u); v->v.x = x * y; v->v.y = -(1 + x * x); v->v.z = y; vec3_normalize_self(v); }
/* for a plane defined by n=normal, return a u and v vector that is on that plane and perpendictular */ void plane_vector_u_and_v_from_normal(union vec3 *u, union vec3 *v, const union vec3 *n) { union vec3 basis = { { 1, 0, 0 } }; /* find a vector we can use for our basis to define v */ float dot = vec3_dot(n, &basis); if (fabs(dot) >= 1.0 - ZERO_TOLERANCE) { /* if forward is parallel, we can use up */ vec3_init(&basis, 0, 1, 0); } /* find the right vector from our basis and the normal */ vec3_cross(v, &basis, n); vec3_normalize_self(v); /* now the final forward vector is perpendicular n and v */ vec3_cross(u, n, v); vec3_normalize_self(u); }
static void normalize_sphere(struct mesh *m) { int i; for (i = 0; i < m->nvertices; i++) { union vec3 v = { { m->v[i].x, m->v[i].y, m->v[i].z } }; vec3_normalize_self(&v); m->v[i].x = v.v.x; m->v[i].y = v.v.y; m->v[i].y = v.v.y; } m->radius = 1.0; }
static void recursive_add_bump(union vec3 pos, float r, float h, float shrink, float rlimit) { float hoffset; add_bump(pos, r, h); if (r * shrink < rlimit) return; for (int i = 0; i < nbumps; i++) { union vec3 d; d.v.x = snis_random_float() * r * scatterfactor; d.v.y = snis_random_float() * r * scatterfactor; d.v.z = snis_random_float() * r * scatterfactor; vec3_add_self(&d, &pos); vec3_normalize_self(&d); hoffset = snis_random_float() * h * shrink * 0.5; recursive_add_bump(d, r * shrink, h * (shrink + 0.5 * (1.0 - shrink)) + hoffset, shrink, rlimit); } }
void mesh_set_spherical_vertex_normals(struct mesh *m) { int i, j; for (i = 0; i < m->ntriangles; i++) { union vec3 normal; normal = compute_triangle_normal(&m->t[i]); m->t[i].n.x = normal.v.x; m->t[i].n.y = normal.v.y; m->t[i].n.z = normal.v.z; for (j = 0; j < 3; j++) { union vec3 normal = { { m->t[i].v[j]->x, m->t[i].v[j]->y, m->t[i].v[j]->z } }; vec3_normalize_self(&normal); m->t[i].vnormal[j].x = normal.v.x; m->t[i].vnormal[j].y = normal.v.y; m->t[i].vnormal[j].z = normal.v.z; } } }
static union vec3 compute_triangle_normal(struct triangle *t) { union vec3 v1, v2, cross; v1.v.x = t->v[1]->x - t->v[0]->x; v1.v.y = t->v[1]->y - t->v[0]->y; v1.v.z = t->v[1]->z - t->v[0]->z; v2.v.x = t->v[2]->x - t->v[1]->x; v2.v.y = t->v[2]->y - t->v[1]->y; v2.v.z = t->v[2]->z - t->v[1]->z; vec3_cross(&cross, &v1, &v2); vec3_normalize_self(&cross); /* make sure we always have a valid normal */ if (isnan(cross.v.x) || isnan(cross.v.y) || isnan(cross.v.z)) vec3_init(&cross, 0, 1, 0); return cross; }
/* convert from cubemap coords to cartesian coords on surface of sphere */ static union vec3 fij_to_xyz(int f, int i, int j, const int dim) { union vec3 answer; switch (f) { case 0: answer.v.x = (float) (i - dim / 2) / (float) dim; answer.v.y = -(float) (j - dim / 2) / (float) dim; answer.v.z = 0.5; break; case 1: answer.v.x = 0.5; answer.v.y = -(float) (j - dim / 2) / (float) dim; answer.v.z = -(float) (i - dim / 2) / (float) dim; break; case 2: answer.v.x = -(float) (i - dim / 2) / (float) dim; answer.v.y = -(float) (j - dim / 2) / (float) dim; answer.v.z = -0.5; break; case 3: answer.v.x = -0.5; answer.v.y = -(float) (j - dim / 2) / (float) dim; answer.v.z = (float) (i - dim / 2) / (float) dim; break; case 4: answer.v.x = (float) (i - dim / 2) / (float) dim; answer.v.y = 0.5; answer.v.z = (float) (j - dim / 2) / (float) dim; break; case 5: answer.v.x = (float) (i - dim / 2) / (float) dim; answer.v.y = -0.5; answer.v.z = -(float) (j - dim / 2) / (float) dim; break; } vec3_normalize_self(&answer); return answer; }
/* fabricate a tube of length h, radius r, with nfaces, parallel to x axis */ struct mesh *mesh_tube(float h, float r, float nfaces) { struct mesh *m; int ntris = nfaces * 2; int nvertices = nfaces * 2; int i, j; float angle, da; float l = h / 2.0; m = allocate_mesh_for_copy(ntris, nvertices, 0, 1); if (!m) return m; m->geometry_mode = MESH_GEOMETRY_TRIANGLES; da = 2 * M_PI / (float) nfaces; angle = 0.0; for (i = 0; i < nvertices; i += 2) { m->v[i].x = -l; m->v[i].y = r * cos(angle); m->v[i].z = r * -sin(angle); m->v[i + 1].x = l; m->v[i + 1].y = m->v[i].y; m->v[i + 1].z = m->v[i].z; angle += da; } m->nvertices = nvertices; for (i = 0; i < ntris; i += 2) { m->t[i].v[2] = &m->v[i % nvertices]; m->t[i].v[1] = &m->v[(i + 1) % nvertices]; m->t[i].v[0] = &m->v[(i + 2) % nvertices]; m->t[i + 1].v[2] = &m->v[(i + 2) % nvertices]; m->t[i + 1].v[1] = &m->v[(i + 1) % nvertices]; m->t[i + 1].v[0] = &m->v[(i + 3) % nvertices]; } m->ntriangles = ntris; for (i = 0; i < ntris; i++) { union vec3 normal; normal = compute_triangle_normal(&m->t[i]); m->t[i].n.x = normal.v.x; m->t[i].n.y = normal.v.y; m->t[i].n.z = normal.v.z; for (j = 0; j < 3; j++) { union vec3 normal = { { 0, -m->t[i].v[j]->y, -m->t[i].v[j]->z } }; vec3_normalize_self(&normal); m->t[i].vnormal[j].x = normal.v.x; m->t[i].vnormal[j].y = normal.v.y; m->t[i].vnormal[j].z = normal.v.z; } } mesh_set_flat_shading_vertex_normals(m); for (i = 0; i < ntris; i += 2) { mesh_set_triangle_texture_coords(m, i, 0.0, (float) ((int) ((i + 2) / 2)) * 1.0 / (float) nfaces, 1.0, (float) ((int) (i / 2)) / (float) nfaces, 0.0, (float) ((int) (i / 2)) / (float) nfaces); mesh_set_triangle_texture_coords(m, i + 1, 1.0, (float) ((int) ((i + 2) / 2)) / (float) nfaces, 1.0, (float) ((int) (i / 2)) / (float) nfaces, 0.0, (float) ((int) ((i + 2) / 2)) / (float) nfaces); } m->nlines = 0; m->radius = mesh_compute_radius(m); mesh_graph_dev_init(m); return m; }