#include "bounding_volumes.h" #include "../common/log.h" #include int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box) { vec3 size, center, half_ext, half_size; vec3_fill(&size, 0.f, 0.f, 0.f); vec3_fill(¢er, 0.f, 0.f, 0.f); vec3_fill(&half_ext, 0.f, 0.f, 0.f); vec3_fill(&half_size, 0.f, 0.f, 0.f); vec3_sub(&size, &box->max, &box->min); vec3_add(¢er, &box->max, &box->min); vec3_scale(¢er, ¢er, 0.5f); vec3_assign(&half_ext, &size); vec3_scale(&half_size, &size, 0.5f); //for(int i = 0; i < 6; i++) //{ // vec3 normal = {frustum[i].x, frustum[i].y, frustum[i].z}; // float distance = frustum[i].w; // float d = vec3_dot(&normal, ¢er); // vec3 abs_normal = {fabsf(normal.x), fabsf(normal.y), fabsf(normal.z)}; // float r = vec3_dot(&half_ext, &abs_normal); // if(d + r < -distance) // return IT_OUTSIDE; //} //return IT_INSIDE; vec3 edge = { 0.f, 0.f, 0.f }; vec3_sub(&edge, ¢er, &box->min); bool all_inside = true; for(int i = 0; i < 6; i++) { vec3 normal = {frustum[i].x, frustum[i].y, frustum[i].z}; float d = frustum[i].w; float dist = vec3_dot(&normal, ¢er) + d; vec3 abs_normal = { fabsf(normal.x), fabsf(normal.y), fabsf(normal.z) }; float abs_dist = vec3_dot(&abs_normal, &edge); if(dist < -abs_dist) return IT_OUTSIDE; else if(dist < abs_dist) all_inside = false; } return all_inside ? IT_INSIDE : IT_INTERSECT; } int bv_intersect_frustum_box_with_abs_transform(vec4* frustum, struct Bounding_Box* box, vec3* box_abs_position, vec3* box_abs_scale) { vec3 min, max, size, center, half_ext, half_size; vec3_fill(&min, 0.f, 0.f, 0.f); vec3_fill(&max, 0.f, 0.f, 0.f); vec3_fill(&size, 0.f, 0.f, 0.f); vec3_fill(¢er, 0.f, 0.f, 0.f); vec3_fill(&half_ext, 0.f, 0.f, 0.f); vec3_fill(&half_size, 0.f, 0.f, 0.f); vec3_add(&min, &box->min, box_abs_position); vec3_mul(&min, &min, box_abs_scale); vec3_add(&max, &box->max, box_abs_position); vec3_mul(&min, &min, box_abs_scale); vec3_sub(&size, &max, &min); vec3_add(¢er, &max, &min); vec3_scale(¢er, ¢er, 0.5f); vec3_assign(&half_ext, &size); vec3_scale(&half_size, &size, 0.5f); for(int i = 0; i < 6; i++) { vec3 normal = {frustum[i].x, frustum[i].y, frustum[i].z}; float distance = frustum[i].w; float d = vec3_dot(&normal, ¢er); vec3 abs_normal = {fabsf(normal.x), fabsf(normal.y), fabsf(normal.z)}; float r = vec3_dot(&half_ext, &abs_normal); if(d + r < -distance) return IT_OUTSIDE; } return IT_INSIDE; } int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, vec3* sphere_abs_pos, vec3* sphere_abs_scale) { int intersect_type = IT_INSIDE; vec3 center; float radius = sphere->radius; vec3_fill(¢er, 0.f, 0.f, 0.f); float max_scale_dimension = fabsf(sphere_abs_scale->x); if(fabsf(sphere_abs_scale->y) > max_scale_dimension) max_scale_dimension = fabsf(sphere_abs_scale->y); if(fabsf(sphere_abs_scale->z) > max_scale_dimension) max_scale_dimension = fabsf(sphere_abs_scale->z); radius *= max_scale_dimension; vec3_add(¢er, &sphere->center, sphere_abs_pos); //vec3_mul(¢er, ¢er, &transform->scale); for(int i = 0; i < 6; i++) { vec3 plane_normal = {frustum[i].x, frustum[i].y, frustum[i].z}; float distance = frustum[i].w; float dot = vec3_dot(&plane_normal, ¢er) + distance; if(dot < -radius) { intersect_type = IT_OUTSIDE; return intersect_type; } if(fabsf(dot) < radius) { intersect_type = IT_INTERSECT; return intersect_type; } } return intersect_type; } bool bv_point_inside_frustum(vec4* frustum, const vec3* point) { bool success = true; for(int i = 0; i < 6; i++) { if((frustum[i].x * point->x + frustum[i].y * point->y + frustum[i].z * point->z + frustum[i].w) < 0 ) success = false; } return success; } int bv_intersect_sphere_ray(struct Bounding_Sphere* sphere, vec3* sphere_abs_position, vec3* sphere_abs_scale, struct Ray* ray) { int intersection_type = IT_OUTSIDE; vec3 center = {0.f, 0.f, 0.f}; vec3_add(¢er, &sphere->center, sphere_abs_position); float radius = sphere->radius * sphere_abs_scale->x; //float squared_radius = sphere->radius * sphere->radius; float squared_radius = radius * radius; vec3 centered_origin; vec3_sub(¢ered_origin, &ray->origin, ¢er); //vec3_sub(¢ered_origin, ¢er, &ray->origin); float centered_origin_len_sqrd = vec3_len(¢ered_origin); centered_origin_len_sqrd *= centered_origin_len_sqrd; //Check if ray originates inside the sphere if(centered_origin_len_sqrd <= squared_radius) return IT_INSIDE; // Calculate the intersection by quatratic equation' float a = vec3_dot(&ray->direction, &ray->direction); float b = 2.f * vec3_dot(¢ered_origin, &ray->direction); float c = vec3_dot(¢ered_origin, ¢ered_origin) - squared_radius; float d = b * b - 4.f * a * c; //No solution if(d < 0.f) return IT_OUTSIDE; //Get the near solution float d_sqrt = sqrtf(d); float dist = (-b - d_sqrt) / (2.f * a); if(dist >= 0.f) return IT_INTERSECT; else return IT_OUTSIDE; //float tca = vec3_dot(¢ered_origin, &ray->direction); //if(tca < 0.0) return IT_OUTSIDE; //float L_dot = vec3_dot(¢ered_origin, ¢ered_origin); //float d2 = L_dot - (tca * tca); //float radius_sqr = radius * radius; //if (d2 > radius_sqr) return IT_OUTSIDE; //float thc = sqrtf(radius_sqr - d2); //float t0 = tca - thc; //float t1 = tca + thc; //if(t0 > t1) //{ // float temp = t0; // t0 = t1; // t1 = temp; //} //if(t0 < 0) //{ // t0 = t1; // if(t0 < 0) return IT_OUTSIDE; //} //return IT_INTERSECT; } float bv_distance_ray_plane(struct Ray* ray, Plane* plane) { float dot = vec3_dot(&plane->normal, &ray->direction); float abs_dot = fabsf(dot); if(abs_dot >= EPSILON) { float dot_origin = vec3_dot(&plane->normal, &ray->origin); float t = -(dot_origin + plane->constant) / dot; if(t >= 0.0f) return t; else return INFINITY; } else return INFINITY; } void bv_bounding_box_vertices_get(struct Bounding_Box* bounding_box, vec3 out_vertices[8]) { vec3_fill(&out_vertices[0], bounding_box->min.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[1], bounding_box->max.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[2], bounding_box->min.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[3], bounding_box->min.x, bounding_box->min.y, bounding_box->max.z); vec3_fill(&out_vertices[4], bounding_box->max.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[5], bounding_box->min.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[6], bounding_box->max.x, bounding_box->min.y, bounding_box->max.z); vec3_fill(&out_vertices[7], bounding_box->max.x, bounding_box->max.y, bounding_box->min.z); } void bv_bounding_box_vertices_get_line_visualization(struct Bounding_Box* bounding_box, vec3 out_vertices[24]) { // Back vec3_fill(&out_vertices[0], bounding_box->min.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[1], bounding_box->min.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[2], bounding_box->min.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[3], bounding_box->max.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[4], bounding_box->min.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[5], bounding_box->max.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[6], bounding_box->max.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[7], bounding_box->max.x, bounding_box->min.y, bounding_box->min.z); // Front vec3_fill(&out_vertices[8], bounding_box->min.x, bounding_box->min.y, bounding_box->max.z); vec3_fill(&out_vertices[9], bounding_box->min.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[10], bounding_box->min.x, bounding_box->min.y, bounding_box->max.z); vec3_fill(&out_vertices[11], bounding_box->max.x, bounding_box->min.y, bounding_box->max.z); vec3_fill(&out_vertices[12], bounding_box->min.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[13], bounding_box->max.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[14], bounding_box->max.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[15], bounding_box->max.x, bounding_box->min.y, bounding_box->max.z); // Left vec3_fill(&out_vertices[16], bounding_box->min.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[17], bounding_box->min.x, bounding_box->max.y, bounding_box->max.z); vec3_fill(&out_vertices[18], bounding_box->min.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[19], bounding_box->min.x, bounding_box->min.y, bounding_box->max.z); // Right vec3_fill(&out_vertices[20], bounding_box->max.x, bounding_box->min.y, bounding_box->min.z); vec3_fill(&out_vertices[21], bounding_box->max.x, bounding_box->min.y, bounding_box->max.z); vec3_fill(&out_vertices[22], bounding_box->max.x, bounding_box->max.y, bounding_box->min.z); vec3_fill(&out_vertices[23], bounding_box->max.x, bounding_box->max.y, bounding_box->max.z); } int bv_intersect_bounding_box_ray(struct Bounding_Box* box, struct Ray* ray) { float tmin = (box->min.x - ray->origin.x) / ray->direction.x; float tmax = (box->max.x - ray->origin.x) / ray->direction.x; if(tmin > tmax) { float temp = tmin; tmin = tmax; tmax = temp; } float tymin = (box->min.y - ray->origin.y) / ray->direction.y; float tymax = (box->max.y - ray->origin.y) / ray->direction.y; if(tymin > tymax) { float temp = tymin; tymin = tymax; tymax = temp; } if((tmin > tymax) || (tymin > tmax)) return IT_OUTSIDE; if(tymin > tmin) tmin = tymin; if(tymax < tmax) tmax = tymax; float tzmin = (box->min.z - ray->origin.z) / ray->direction.z; float tzmax = (box->max.z - ray->origin.z) / ray->direction.z; if(tzmin > tzmax) { float temp = tzmin; tzmin = tzmax; tzmax = temp; } if((tmin > tzmax) || (tzmin > tmax)) return IT_OUTSIDE; if(tzmin > tmin) tmin = tzmin; if(tzmax < tmax) tmax = tzmax; return tmin < 0.f ? IT_INSIDE : IT_INTERSECT; } float bv_distance_ray_bounding_box(struct Ray* ray, struct Bounding_Box* box) { float tmin = (box->min.x - ray->origin.x) / ray->direction.x; float tmax = (box->max.x - ray->origin.x) / ray->direction.x; if(tmin > tmax) { float temp = tmin; tmin = tmax; tmax = temp; } float tymin = (box->min.y - ray->origin.y) / ray->direction.y; float tymax = (box->max.y - ray->origin.y) / ray->direction.y; if(tymin > tymax) { float temp = tymin; tymin = tymax; tymax = temp; } if((tmin > tymax) || (tymin > tmax)) return INFINITY; if(tymin > tmin) tmin = tymin; if(tymax < tmax) tmax = tymax; float tzmin = (box->min.z - ray->origin.z) / ray->direction.z; float tzmax = (box->max.z - ray->origin.z) / ray->direction.z; if(tzmin > tzmax) { float temp = tzmin; tzmin = tzmax; tzmax = temp; } if((tmin > tzmax) || (tzmin > tmax)) return INFINITY; if(tzmin > tmin) tmin = tzmin; if(tzmax < tmax) tmax = tzmax; return tmin >= 0.f ? tmin : tmax; // if tmin < 0, return the max value since it represents the hit in front of us. We don't care about hits behind us } int bv_intersect_bounding_boxes(struct Bounding_Box* b1, struct Bounding_Box* b2) { if(b2->max.x < b1->min.x || b2->min.x > b1->max.x || b2->max.y < b1->min.y || b2->min.y > b1->max.y || b2->max.z < b1->min.z || b2->min.z > b1->max.z) return IT_OUTSIDE; else if(b2->min.x < b1->min.x || b2->max.x > b1->max.x || b2->min.y < b1->min.y || b2->max.y > b1->max.y || b2->min.z < b1->min.z || b2->max.z > b1->max.z) return IT_INTERSECT; else return IT_INSIDE; // b2 is inside b1 } bool bv_point_inside_bounding_box(struct Bounding_Box* box, vec3 point) { if(point.x < box->min.x || point.x > box->max.x || point.y < box->min.y || point.y > box->max.y || point.z < box->min.z || point.z > box->max.z) return false; else return true; } vec3 bv_bounding_box_normal_from_intersection_point(struct Bounding_Box* box, vec3 intersection_point) { vec3 center = { (box->max.x + box->min.x) * 0.5f, (box->max.y + box->min.y) * 0.5f, (box->max.z + box->min.z) * 0.5f }; vec3 local_point = { 0.f, 0.f, 0.f }; vec3_sub(&local_point, &intersection_point, ¢er); vec3 d = { (box->min.x - box->max.x) * 0.5f, (box->min.y - box->max.y) * 0.5f, (box->min.z - box->max.z) * 0.5f }; float bias = 1.000001f; vec3 normal = { (int)(local_point.x / fabsf(d.x) * bias), (int)(local_point.y / fabsf(d.y) * bias), (int)(local_point.z / fabsf(d.z) * bias) }; vec3_norm(&normal, &normal); return normal; }