Improved ray-boundingbox intersection tests and implemented getting hit distance from ray-bounding box intersection test

dev
Shariq Shah 6 years ago
parent ca3a5ac6ec
commit 9c89516d3a
  1. 78
      src/game/bounding_volumes.c
  2. 5
      src/game/bounding_volumes.h
  3. 63
      src/game/editor.c
  4. 53
      src/game/scene.c
  5. 5
      src/game/scene.h
  6. 7
      todo.txt

@ -1,4 +1,5 @@
#include "bounding_volumes.h"
#include "../common/log.h"
#include <math.h>
@ -94,7 +95,7 @@ int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, v
return intersect_type;
}
bool bv_intersect_frustum_point(vec4* frustum, const vec3* point)
bool bv_point_inside_frustum(vec4* frustum, const vec3* point)
{
bool success = true;
for(int i = 0; i < 6; i++)
@ -297,5 +298,78 @@ int bv_intersect_bounding_box_ray(struct Bounding_Box* box, struct Ray* ray)
if(tzmax < tmax)
tmax = tzmax;
return IT_INTERSECT;
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;
}

@ -52,11 +52,14 @@ struct Raycast_Result
int bv_intersect_frustum_box(vec4* frustum, struct Bounding_Box* box, vec3* box_abs_position, vec3* box_abs_scale);
int bv_intersect_frustum_box_(vec4* frustum, struct Bounding_Box* box);
int bv_intersect_frustum_sphere(vec4* frustum, struct Bounding_Sphere* sphere, vec3* sphere_abs_pos, vec3* sphere_abs_scale);
bool bv_intersect_frustum_point(vec4* frustum, const vec3* point);
bool bv_point_inside_frustum(vec4* frustum, const vec3* point);
bool bv_point_inside_bounding_box(struct Bounding_Box* box, vec3 point);
int bv_intersect_bounding_box_ray(struct Bounding_Box* box, struct Ray* ray);
int bv_intersect_sphere_ray(struct Bounding_Sphere* sphere, vec3* sphere_abs_position, vec3* sphere_abs_scale, struct Ray* ray);
int bv_intersect_bounding_boxes(struct Bounding_Box* b1, struct Bounding_Box* b2);
float bv_distance_ray_plane(struct Ray* ray, Plane* plane);
void bv_bounding_box_vertices_get(struct Bounding_Box* box, vec3 out_vertices[8]);
void bv_bounding_box_vertices_get_line_visualization(struct Bounding_Box* bounding_box, vec3 out_vertices[24]);
float bv_distance_ray_bounding_box(struct Ray* ray, struct Bounding_Box* box);
#endif

@ -857,21 +857,11 @@ void editor_on_mousebutton_release(const struct Event* event)
struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y);
struct Scene* scene = game_state_get()->scene;
struct Raycast_Result ray_result;
scene_ray_intersect(scene, &ray, &ray_result);
if(ray_result.num_entities_intersected > 0)
struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray);
if(intersected_entity)
{
//For now, just select the first entity that is intersected
struct Entity* intersected_entity = ray_result.entities_intersected[0];
if(intersected_entity == editor->cursor_entity)
{
if(ray_result.num_entities_intersected > 1)
intersected_entity = ray_result.entities_intersected[1];
else
intersected_entity = NULL;
}
if(intersected_entity) editor_entity_select(editor, intersected_entity);
if(intersected_entity != editor->selected_entity)
editor_entity_select(editor, intersected_entity);
}
else
{
@ -945,28 +935,12 @@ void editor_on_mousebutton_press(const struct Event* event)
int mouse_x = 0, mouse_y = 0;
platform_mouse_position_get(&mouse_x, &mouse_y);
struct Ray ray = camera_screen_coord_to_ray(editor_camera, mouse_x, mouse_y);
struct Raycast_Result ray_result;
scene_ray_intersect(scene, &ray, &ray_result);
struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray);
bool start_rotation = true;
if(ray_result.num_entities_intersected > 0)
if(intersected_entity)
{
//For now, just select the first entity that is intersected
struct Entity* intersected_entity = ray_result.entities_intersected[0];
if(intersected_entity == editor->cursor_entity || intersected_entity == editor->selected_entity)
{
if(ray_result.num_entities_intersected > 1)
{
intersected_entity = ray_result.entities_intersected[1];
if(intersected_entity)
{
editor_entity_select(editor, intersected_entity);
start_rotation = false;
}
}
}
else
if(intersected_entity != editor->selected_entity)
{
editor_entity_select(editor, intersected_entity);
start_rotation = false;
@ -1166,13 +1140,24 @@ void editor_on_mousemotion(const struct Event* event)
struct Scene* scene = game_state->scene;
struct Camera* editor_camera = &scene->cameras[CAM_EDITOR];
struct Ray ray = camera_screen_coord_to_ray(editor_camera, event->mousemotion.x, event->mousemotion.y);
struct Raycast_Result ray_result;
scene_ray_intersect(scene, &ray, &ray_result);
if(ray_result.num_entities_intersected > 0)
//struct Raycast_Result ray_result;
//scene_ray_intersect(scene, &ray, &ray_result);
//if(ray_result.num_entities_intersected > 0)
//{
// struct Entity* intersected_entity = ray_result.entities_intersected[0];
// if(intersected_entity && intersected_entity != editor->hovered_entity)
// editor->hovered_entity = intersected_entity;
//}
//else
//{
// if(editor->hovered_entity)
// editor->hovered_entity = NULL;
//}
struct Entity* intersected_entity = scene_ray_intersect_closest(scene, &ray);
if(intersected_entity)
{
struct Entity* intersected_entity = ray_result.entities_intersected[0];
if(intersected_entity && intersected_entity != editor->hovered_entity)
if(intersected_entity != editor->hovered_entity)
editor->hovered_entity = intersected_entity;
}
else

@ -21,10 +21,10 @@
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
static void scene_write_entity_entry(struct Scene* scene, struct Entity* entity, struct Parser* parser);
static void scene_write_entity_list(struct Scene* scene, int entity_type, struct Parser* parser);
static int scene_sort_by_distance_from_active_viewer_func(const void* e1, const void* e2);
void scene_init(struct Scene* scene)
{
@ -821,32 +821,49 @@ void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Re
transform_get_absolute_scale(mesh, &abs_scale);
struct Geometry* geometry = geom_get(mesh->model.geometry_index);
//if(bv_intersect_sphere_ray(&geometry->bounding_sphere, &abs_pos, &abs_scale, ray) == IT_INTERSECT)
if(bv_intersect_bounding_box_ray(&mesh->base.transform.bounding_box, ray) == IT_INTERSECT)
{
out_results->entities_intersected[out_results->num_entities_intersected] = &mesh->base;
out_results->num_entities_intersected++;
}
}
if(out_results->num_entities_intersected > 1)
qsort(out_results->entities_intersected, out_results->num_entities_intersected, sizeof(struct Entity*), &scene_sort_by_distance_from_active_viewer_func);
}
int scene_sort_by_distance_from_active_viewer_func(const void* e1, const void* e2)
struct Entity* scene_ray_intersect_closest(struct Scene* scene, struct Ray* ray)
{
const struct Entity* entity1 = *(struct Entity**)e1;
const struct Entity* entity2 = *(struct Entity**)e2;
struct Scene* scene = game_state_get()->scene;
struct Camera* camera = &scene->cameras[scene->active_camera_index];
float d1 = scene_entity_distance(scene, entity1, camera);
float d2 = scene_entity_distance(scene, entity2, camera);
if(d1 < d2)
return -1;
else if(d1 == d2)
return 0;
else
return 1;
struct Entity* closest = NULL;
float current_closest = 0.f;
for(int i = 0; i < MAX_STATIC_MESHES; i++)
{
struct Static_Mesh* mesh = &scene->static_meshes[i];
if(!(mesh->base.flags & EF_ACTIVE) || (mesh->base.flags & EF_IGNORE_RAYCAST)) continue;
vec3 abs_pos = { 0.f, 0.f, 0.f };
vec3 abs_scale = { 1.f, 1.f, 1.f };
transform_get_absolute_position(mesh, &abs_pos);
transform_get_absolute_scale(mesh, &abs_scale);
struct Geometry* geometry = geom_get(mesh->model.geometry_index);
float distance = bv_distance_ray_bounding_box(ray, &mesh->base.transform.bounding_box);
if(distance != INFINITY && distance >= 0.f)
{
bool assign = false;
if(closest == NULL)
assign = true;
else if(distance > current_closest &&
bv_intersect_bounding_box_ray(&mesh->base.transform.bounding_box, ray) == IT_INSIDE &&
bv_intersect_bounding_boxes(&mesh->base.transform.bounding_box, &closest->transform.bounding_box) != IT_INSIDE)
assign = true;
else if(distance < current_closest)
assign = true;
if(assign)
{
current_closest = distance;
closest = &mesh->base;
}
}
}
return closest;
}
float scene_entity_distance(struct Scene* scene, struct Entity* entity1, struct Entity* entity2)

@ -60,8 +60,9 @@ void scene_entity_parent_set(struct Scene* scene, struct Entity* entity, struct
void scene_entity_parent_reset(struct Scene* scene, struct Entity* entity); // Sets root entity as parent
int scene_entity_archetype_add(struct Scene* scene, const char* filename);
void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Result* out_results);
float scene_entity_distance(struct Scene* scene, struct Entity* entity1, struct Entity* entity2);
void scene_ray_intersect(struct Scene* scene, struct Ray* ray, struct Raycast_Result* out_results);
struct Entity* scene_ray_intersect_closest(struct Scene* scene, struct Ray* ray);
float scene_entity_distance(struct Scene* scene, struct Entity* entity1, struct Entity* entity2);
//
//void scene_init(void);

@ -1,9 +1,10 @@
Todo:
- Implement frustum culling with bounding boxes only or improve frustum-sphere intersection
- Imlpement picking entities of all types in editor
- Determine whether we should enable or disble picking when a tool is active within an editor
- Implement checking if point is inside a bounding box and use that to determine whether a ray is originating inside a bounding box when checking for ray-boundingbox intersection
- Fix issue where if an entity is hoverd in editor and deleted, the game crashes because the hovered variable in editor doesn't know that the entity was deleted
? Only show bounding box for hovered entity
- Fix crash where if an entity is hoverd in editor and deleted, the game crashes because the hovered variable in editor doesn't know that the entity was deleted
- Command to create a placeholder entity of a particular type in a file
- Re-write/Overhaul bounding volumes and ray intersection
- Reduce the opacity of wireframe around selected entity in editor
- Release mouse when window loses focus and limit fps
- Allow picking and selecting other entity types in editor i.e. the ones that don't have meshes

Loading…
Cancel
Save