/* This is basically Cramer's rule, but with vector calculus. */ static bool ray_triangle_intersect(Ray ray, Vec3 u, Vec3 v, Vec3 w, struct TriangleHit *tri_hit) { Vec3 edge1, edge2, tvec, pvec, qvec; float det; float aa, bb, cc; edge1 = vec3_sub(v, u); edge2 = vec3_sub(w, u); pvec = vec3_cross(ray.direction, edge2); det = vec3_dot(edge1, pvec); tvec = vec3_sub(ray.origin, u); bb = vec3_dot(tvec, pvec) / det; if (bb < 0.0 || bb > 1.0) return false; qvec = vec3_cross(tvec, edge1); cc = vec3_dot(ray.direction, qvec) / det; if (cc < 0.0 || cc + bb > 1.0) return false; aa = 1.0 - bb - cc; tri_hit->a = aa; tri_hit->b = bb; tri_hit->c = cc; tri_hit->t = vec3_dot(edge2, qvec) / det; return true; }
/* calculate sphere that goes through 4 points */ struct sphere* sphere_circum(struct sphere* rs, const struct vec4f* v0, const struct vec4f* v1, const struct vec4f* v2, const struct vec4f* v3) { struct vec4f a; vec3_sub(&a, v1, v0); struct vec4f b; vec3_sub(&b, v2, v0); struct vec4f c; vec3_sub(&c, v3, v0); struct vec4f o; struct vec4f tmp; struct mat3f m; mat3_setf(&m, a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z, 0.0f, 0.0f, 0.0f); float denom = 2.0f * mat3_det(&m); vec3_muls(&o, vec3_cross(&tmp, &a, &b), vec3_dot(&c, &c)); vec3_add(&o, &o, vec3_muls(&tmp, vec3_cross(&tmp, &c, &a), vec3_dot(&b, &b))); vec3_add(&o, &o, vec3_muls(&tmp, vec3_cross(&tmp, &b, &c), vec3_dot(&a, &a))); vec3_muls(&o, &o, 1.0f/denom); return sphere_setf(rs, v0->x + o.x, v0->y + o.y, v0->z + o.z, vec3_len(&o) + EPSILON); }
static box_t get_box(const vec3_t *p0, const vec3_t *p1, const vec3_t *n, float r, const plane_t *plane) { mat4_t rot; box_t box; if (p1 == NULL) { box = bbox_from_extents(*p0, r, r, r); box = box_swap_axis(box, 2, 0, 1); return box; } if (r == 0) { box = bbox_grow(bbox_from_points(*p0, *p1), 0.5, 0.5, 0.5); // Apply the plane rotation. rot = plane->mat; rot.vecs[3] = vec4(0, 0, 0, 1); mat4_imul(&box.mat, rot); return box; } // Create a box for a line: int i; const vec3_t AXES[] = {vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1)}; box.mat = mat4_identity; box.p = vec3_mix(*p0, *p1, 0.5); box.d = vec3_sub(*p1, box.p); for (i = 0; i < 3; i++) { box.w = vec3_cross(box.d, AXES[i]); if (vec3_norm2(box.w) > 0) break; } if (i == 3) return box; box.w = vec3_mul(vec3_normalized(box.w), r); box.h = vec3_mul(vec3_normalized(vec3_cross(box.d, box.w)), r); return box; }
/* Various intersection routines. The sphere and cylinder routines are the most * mature. */ static int ray_plane_intersect(Ray ray, Plane plane, float t[1], Vec3 normal[1]) { float test_t, alpha, beta, det; Vec3 a = plane.edge1, b = plane.edge2, d = ray.direction, o = ray.origin; Vec3 n, axn, bxn, pos; /* This is basically Cramer's rule with vector calculus */ n = vec3_cross(a, b); test_t = -vec3_dot(o, n)/vec3_dot(d, n); pos = vec3_add(o, vec3_scale(test_t, d)); axn = vec3_cross(a, n); bxn = vec3_cross(b, n); det = vec3_dot(a, bxn); alpha = vec3_dot(pos, bxn)/det; beta = -vec3_dot(pos, axn)/det; if (alpha < 0 || alpha > 1 || beta < 0 || beta > 1) return 0; t[0] = test_t; if (vec3_dot(d, n) < 0) normal[0] = n; else normal[0] = vec3_scale(-1, n); return 1; }
t_mat4 mat4_view_lookat(t_vec3 eye, t_vec3 targ, t_vec3 up) { t_mat4 out; t_vec3 zaxis; t_vec3 xaxis; t_vec3 yaxis; zaxis = vec3_normal(vec3_sub(eye, targ)); xaxis = vec3_normal(vec3_cross(up, zaxis)); yaxis = vec3_cross(zaxis, xaxis); out = mat4_ident(); out.m[0] = xaxis.x; out.m[1] = yaxis.x; out.m[2] = zaxis.x; out.m[4] = xaxis.y; out.m[5] = yaxis.y; out.m[6] = zaxis.y; out.m[8] = xaxis.z; out.m[9] = yaxis.z; out.m[10] = zaxis.z; out.m[12] = -vec3_dot(xaxis, eye); out.m[13] = -vec3_dot(yaxis, eye); out.m[14] = -vec3_dot(zaxis, eye); return (out); }
static void spherical_lerp(float *v1, float *v2, float d, float *vout) { float v1xv2[3]; float v3[3]; float v1_norm = vec3_norm(v1); float v2_norm = vec3_norm(v2); vec3_normalize(v1); vec3_normalize(v2); vec3_cross(v1, v2, v1xv2); double theta; float dot = vec3_dot(v1, v2); if (dot > 1) dot = 1; theta = acosf(dot); if (theta < 0.05) { lerp(v1, v2, d, vout); return; } double phi = d * theta; vec3_normalize(v1xv2); vec3_cross(v1xv2, v1, v3); int i = 0; float cos_phi = cos(phi); float sin_phi = sin(phi); for (i = 0; i < 3; i++) { vout[i] = (cos_phi * v1[i] + sin_phi * v3[i]) * (v1_norm * (1-d) + v2_norm * d); } }
/** * Component of the support function for a cylinder collider. **/ static void object_support_component_cylinder(object_t *object, float direction[3], float out[3]) { float top[3] = { 0, object->h / 2, 0 }; float bottom[3] = { 0, -object->h / 2, 0 }; float axis[3]; float dir_perp[3]; float trans[16]; float dot_top; object_get_transform_mat(object, trans); /* Top and bottom are set to points in the middle of the top and the * bottom faces of the cylinder respectively. We transform them to * their worldspace positions. */ matrix_vec3_mul(trans, top, 1.0, top); matrix_vec3_mul(trans, bottom, 1.0, bottom); /* We get an axis vector that runs down the middle of the cylinder. */ vec3_subtract(top, bottom, axis); /* Part of another process, but useful now for a reason... */ vec3_cross(axis, direction, dir_perp); /* If the cross product is zero, our direction is aligned with the * cylinder and top and bottom are our two final candidates. */ if (vec3_magnitude(dir_perp) > 0) { /* This completes what we started with the last cross product. * dir_perp is now a vector perpendicular to the cylinder's * axis, but as close to our selected direction as possible. */ vec3_cross(dir_perp, axis, dir_perp); /* Scale dir_perp to be the radius of our cylinder. */ vec3_normalize(dir_perp, dir_perp); vec3_scale(dir_perp, dir_perp, object->r); /* Finally, move top and bottom to the edges of our cylinder in * the appropriate direction. We now have our two final * candidates. */ vec3_add(dir_perp, top, top); vec3_add(dir_perp, bottom, bottom); } /* We now have two candidates, top and bottom. We can just use largest * dot product to determine which is furthest. */ dot_top = vec3_dot(top, direction); if (dot_top > vec3_dot(bottom, direction)) memcpy(out, top, 3 * sizeof(float)); else memcpy(out, bottom, 3 * sizeof(float)); }
void camera_control_freecam(camera* c, float timestep) { const Uint8* kbstate = SDL_GetKeyboardState(NULL); if (kbstate[SDL_SCANCODE_W] || kbstate[SDL_SCANCODE_S] || kbstate[SDL_SCANCODE_A] || kbstate[SDL_SCANCODE_D]) { vec3 cam_dir = vec3_normalize(vec3_sub(c->target, c->position)); vec3 side_dir = vec3_normalize(vec3_cross(cam_dir, vec3_new(0,1,0))); const float speed = 100 * timestep; if (kbstate[SDL_SCANCODE_W]) { c->position = vec3_add(c->position, vec3_mul(cam_dir, speed)); c->target = vec3_add(c->target, vec3_mul(cam_dir, speed)); } if (kbstate[SDL_SCANCODE_S]) { c->position = vec3_sub(c->position, vec3_mul(cam_dir, speed)); c->target = vec3_sub(c->target, vec3_mul(cam_dir, speed)); } if (kbstate[SDL_SCANCODE_D]) { c->position = vec3_add(c->position, vec3_mul(side_dir, speed)); c->target = vec3_add(c->target, vec3_mul(side_dir, speed)); } if (kbstate[SDL_SCANCODE_A]) { c->position = vec3_sub(c->position, vec3_mul(side_dir, speed)); c->target = vec3_sub(c->target, vec3_mul(side_dir, speed)); } } int mouse_x, mouse_y; Uint8 mstate = SDL_GetRelativeMouseState(&mouse_x, &mouse_y); if (mstate & SDL_BUTTON(1)) { float a1 = -(float)mouse_x * 0.005; float a2 = (float)mouse_y * 0.005; vec3 cam_dir = vec3_normalize(vec3_sub(c->target, c->position)); cam_dir.y += -a2; vec3 side_dir = vec3_normalize(vec3_cross(cam_dir, vec3_new(0,1,0))); cam_dir = vec3_add(cam_dir, vec3_mul(side_dir, -a1)); cam_dir = vec3_normalize(cam_dir); c->target = vec3_add(c->position, cam_dir); } }
/* Manually apply a look-at matrix. Will reset MODELVIEW automatically. */ void cm_apply_look_at(VEC3 target, VEC3 position) { VEC3 forward = vec3_normalize(vec3_subtract(target, position)); VEC3 right = vec3_cross(forward, (VEC3){ 0, 1, 0 }); VEC3 up = vec3_normalize(vec3_cross(forward, right)); double ang = atan(NOT_DUMB_ABS(forward.y) / sqrt(forward.x * forward.x + forward.z * forward.z)); if (ang >= PI_O4) { up = vec3_negate(up); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(position.x, position.y, position.z, target.x, target.y, target.z, up.x, up.y, up.z); }
/* Calculate the quaternion to rotate from vector u to vector v */ void quat_from_u2v(union quat *q, const union vec3 *u, const union vec3 *v, const union vec3 *up) { union vec3 un, vn, axis, axisn; float dot; float angle; vec3_normalize(&un, u); vec3_normalize(&vn, v); dot = vec3_dot(&un, &vn); if (fabs(dot - -1.0f) < ZERO_TOLERANCE) { /* vector a and b point exactly in the opposite direction * so it is a 180 degrees turn around the up-axis */ union vec3 default_up = { { 0, 1, 0} }; if (!up) up = &default_up; quat_init_axis(q, up->v.x, up->v.y, up->v.z, M_PI); return; } if (fabs(dot - 1.0f) < ZERO_TOLERANCE) { /* vector a and b point exactly in the same direction * so we return the identity quaternion */ *q = identity_quat; return; } angle = acos(dot); vec3_cross(&axis, &un, &vn); vec3_normalize(&axisn, &axis); quat_init_axis(q, axisn.v.x, axisn.v.y, axisn.v.z, angle); }
static int _llfunc_vec3_cross(lua_State *L) { vec3 *a = (vec3*)userdata_get_or_die(L, 1); vec3 *b = (vec3*)userdata_get_or_die(L, 2); vec3 *r = (vec3*)userdata_get_or_new(L, 3, sizeof(vec3)); vec3_cross(a, b, r); return 1; }
void camera_control_joyorbit(camera* c, float timestep) { if (joystick_count() == 0) return; SDL_Joystick* mainstick = joystick_get(0); int x_move = SDL_JoystickGetAxis(mainstick, 0); int y_move = SDL_JoystickGetAxis(mainstick, 1); /* Dead Zone */ if (abs(x_move) < 10000) { x_move = 0; }; if (abs(y_move) < 10000) { y_move = 0; }; float a1 = (x_move / 32768.0) * -0.05; float a2 = (y_move / 32768.0) * 0.05; vec3 translation = c->target; c->position = vec3_sub(c->position, translation); c->target = vec3_sub(c->target, translation); c->position = mat3_mul_vec3(mat3_rotation_y( a1 ), c->position ); vec3 axis = vec3_normalize(vec3_cross( vec3_sub(c->position, c->target) , vec3_new(0,1,0) )); c->position = mat3_mul_vec3(mat3_rotation_axis_angle(axis, a2 ), c->position ); c->position = vec3_add(c->position, translation); c->target = vec3_add(c->target, translation); }
void quat_vector_vector(quat_t *q, const vec3_t *a, const vec3_t *b) { float cost = vec3_dot(a, b); if (cost > 0.99999f) { /* parallel */ *q = QUAT_IDENT; } else if (cost < -0.99999f) { /* opposite */ vec3_t t = VEC3(0, a->x, -a->y); /* cross with (1,0,0) */ if (vec3_magnitude(&t) < EPSILON) t = VEC3(-a->z, 0, a->x); /* nope, use (0,1,0) */ vec3_normalize(&t); q->v = t; q->w = 0.f; } else { vec3_t t; vec3_cross(&t, a, b); vec3_normalize(&t); /* sin^2 t = (1 - cos(2t)) / 2 */ float ss = sqrt(.5f * (1.f - cost)); vec3_scale(&t, ss); q->v = t; /* cos^2 t = (1 + cos(2t) / 2 */ q->w = sqrt(.5f * (1.f + cost)); } }
bool Face3::intersects_aabb(const AABB &p_aabb) const { /** TEST PLANE **/ if (!p_aabb.intersects_plane(get_plane())) return false; #define TEST_AXIS(m_ax) \ /** TEST FACE AXIS */ \ { \ real_t aabb_min = p_aabb.position.m_ax; \ real_t aabb_max = p_aabb.position.m_ax + p_aabb.size.m_ax; \ real_t tri_min = vertex[0].m_ax; \ real_t tri_max = vertex[0].m_ax; \ for (int i = 1; i < 3; i++) { \ if (vertex[i].m_ax > tri_max) \ tri_max = vertex[i].m_ax; \ if (vertex[i].m_ax < tri_min) \ tri_min = vertex[i].m_ax; \ } \ \ if (tri_max < aabb_min || aabb_max < tri_min) \ return false; \ } TEST_AXIS(x); TEST_AXIS(y); TEST_AXIS(z); /** TEST ALL EDGES **/ Vector3 edge_norms[3] = { vertex[0] - vertex[1], vertex[1] - vertex[2], vertex[2] - vertex[0], }; for (int i = 0; i < 12; i++) { Vector3 from, to; p_aabb.get_edge(i, from, to); Vector3 e1 = from - to; for (int j = 0; j < 3; j++) { Vector3 e2 = edge_norms[j]; Vector3 axis = vec3_cross(e1, e2); if (axis.length_squared() < 0.0001) continue; // coplanar axis.normalize(); real_t minA, maxA, minB, maxB; p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); project_range(axis, Transform(), minB, maxB); if (maxA < minB || maxB < minA) return false; } } return true; }
void camera_control_orbit(camera* c, SDL_Event e) { float a1 = 0; float a2 = 0; vec3 axis; vec3 translation = c->target; c->position = vec3_sub(c->position, translation); c->target = vec3_sub(c->target, translation); switch(e.type) { case SDL_MOUSEMOTION: if (e.motion.state & SDL_BUTTON(1)) { a1 = e.motion.xrel * -0.005; a2 = e.motion.yrel * 0.005; c->position = mat3_mul_vec3(mat3_rotation_y( a1 ), c->position ); axis = vec3_normalize(vec3_cross( vec3_sub(c->position, c->target) , vec3_new(0,1,0) )); c->position = mat3_mul_vec3(mat3_rotation_angle_axis(a2, axis), c->position ); } break; case SDL_MOUSEWHEEL: c->position = vec3_add(c->position, vec3_mul(vec3_normalize(c->position), -e.wheel.y)); break; } c->position = vec3_add(c->position, translation); c->target = vec3_add(c->target, translation); }
void scotland_update() { camera* cam = entity_get("camera"); light* sun = entity_get("sun"); static_object* skydome = entity_get("skydome"); landscape* world = entity_get("world"); sun_orbit += frame_time() * 0.01; sun->position.x = 512 + sin(sun_orbit) * 512; sun->position.y = cos(sun_orbit) * 512; sun->position.z = 512; sun->target = vec3_new(512, 0, 512); if (w_held || s_held) { vec3 cam_dir = vec3_normalize(vec3_sub(cam->target, cam->position)); float speed = 0.5; if (!freecam) speed = 0.05; if (w_held) { cam->position = vec3_add(cam->position, vec3_mul(cam_dir, speed)); } if (s_held) { cam->position = vec3_sub(cam->position, vec3_mul(cam_dir, speed)); } if (!freecam) { float height = terrain_height(asset_hndl_ptr(world->terrain), vec2_new(cam->position.x, cam->position.z)); cam->position.y = height + 1; } cam->target = vec3_add(cam->position, cam_dir); } Uint8 keystate = SDL_GetMouseState(NULL, NULL); if(keystate & SDL_BUTTON(1)){ float a1 = -(float)mouse_x * 0.005; float a2 = (float)mouse_y * 0.005; vec3 cam_dir = vec3_normalize(vec3_sub(cam->target, cam->position)); cam_dir.y += -a2; vec3 side_dir = vec3_normalize(vec3_cross(cam_dir, vec3_new(0,1,0))); cam_dir = vec3_add(cam_dir, vec3_mul(side_dir, -a1)); cam_dir = vec3_normalize(cam_dir); cam->target = vec3_add(cam->position, cam_dir); } mouse_x = 0; mouse_y = 0; ui_button* framerate = ui_elem_get("framerate"); ui_button_set_label(framerate, frame_rate_string()); }
/* ======================================================================================================================================= BaseWindingForPlane ======================================================================================================================================= */ winding_t *BaseWindingForPlane(vec3_t normal, vec_t dist) { int i, x = -1; vec_t max = -MAX_MAP_BOUNDS, v; vec3_t org, vright, vup; winding_t *w; // find the major axis for (i = 0; i < 3; i++) { v = Q_fabs(normal[i]); if (v > max) { x = i; max = v; } } if (x == -1) { Com_Error(ERR_DROP, "BaseWindingForPlane: no axis found"); } VectorCopy(vec3_origin, vup); switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; } v = DotProduct(vup, normal); VectorMA(vup, -v, normal, vup); vec3_norm2(vup, vup); VectorScale(normal, dist, org); vec3_cross(vup, normal, vright); VectorScale(vup, MAX_MAP_BOUNDS, vup); VectorScale(vright, MAX_MAP_BOUNDS, vright); // project a really big axis aligned box onto the plane w = AllocWinding(4); VectorSubtract(org, vright, w->p[0]); VectorAdd(w->p[0], vup, w->p[0]); VectorAdd(org, vright, w->p[1]); VectorAdd(w->p[1], vup, w->p[1]); VectorAdd(org, vright, w->p[2]); VectorSubtract(w->p[2], vup, w->p[2]); VectorSubtract(org, vright, w->p[3]); VectorSubtract(w->p[3], vup, w->p[3]); w->numpoints = 4; return w; }
/* ======================================================================================================================================= WindingPlane ======================================================================================================================================= */ void WindingPlane(winding_t *w, vec3_t normal, vec_t *dist) { vec3_t v1, v2; VectorSubtract(w->p[1], w->p[0], v1); VectorSubtract(w->p[2], w->p[0], v2); vec3_cross(v2, v1, normal); vec3_norm2(normal, normal); *dist = DotProduct(w->p[0], normal); }
void Polygon_FindNormale(polygon_p p) { float v1[3], v2[3]; vec3_sub(v1, p->vertices[1].position, p->vertices[0].position); vec3_sub(v2, p->vertices[2].position, p->vertices[1].position); vec3_cross(p->plane, v1, v2); p->plane[3] = -vec3_abs(p->plane); vec3_norm_plane(p->plane, p->vertices[0].position, p->plane[3]); }
/* 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); }
bool Plane::intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result) const { const Plane &p_plane0 = *this; Vector3 normal0 = p_plane0.normal; Vector3 normal1 = p_plane1.normal; Vector3 normal2 = p_plane2.normal; real_t denom = vec3_cross(normal0, normal1).dot(normal2); if (ABS(denom) <= CMP_EPSILON) return false; if (r_result) { *r_result = ((vec3_cross(normal1, normal2) * p_plane0.d) + (vec3_cross(normal2, normal0) * p_plane1.d) + (vec3_cross(normal0, normal1) * p_plane2.d)) / denom; } return true; }
/* Create a new buffer object from an array of vec3s for pts, and vec3s for texture coordinates. Faces is an array of 3 shorts for each face. */ BUFFER_T *buffer_new(float pts[][3], float tex[][3], short faces[][3], int numpts, int numfaces) { int i; float normals[numpts][3]; BUFFER_T *buf; NEW(buf); for(i=0; i<numpts; i++) { normals[i][0]=0; normals[i][1]=0; normals[i][2]=1; } for(i=0; i<numfaces; i++) { int a = faces[i][0]; int b = faces[i][1]; int c = faces[i][2]; float tmp[3]; float tmp2[3]; float n[3]; vec3_sub(tmp,pts[b],pts[a]); vec3_sub(tmp2,pts[c],pts[a]); vec3_cross(n,tmp,tmp2); vec3_normal(n,n); vec3_copy(normals[a],n); vec3_copy(normals[b],n); vec3_copy(normals[c],n); } float B[3*3*numpts]; for(i=0; i<numpts; i++) { for(int j=0; j<3; j++) { B[i*3*3+j]=pts[i][j]; B[i*3*3+3+j]=tex[i][j]; B[i*3*3+6+j]=normals[i][j]; } } buf->ntris=numfaces; glGenBuffers(1,&buf->vbuf); glBindBuffer(GL_ARRAY_BUFFER, buf->vbuf); glBufferData(GL_ARRAY_BUFFER, 36*numpts, B, GL_STATIC_DRAW); buf->vbuf_num = numpts; glGenBuffers(1,&buf->ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 6*numfaces, faces, GL_STATIC_DRAW); buf->ebuf_num = numfaces*3; return buf; }
bool hitscan_sprite_mobs(const Vec3& position, const Vec3& direction, float range, SpriteMobID& id, float& distance, Vec3& collision_point) { SpriteMobID nearest_mob = NULL_SPRITE_MOB; float nearest_distance = 100000.0f; Vec3 nearest_collision_point = vec3_init(0); const float range_sq = range * range; const Vec3 up = vec3_init(0, 0, 1); for (size_t i=0, j=0; i<sprite_mob_list->max && j<sprite_mob_list->count; i++) { // TODO // do a line-plane intersection test against the mob, if its in frustum SpriteMob* m = sprite_mob_list->objects[i]; if (m == NULL) continue; j++; Vec3 p = m->get_center(); p = quadrant_translate_position(position, p); if (vec3_distance_squared(position, p) > range_sq) continue; float rad_sq = 10000.0f; Vec3 line_point = vec3_init(0); if (!sphere_line_distance(position, direction, p, line_point, rad_sq)) continue; Vec3 forward = vec3_sub(position, p); forward.z = 0.0f; if (unlikely(vec3_length_squared(forward) == 0)) continue; forward = vec3_normalize(forward); const Vec3 right = vec3_normalize(vec3_cross(forward, up)); float d = 1000000.0f; float width = get_mob_width(m->type) * 0.5f; float height = get_mob_height(m->type) * 0.5f; if (!line_plane_intersection(position, direction, p, width, height, forward, right, up, d)) continue; if (d >= nearest_distance) continue; nearest_distance = d; nearest_mob = m->id; nearest_collision_point = line_point; } id = nearest_mob; distance = nearest_distance; collision_point = translate_position(nearest_collision_point); return (nearest_mob != NULL_SPRITE_MOB); }
static void draw_gui() { glColor3d(1, 1, 1); VEC3 cfwd = cm_get_fps_camera_forward(fcamera); VEC3 cright = cm_get_fps_camera_right(fcamera); VEC3 cup = vec3_cross(cright, cfwd); rh_draw_window_text((VEC2){ 3, 3 }, "Camera Type: %s", camera_type == 1 ? "Perspective Target" : (camera_type == 2 ? "Orthographic Target" : "Perspective FPS")); rh_draw_window_text((VEC2){ 3, 25}, "Camera Position: (%f,%f,%f)", fcamera.position.x, fcamera.position.y, fcamera.position.z); rh_draw_window_text((VEC2){ 3, 50}, "Camera Forward: (%f,%f,%f)", cfwd.x, cfwd.y, cfwd.z); rh_draw_window_text((VEC2){ 3, 75}, "Camera Right: (%f,%f,%f)", cright.x, cright.y, cright.z); rh_draw_window_text((VEC2){ 3, 100}, "Camera Up: (%f,%f,%f)", cup.x, cup.y, cup.z); }
/* Calculate the quaternion to rotate from vector u to vector v */ void quat_from_u2v(union quat *q, const union vec3 *u, const union vec3 *v, const union vec3 *up) { /* See: http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors */ union vec3 w; vec3_cross(&w, u, v); q->v.w = vec3_dot(u, v); q->v.x = w.v.x; q->v.y = w.v.y; q->v.z = w.v.z; q->v.w += quat_len(q); quat_normalize_self(q); }
void plane_from_tri(struct plane *dst, const struct vec3 *v1, const struct vec3 *v2, const struct vec3 *v3) { struct vec3 temp; vec3_sub(&temp, v2, v1); vec3_sub(&dst->dir, v3, v1); vec3_cross(&dst->dir, &temp, &dst->dir); vec3_norm(&dst->dir, &dst->dir); dst->dist = vec3_dot(v1, &dst->dir); }
int Polygon_RayIntersect(polygon_p p, float dir[3], float dot[3], float *t) { float tt, u, v, E1[3], E2[3], P[3], Q[3], T[3]; vertex_p vp; u = vec3_dot(p->plane, dir); if(fabs(u) < 0.001 /*|| vec3_plane_dist(p->plane, dot) < -0.001*/) // FIXME: magick { return 0; // plane is parallel to the ray - no intersection } *t = - vec3_plane_dist(p->plane, dot); *t /= u; vp = p->vertices; // current polygon pointer vec3_sub(T, dot, vp[0].position); vec3_sub(E2, vp[1].position, vp[0].position) for(uint16_t i = 0; i < p->vertex_count - 2; i++, vp++) { vec3_copy(E1, E2) // PREV vec3_sub(E2, vp[2].position, p->vertices[0].position) // NEXT vec3_cross(P, dir, E2) vec3_cross(Q, T, E1) tt = vec3_dot(P, E1); u = vec3_dot(P, T); u /= tt; v = vec3_dot(Q, dir); v /= tt; tt = 1.0 - u - v; if((u <= 1.0) && (u >= 0.0) && (v <= 1.0) && (v >= 0.0) && (tt <= 1.0) && (tt >= 0.0)) { return 1; } } return 0; }
t_vec3 bump_normal(t_obj *obj, t_ray *ray) { t_vec3 normal; t_vec3 tangent; t_vec3 binormal; t_vec3 bump; t_vec3 c[2]; normal = obj->normal; bump = texture_mapping(obj, obj->mat.texture.bump, ray->hit); bump = vec3_sub(vec3_fmul(bump, 2), vec3(1, 1, 1)); c[0] = vec3_cross(normal, vec3(0, 0, 1)); c[1] = vec3_cross(normal, vec3(0, 1, 0)); tangent = (vec3_magnitude(c[0]) > vec3_magnitude(c[1]) ? c[0] : c[1]); tangent = vec3_sub(tangent, vec3_fmul(normal, vec3_dot(tangent, normal))); vec3_normalize(&tangent); binormal = vec3_norm(vec3_cross(normal, tangent)); normal.x = vec3_dot(bump, vec3(tangent.x, binormal.x, normal.x)); normal.y = vec3_dot(bump, vec3(tangent.y, binormal.y, normal.y)); normal.z = vec3_dot(bump, vec3(tangent.z, binormal.z, normal.z)); vec3_normalize(&normal); return (normal); }
/* ======================================================================================================================================= WindingArea ======================================================================================================================================= */ vec_t WindingArea(winding_t *w) { int i; vec3_t d1, d2, cross; vec_t total = 0; for (i = 2; i < w->numpoints; i++) { VectorSubtract(w->p[i - 1], w->p[0], d1); VectorSubtract(w->p[i], w->p[0], d2); vec3_cross(d1, d2, cross); total += 0.5f * vec3_length(cross); } return total; }
void matrix_4x4_lookat(math_matrix_4x4 *out, vec3_t eye, vec3_t center, vec3_t up) { vec3_t zaxis; /* the "forward" vector */ vec3_t xaxis; /* the "right" vector */ vec3_t yaxis; /* the "up" vector */ vec3_copy(&zaxis[0], center); vec3_subtract(&zaxis[0], eye); vec3_normalize(&zaxis[0]); vec3_cross(&xaxis[0], &zaxis[0], up); vec3_normalize(&xaxis[0]); vec3_cross(&yaxis[0], &xaxis[0], zaxis); MAT_ELEM_4X4(*out, 0, 0) = xaxis[0]; MAT_ELEM_4X4(*out, 0, 1) = yaxis[0]; MAT_ELEM_4X4(*out, 0, 2) = -zaxis[0]; MAT_ELEM_4X4(*out, 0, 3) = 0.0; MAT_ELEM_4X4(*out, 1, 0) = xaxis[1]; MAT_ELEM_4X4(*out, 1, 1) = yaxis[1]; MAT_ELEM_4X4(*out, 1, 2) = -zaxis[1]; MAT_ELEM_4X4(*out, 1, 3) = 0.0f; MAT_ELEM_4X4(*out, 2, 0) = xaxis[2]; MAT_ELEM_4X4(*out, 2, 1) = yaxis[2]; MAT_ELEM_4X4(*out, 2, 2) = -zaxis[2]; MAT_ELEM_4X4(*out, 2, 3) = 0.0f; MAT_ELEM_4X4(*out, 3, 0) = -(xaxis[0] * eye[0] + xaxis[1] * eye[1] + xaxis[2] * eye[2]); MAT_ELEM_4X4(*out, 3, 1) = -(yaxis[0] * eye[0] + yaxis[1] * eye[1] + yaxis[2] * eye[2]); MAT_ELEM_4X4(*out, 3, 2) = -(zaxis[0] * eye[0] + zaxis[1] * eye[1] + zaxis[2] * eye[2]); MAT_ELEM_4X4(*out, 3, 3) = 1.f; }