t_mat4 m4_look_at(t_vec3 from, t_vec3 to, t_vec3 up) { t_vec3 x; t_vec3 y; t_vec3 z; z = v3_muls(v3_norm(v3_sub(to, from)), -1); x = v3_norm(v3_cross(up, z)); y = v3_cross(z, x); return (mat4( x.x, x.y, x.z, -v3_dot(from, x), y.x, y.y, y.z, -v3_dot(from, y), z.x, z.y, z.z, -v3_dot(from, z), 0, 0, 0, 1 )); }
Vector3 sph_coord(Vector3 r) { Real len = v3_norm(r); Real theta = atan2(r.y/len, r.x/len); Real phi = asin(r.z/len); return v3_make(theta, phi, len); }
static void tri_refine(Vector3 v0, Vector3 v1, Vector3 v2, Real s, int maxrec) { Real l1 = v3_norm(v3_sub(v0, v1)); Real l2 = v3_norm(v3_sub(v1, v2)); Real l3 = v3_norm(v3_sub(v2, v0)); if ((MAX(l1, MAX(l2, l3))) <= s || --maxrec < 0) { plist = poly_insert(plist, poly3_make(v0, v1, v2)); } else { Vector3 m1 = v3_scale(0.5, v3_add(v0, v1)); Vector3 m2 = v3_scale(0.5, v3_add(v1, v2)); Vector3 m3 = v3_scale(0.5, v3_add(v2, v0)); tri_refine(m1, v1, m2, s, maxrec); tri_refine(m2, v2, m3, s, maxrec); tri_refine(m3, v0, m1, s, maxrec); tri_refine(m1, m2, m3, s, maxrec); } }
hit_test intersect(ray r, object obj) { v3 ro = r.origin; v3 rd = r.direction; double t; hit_test ht_out; switch (obj.tag) { case SPHERE: { v3 sc = obj.o.s.center; double sr = obj.o.s.radius; v3 A = v3_sub(ro, sc); double B = v3_dot(A, rd); double C = v3_dot(A, A) - sr*sr; double D = B*B - C; t = -B - sqrt(D); if (D > 0 && t > 0) { v3 ray_pos = ray_position(r, t); ht_out.miss = HIT; ht_out.t = t; ht_out.hit_point = ray_pos; ht_out.surf = \ (*(obj.o.s.surface_color))(obj.o.s.center, ray_pos); ht_out.shine = obj.o.s.shine; ht_out.surf_norm = v3_norm(v3_sub(ray_pos, obj.o.s.center)); } else { ht_out.miss = MISS; } break; } case POSTER: { v3 n = v3_expr(0, 0, -1); double d = obj.o.p.upper_left.z; t = -(v3_dot(ro, n) + d) / v3_dot(rd, n); v3 ray_pos = ray_position(r, t); if (t > 0 && is_on_poster(ray_pos, obj.o.p)) { ht_out.miss = HIT; ht_out.t = t; ht_out.hit_point = ray_pos; ht_out.surf = \ (*(obj.o.p.surface_color))(obj.o.p.upper_left, ray_pos); ht_out.shine = obj.o.p.shine; ht_out.surf_norm = n; } else { ht_out.miss = MISS; } break; } default: fprintf(stderr, "error in intersect: unrecognized tag\n"); exit(1); } return ht_out; }
hit_test intersect_cylinder (ray r, cylinder c) { hit_test result; v3 rp = v3_expr(r.direction.x,0,r.direction.z); double mp = v3_mag(rp); v3 np = v3_norm(rp); double xbar = r.origin.x - c.center.x; double zbar = r.origin.z - c.center.z; double a = pow(np.x,2) + pow(np.z,2); double b = 2 * ( (xbar*np.x) + (zbar*np.z) ); double c1 = pow(xbar,2) + pow(zbar,2) - pow(c.radius,2); double d = pow(b,2) - (4*a*c1); result.miss = MISS; if(d >= 0) { double t_front = (-b - sqrt(d)) / (2*a); double t_back = (-b + sqrt(d)) / (2*a); v3 p_front = ray_position(r, t_front/mp); v3 p_back = ray_position(r, t_back/mp); if( (t_front < t_back) && (t_front > 0) && (p_front.y >= c.center.y) && (on_cylinder(p_front, c))) { result.miss = HIT; result.t = (t_front/mp); result.hit_point = p_front; result.surf = c.surface_color(c.center, p_front); result.shine = c.shine; v3 c2 = v3_expr(c.center.x, p_front.y, c.center.z); result.surf_norm = v3_norm(v3_sub(p_front,c2)); } else if( (t_back > 0) && (p_back.y >= c.center.y) && (on_cylinder(p_back, c)) ) { result.miss = HIT; result.t = (t_back/mp); result.hit_point = p_back; result.surf = c.surface_color(c.center, p_back); result.shine = c.shine; v3 c3 = v3_expr(c.center.x, p_back.y, c.center.z); result.surf_norm = v3_norm(v3_sub(c3,p_back)); } } return result; }
void line_projection3d_p(v3 *a, v3 *b, v3 *p, v3 *out) { v3 BmA, PmA, res; DAFLOAT coef, normed, doted; v3_diff_p(b, a, &BmA); v3_diff_p(p, a, &PmA); doted = v3_dot_p(&BmA, &PmA); normed = v3_norm(BmA); normed = normed * normed; coef = doted / normed; v3_mult_p(&BmA, coef, &res); v3_sum_p(a, &res, out); }
void makeviewVi(void) { Vector3 n,u,v,t; view->Vinv = m4_ident(); n = view->normal; v = v3_sub(view->up, v3_scale(v3_dot(view->up, n), n)); if (v3_norm(v) < ROUNDOFF) error("view up parallel to view normal"); v = v3_unit(v); u = v3_cross(n, v); t = view->center; view->Vinv = m4_ident(); view->Vinv.r1.x = u.x; view->Vinv.r2.x = u.y; view->Vinv.r3.x = u.z; view->Vinv.r1.y = v.x; view->Vinv.r2.y = v.y; view->Vinv.r3.y = v.z; view->Vinv.r1.z = n.x; view->Vinv.r2.z = n.y; view->Vinv.r3.z = n.z; view->Vinv.r1.w = t.x; view->Vinv.r2.w = t.y; view->Vinv.r3.w = t.z; }
void display_generate_line(int subDiv, t_v3* min, t_v3* max, float sphere_radius, uint8* vb, t_mesh_definition* def, uint16* ib, uint16 start) { t_v3 direction; t_v3 normal; v3_set(&normal, 0, 0, 1); v3_sub(max, min, &direction); v3_norm(&direction, &direction); v3_cross(&direction, &normal, &normal); normal.x *= sphere_radius; normal.y *= sphere_radius; normal.z *= sphere_radius; float vs[] = { min->x - normal.x, min->y - normal.y, min->z, min->x + normal.x, min->y + normal.y, min->z, max->x - normal.x, max->y - normal.y, max->z, max->x + normal.x, max->y + normal.y, max->z, }; float* vsp = vs; int32 i; for (i = 0; i < 4; ++i) { t_v3* v = (t_v3*)(vb + def->vertex_offset); t_v3* n = (t_v3*)(vb + def->normal_offset); v3_set(v, *vsp, *(vsp + 1), *(vsp + 2)); vsp += 3; if (def->normal_offset != -1) v3_set(n, 0.0f, 0.0f, 1.0f); vb += def->stride; } *ib++ = start + 0; *ib++ = start + 1; *ib++ = start + 3; *ib++ = start + 0; *ib++ = start + 3; *ib++ = start + 2; }
t_mat4 m4_rotation(float angle_in_rad, t_vec3 axis) { t_vec3 normalized_axis; t_vec3 xyz; float c; float s; normalized_axis = v3_norm(axis); xyz.x = normalized_axis.x; xyz.y = normalized_axis.y; xyz.z = normalized_axis.z; c = cosf(angle_in_rad); s = sinf(angle_in_rad); return (mat4( c + xyz.x * xyz.x * (1 - c), xyz.x * xyz.y * (1 - c) - xyz.z * s, xyz.x * xyz.z * (1 - c) + xyz.y * s, 0, xyz.y * xyz.x * (1 - c) + xyz.z * s, c + xyz.y * xyz.y * (1 - c), xyz.y * xyz.z * (1 - c) - xyz.x * s, 0, xyz.z* xyz.x * (1 - c) - xyz.y * s, xyz.z * xyz.y * (1 - c) + xyz.x * s, c + xyz.z * xyz.z * (1 - c), 0, 0, 0, 0, 1 )); }
hit_test intersect_sphere (ray r, sphere s) { hit_test result = {0}; v3 sc = s.center; double sr = s.radius; v3 a = v3_sub(r.origin, sc); double b = v3_dot(a, r.direction); double c = v3_dot(a, a) - (sr * sr); double d = (b * b) - c; double t = -b - sqrt(d); result.miss = MISS; if (d > 0 && t > 0) { v3 intersection = ray_position(r, t); result.miss = HIT; result.t = t; result.hit_point = intersection; result.surf = s.surface_color(sc, intersection); result.shine = s.shine; result.surf_norm = v3_norm(v3_sub(intersection, sc)); } return result; }
void display_generate_sphere(int subDiv, t_v3* center, float sphere_radius, uint8* vb, t_mesh_definition* def, uint16* ib, uint16 start) { float pi = DISPLAY_M_PI; int32 i, j; for (i = 0; i < subDiv; ++i) { float theta = (float)i / (subDiv - 1); for (j = 0; j < subDiv; ++j) { float phi = (float)j / subDiv; float radius = sinf(theta * pi) * sphere_radius; t_v3* v = (t_v3*)(vb + def->vertex_offset); t_v3* n = (t_v3*)(vb + def->normal_offset); v->x = sinf(phi * 2.0f * pi) * radius; v->y = cosf(phi * 2.0f * pi) * radius; v->z = cosf(theta * pi) * sphere_radius; if (def->normal_offset != -1) v3_norm(v, n); v3_add(v, center, v); vb += def->stride; } } for (i = 0; i < subDiv - 1; ++i) { for (j = 0; j < subDiv; ++j) { int32 i0 = start + (i + 0) * subDiv + j; int32 i1 = start + (i + 1) * subDiv + j; int32 i2 = start + (i + 1) * subDiv + ((j + 1) % subDiv); int32 i3 = start + (i + 0) * subDiv + ((j + 1) % subDiv); *ib++ = i0, *ib++ = i1, *ib++ = i2; *ib++ = i0, *ib++ = i2, *ib++ = i3; } } }
void makeviewV(void) { Vector3 n,u,v,t; n = view->normal; v = v3_sub(view->up, v3_scale(v3_dot(view->up, n), n)); if (v3_norm(v) < ROUNDOFF) error("view up parallel to view normal"); v = v3_unit(v); u = v3_cross(n, v); v = v3_cross(u, n); n = v3_scale(-1.0, n); t.x = v3_dot(view->center, u); t.y = v3_dot(view->center, v); t.z = v3_dot(view->center, n); view->V = m4_ident(); view->V.r1.x = u.x; view->V.r2.x = v.x; view->V.r3.x = n.x; view->V.r1.y = u.y; view->V.r2.y = v.y; view->V.r3.y = n.y; view->V.r1.z = u.z; view->V.r2.z = v.z; view->V.r3.z = n.z; view->V.r1.w = -t.x; view->V.r2.w = -t.y; view->V.r3.w = -t.z; makeviewVi(); }
void camera_setup( camera_t * const c, v3_t eye, v3_t lookat, v3_t up, float fov ) { // compute the basis for the camera // negative look direction from eye to destination v3_t w = v3_norm(v3_sub(eye, lookat)); // compute the side axis v3_t u = v3_norm(v3_cross(up, w)); // and the "up" normal v3_t v = v3_norm(v3_cross(w, u)); m44_t cam = {{ { u.p[0], u.p[1], u.p[2], -v3_dot(u,eye) }, { v.p[0], v.p[1], v.p[2], -v3_dot(v,eye) }, { w.p[0], w.p[1], w.p[2], -v3_dot(w,eye) }, { 0, 0, 0, 1 }, }}; fprintf(stderr, "Camera:\n"); for(int i = 0 ; i < 4 ; i++) { for(int j = 0 ; j < 4 ; j++) fprintf(stderr, " %+5.3f", cam.m[i][j]); fprintf(stderr, "\n"); } // now compute the perspective projection matrix if(1) { float s = 1000.0 / tan(fov * M_PI / 180 / 2); c->near = 1; c->far = 200; float f1 = - c->far / (c->far - c->near); float f2 = - c->far * c->near / (c->far - c->near); m44_t pers = {{ { s, 0, 0, 0 }, { 0, s, 0, 0 }, { 0, 0, f2, -1 }, { 0, 0, f1, 0 }, }}; fprintf(stderr, "Perspective:\n"); for(int i = 0 ; i < 4 ; i++) { for(int j = 0 ; j < 4 ; j++) fprintf(stderr, " %+5.3f", pers.m[i][j]); fprintf(stderr, "\n"); } m44_mult(&c->r, &pers, &cam); } else { // no perspective m44_t pers = {{ { 1, 0, 0, 0 }, { 0, 1, 0, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 1 }, }}; // and apply it to the camera matrix to generate transform m44_mult(&c->r, &pers, &cam); } fprintf(stderr, "Cam*Pers\n"); for(int i = 0 ; i < 4 ; i++) { for(int j = 0 ; j < 4 ; j++) fprintf(stderr, " %+5.3f", c->r.m[i][j]); fprintf(stderr, "\n"); } }
int torus_classify(Prim *p, Vector3 q) { Vector3 w = v3_m4mult(q, p->ti); Real d = v3_norm(w); return (d < 1)? PRIM_IN : ((d > 1)? PRIM_OUT : PRIM_ON); }
static void find_normal( const stl_3d_t * const stl, const stl_vertex_t * const v, const float inset_distance, v3_t * const avg ) { int * const face_used = calloc(sizeof(*face_used), stl->num_face); // generate all of the coplanar polygons at this vertex const stl_vertex_t ** const vertex_list = calloc(sizeof(**vertex_list), stl->num_vertex); for (int j = 0 ; j < v->num_face; j++) { // generate the polygon face for this vertex const stl_face_t * const f = v->face[j]; if (face_used[f - stl->face]) continue; //ref.origin.p[0] = 0; //ref.origin.p[1] = 0; //ref.origin.p[2] = 0; const int start_vertex = v->face_num[j]; const int vertex_count = stl_trace_face( stl, f, vertex_list, face_used, start_vertex ); // find this vertex in the vertex list // and compute the vector that subdivides the // two outbound edges for (int k = 0 ; k < vertex_count ; k++) { if (vertex_list[k] != v) continue; v3_t p1 = vertex_list[(k+vertex_count-1) % vertex_count]->p; v3_t p2 = vertex_list[k % vertex_count]->p; v3_t p3 = vertex_list[(k+1) % vertex_count]->p; refframe_t ref; refframe_init( &ref, p2, p3, p1 ); double x, y; refframe_inset(&ref, inset_distance, &x, &y, p1, p2, p3); v3_t hole = refframe_project(&ref, (v3_t){{x,y,0}}); //hole = refframe_project(&ref, (v3_t){{10,0,0}}); //hole.p[0] = 10*ref.x.p[0]; // + ref.origin.p[0]; //hole.p[1] = 10*ref.x.p[1]; // + ref.origin.p[1]; //hole.p[2] = 10*ref.x.p[2]; // + ref.origin.p[2]; fprintf(stderr, "**** %p [%f,%f]=>%f,%f,%f\n", v, x, y, hole.p[0], hole.p[1], hole.p[2] ); //*avg = v3_add(*avg, ref.z); *avg = v3_add(*avg, v3_norm(v3_sub(ref.origin, hole))); //*avg = v3_add(*avg, (v3_sub(hole, ref.origin))); } } free(face_used); free(vertex_list); }