Skip to content

Commit

Permalink
Fixed water collider generation and improved entity raycasting
Browse files Browse the repository at this point in the history
  • Loading branch information
patricklbell committed Dec 19, 2022
1 parent 173e4ae commit a0a12a2
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 131 deletions.
Binary file added data/levels/water_test.level
Binary file not shown.
Binary file added data/levels/water_test.level.0.tga
Binary file not shown.
Binary file added data/levels/water_test.level.1.tga
Binary file not shown.
Binary file added data/levels/water_test.level.2.tga
Binary file not shown.
Binary file added data/levels/water_test.level.3.tga
Binary file not shown.
32 changes: 17 additions & 15 deletions include/utilities/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,16 @@ struct Raycast {
glm::vec3 direction;

Raycast(glm::vec3 _origin, glm::vec3 _direction) : origin(_origin), direction(_direction) {}
};

// This contains the result of a raycast, anything other than hit and t is not garaunteed to be updated
struct RaycastResult {
bool hit = false;
operator bool() const { return hit; }

// This contains the result of a raycast, anything other than hit and t is not garaunteed to be updated
struct Result {
bool hit = false;
unsigned int indice; // @note this is the actual array index, so you don't need to multiply by 3
float t = FLT_MAX, u = -1.0, v = -1.0; // This distance to the intersection, the uv coordinates on the triangle
glm::vec3 normal;
} result;
unsigned int indice; // @note this is the actual array index, so you don't need to multiply by 3
float t = FLT_MAX, u = -1.0, v = -1.0; // This distance to the intersection, the uv coordinates on the triangle
glm::vec3 normal;
};

struct AABB {
Expand All @@ -42,14 +44,14 @@ struct AABB {
AABB&& transformAABB(AABB& aabb, glm::mat4 transform);

Raycast mouseToRaycast(glm::ivec2 mouse_position, glm::ivec2 screen_size, glm::mat4 inv_vp);
bool raycastTriangleCull(const glm::vec3 vertices[3], Raycast& raycast);
bool raycastTriangle(const glm::vec3 vertices[3], Raycast& raycast);
bool raycastTriangles(glm::vec3* vertices, unsigned int* indices, const int num_indices, const glm::mat4x4& vertices_transform, Raycast& raycast);
bool raycastTrianglesTest(glm::vec3* vertices, unsigned int* indices, const int num_indices, const glm::mat4x4& vertices_transform, Raycast& raycast);
bool raycastPlane(const glm::vec3& center, const glm::vec3& normal, Raycast& raycast);
bool raycastBoundedPlane(const glm::vec3& center, const glm::vec3& normal, const glm::vec3& bounds, Raycast& raycast);
bool raycastCube(const glm::vec3& center, const glm::vec3& scale, Raycast& raycast);
bool raycastAabb(const AABB& aabb, Raycast& raycast);
RaycastResult raycastTriangleCull(const glm::vec3 vertices[3], Raycast& raycast);
RaycastResult raycastTriangle(const glm::vec3 vertices[3], Raycast& raycast);
RaycastResult raycastTriangles(glm::vec3* vertices, unsigned int* indices, const int num_indices, const glm::mat4x4& vertices_transform, Raycast& raycast);
RaycastResult raycastTrianglesTest(glm::vec3* vertices, unsigned int* indices, const int num_indices, const glm::mat4x4& vertices_transform, Raycast& raycast);
RaycastResult raycastPlane(const glm::vec3& center, const glm::vec3& normal, Raycast& raycast);
RaycastResult raycastBoundedPlane(const glm::vec3& center, const glm::vec3& normal, const glm::vec3& bounds, Raycast& raycast);
RaycastResult raycastCube(const glm::vec3& center, const glm::vec3& scale, Raycast& raycast);
RaycastResult raycastAabb(const AABB& aabb, Raycast& raycast);

float distanceBetweenLines(const glm::vec3& l1_origin, const glm::vec3& l1_direction, const glm::vec3& l2_origin, const glm::vec3& l2_direction, float& l1_t, float& l2_t);

Expand Down
57 changes: 27 additions & 30 deletions src/controls/behaviour.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,59 +19,60 @@
#include "editor.hpp"
#include "game_behaviour.hpp"

Raycast raycastEntities(Raycast& raycast, EntityManager& entity_manager, bool colliders=false) {
auto tmp_raycast = raycast;
RaycastResult raycastEntities(Raycast& raycast, EntityManager& entity_manager, bool colliders=false) {
RaycastResult result, entity_result, submesh_result;
for (int i = 0; i < ENTITY_COUNT; ++i) {
auto e = entity_manager.entities[i];
if (e == nullptr) continue;

tmp_raycast.result.hit = false;
entity_result.hit = false;
if (!colliders && e->type & EntityType::WATER_ENTITY) {
auto w_e = (WaterEntity*)e;

glm::vec3 bounds{ w_e->scale[0][0], w_e->scale[1][1], w_e->scale[2][2] };
raycastBoundedPlane(w_e->position + bounds*glm::vec3(0.5,0,0.5), glm::vec3(0, 1, 0), bounds*0.5f, tmp_raycast);
entity_result = raycastBoundedPlane(w_e->position + bounds*glm::vec3(0.5,0,0.5), glm::vec3(0, 1, 0), bounds, raycast);
}
else if (!colliders && e->type & EntityType::MESH_ENTITY && ((MeshEntity*)e)->mesh != nullptr) {
const auto& m_e = (MeshEntity*)e;
const auto& mesh = m_e->mesh;

submesh_result.hit = false;
for (int j = 0; j < mesh->num_submeshes; j++) {
auto model = createModelMatrix(mesh->transforms[j], m_e->position, m_e->rotation, m_e->scale);

auto t_aabb = transformAABB(mesh->aabbs[j], model);
if (!raycastAabb(t_aabb, tmp_raycast) || tmp_raycast.result.t > raycast.result.t)
if (!(submesh_result = raycastAabb(t_aabb, raycast)) || submesh_result.t > result.t)
continue;
if (raycastTriangles(mesh->vertices, mesh->indices, mesh->num_indices, model, tmp_raycast)) {
if (tmp_raycast.result.hit && tmp_raycast.result.t < raycast.result.t) {
raycast = tmp_raycast;
raycast.result.indice = i;

submesh_result.hit = false;
if (submesh_result = raycastTriangles(mesh->vertices, mesh->indices, mesh->num_indices, model, raycast)) {
if (submesh_result.t < result.t) {
entity_result = submesh_result;
}
}
}
continue;
}
else if (colliders && (e->type & EntityType::COLLIDER_ENTITY)) {
auto c = (ColliderEntity*)entity_manager.entities[i];
auto bounds = glm::vec3(c->collider_scale[0][0], c->collider_scale[1][1], c->collider_scale[2][2]);
raycastCube(c->collider_position + bounds/2.0f, bounds, tmp_raycast);
entity_result = raycastCube(c->collider_position + bounds/2.0f, bounds, raycast);
}

if (tmp_raycast.result.hit && tmp_raycast.result.t < raycast.result.t) {
raycast = tmp_raycast;
raycast.result.indice = i;
if (entity_result.hit && entity_result.t < result.t) {
result = entity_result;
result.indice = i;
}
}

return raycast;
return result;
}

Raycast raycastEntityWithMouse(const Camera& camera, EntityManager& entity_manager) {
RaycastResult raycastEntityWithMouse(const Camera& camera, EntityManager& entity_manager) {
auto raycast = mouseToRaycast(Controls::mouse_position, glm::ivec2(window_width, window_height), camera.inv_vp);
return raycastEntities(raycast, entity_manager);
}

Raycast raycastColliderWithMouse(const Camera& camera, EntityManager& entity_manager) {
RaycastResult raycastColliderWithMouse(const Camera& camera, EntityManager& entity_manager) {
auto raycast = mouseToRaycast(Controls::mouse_position, glm::ivec2(window_width, window_height), camera.inv_vp);
return raycastEntities(raycast, entity_manager, true);
}
Expand Down Expand Up @@ -170,10 +171,8 @@ void handleEditorControls(EntityManager*& entity_manager, AssetManager& asset_ma
if (!io.WantCaptureMouse) {
if (Controls::editor.right_mouse.state == Controls::RELEASE && (glfwGetTime() - Controls::editor.right_mouse.last_press) < mouse_hold_threshold) {
if (Editor::editor_mode == EditorMode::COLLIDERS) {
glm::vec3 n;
auto raycast = raycastColliderWithMouse(camera, *entity_manager);
if (raycast.result.hit) {
entity_manager->deleteEntity(entity_manager->entities[raycast.result.indice]->id);
if (auto raycast = raycastColliderWithMouse(camera, *entity_manager)) {
entity_manager->deleteEntity(entity_manager->entities[raycast.indice]->id);
}
}
else {
Expand All @@ -185,13 +184,12 @@ void handleEditorControls(EntityManager*& entity_manager, AssetManager& asset_ma
{
case EditorMode::ENTITY:
{
auto raycast = raycastEntityWithMouse(camera, *entity_manager);
if (raycast.result.hit) {
if (auto raycast = raycastEntityWithMouse(camera, *entity_manager)) {
if (!glfwGetKey(window, GLFW_KEY_LEFT_SHIFT)) {
Editor::selection.clear();
}

auto pick_e = entity_manager->entities[raycast.result.indice];
auto pick_e = entity_manager->entities[raycast.indice];
Editor::selection.toggleEntity(*entity_manager, pick_e);
} else {
Editor::selection.clear();
Expand All @@ -200,19 +198,18 @@ void handleEditorControls(EntityManager*& entity_manager, AssetManager& asset_ma
}
case EditorMode::COLLIDERS:
{
auto raycast = raycastColliderWithMouse(camera, *entity_manager);
if (raycast.result.hit) {
auto pick_c = (ColliderEntity*)entity_manager->entities[raycast.result.indice];
if (auto result = raycastColliderWithMouse(camera, *entity_manager)) {
auto pick_c = (ColliderEntity*)entity_manager->entities[result.indice];

std::cout << "Collided, normal: " << raycast.result.normal << "\n";
std::cout << "Collided, normal: " << result.normal << "\n";
auto c = (ColliderEntity*)copyEntity((Entity*)pick_c);
c->id = entity_manager->getFreeId();
c->mesh = c->mesh;

c->position = pick_c->position + raycast.result.normal;
c->position = pick_c->position + result.normal;
c->scale = pick_c->scale;
c->rotation = pick_c->rotation;
c->collider_position = pick_c->collider_position + raycast.result.normal;
c->collider_position = pick_c->collider_position + result.normal;
c->collider_scale = pick_c->collider_scale;
c->collider_rotation = pick_c->collider_rotation;

Expand Down
47 changes: 24 additions & 23 deletions src/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1089,24 +1089,24 @@ TransformType editTransform(Camera &camera, glm::vec3 &pos, glm::quat &rot, glm:
return change_type;
}

bool raycastGizmoMeshAxis(Raycast& raycast, Mesh& mesh, glm::mat3 axis, glm::mat3 positions, glm::mat3 scales) {
auto tmp_raycast = raycast;
static RaycastResult raycastGizmoMeshAxis(Raycast& raycast, Mesh& mesh, glm::mat3 axis, glm::mat3 positions, glm::mat3 scales) {
RaycastResult result;
for (int i = 0; i < 3; ++i) {
const auto direction = axis[i];

static const auto mesh_up = glm::vec3(0, 1, 0); // The up direction of the mesh should be aligned with y axis
auto transform = createModelMatrix(positions[i], glm::quat(direction, mesh_up), scales[i]);

if (raycastTriangles(mesh.vertices, mesh.indices, mesh.num_indices, transform, tmp_raycast)) {
if (tmp_raycast.result.t < raycast.result.t) {
if (raycastPlane(positions[i], direction, tmp_raycast)) {
raycast = tmp_raycast;
raycast.result.indice = i;
if (auto tmp_result = raycastTriangles(mesh.vertices, mesh.indices, mesh.num_indices, transform, raycast)) {
if (tmp_result.t < result.t) {
if (raycastPlane(positions[i], direction, raycast)) {
result = tmp_result;
result.indice = i;
}
}
}
}
return raycast.result.hit;
return result;
}

bool editorRotationGizmo(glm::vec3& pos, glm::quat& rot, glm::mat3& scl, const Camera& camera, float snap = 1.0, bool do_snap = false) {
Expand All @@ -1130,8 +1130,8 @@ bool editorRotationGizmo(glm::vec3& pos, glm::quat& rot, glm::mat3& scl, const C

bool initial_selection = false;
if(Controls::editor.left_mouse.state == Controls::PRESS) {
if (raycastGizmoMeshAxis(raycast, ring_mesh, axis, positions, distance * scales)) {
selected_ring = raycast.result.indice;
if (auto result = raycastGizmoMeshAxis(raycast, ring_mesh, axis, positions, distance * scales)) {
selected_ring = result.indice;
initial_selection = true;
}
} else if (Controls::editor.left_mouse.state & Controls::RELEASED) {
Expand All @@ -1148,8 +1148,8 @@ bool editorRotationGizmo(glm::vec3& pos, glm::quat& rot, glm::mat3& scl, const C
const auto normal = axis[selected_ring];

// Calculate which direction on the gizmo the user has moved to
if (raycastPlane(pos, normal, raycast)) {
glm::vec3 rot_dir = glm::normalize(raycast.origin + raycast.result.t * raycast.direction - pos);
if (auto result = raycastPlane(pos, normal, raycast)) {
glm::vec3 rot_dir = glm::normalize(raycast.origin + result.t * raycast.direction - pos);
if (initial_selection)
rot_dir_prev = rot_dir;

Expand Down Expand Up @@ -1204,9 +1204,9 @@ bool editorTranslationGizmo(glm::vec3 &pos, glm::quat &rot, glm::mat3 &scl, Came

bool initial_selection = false;
if (Controls::editor.left_mouse.state == Controls::PRESS) {
if (raycastGizmoMeshAxis(raycast, arrow_mesh, axis, positions, distance * scales * 1.1f)) {
selected_arrow = raycast.result.indice;
selection_offset = glm::normalize(raycast.origin + raycast.result.t * raycast.direction - pos);
if (auto result = raycastGizmoMeshAxis(raycast, arrow_mesh, axis, positions, distance * scales * 1.1f)) {
selected_arrow = result.indice;
selection_offset = glm::normalize(raycast.origin + result.t * raycast.direction - pos);
initial_selection = true;
}
}
Expand Down Expand Up @@ -1270,9 +1270,9 @@ bool editorScalingGizmo(glm::vec3 &pos, glm::quat &rot, glm::mat3 &scl, Camera &

bool initial_selection = false;
if (Controls::editor.left_mouse.state == Controls::PRESS) {
if (raycastGizmoMeshAxis(raycast, block_arrow_mesh, axis, positions, distance * scales * 1.1f)) {
selected_arrow = raycast.result.indice;
selection_offset = glm::normalize(raycast.origin + raycast.result.t * raycast.direction - pos);
if (auto result = raycastGizmoMeshAxis(raycast, block_arrow_mesh, axis, positions, distance * scales * 1.1f)) {
selected_arrow = result.indice;
selection_offset = glm::normalize(raycast.origin + result.t * raycast.direction - pos);
initial_selection = true;
}
}
Expand Down Expand Up @@ -1320,15 +1320,16 @@ bool editorScalingGizmo(glm::vec3 &pos, glm::quat &rot, glm::mat3 &scl, Camera &

void drawWaterDebug(WaterEntity* w, const Camera &camera, bool flash = false) {
bindBackbuffer();
gl_state.set_flags(GlFlags::CULL | GlFlags::DEPTH_READ);
gl_state.set_flags(GlFlags::CULL);

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glEnable(GL_LINE_SMOOTH);

gl_state.bind_program(Shaders::debug.program());
auto mvp = camera.vp * createModelMatrix(w->position, glm::quat(), w->scale);
auto model = createModelMatrix(w->position, glm::quat(), w->scale);
auto mvp = camera.vp * model;
glUniformMatrix4fv(Shaders::debug.uniform("mvp"), 1, GL_FALSE, &mvp[0][0]);
glUniformMatrix4fv(Shaders::debug.uniform("model"), 1, GL_FALSE, &w->position[0]);
glUniformMatrix4fv(Shaders::debug.uniform("model"), 1, GL_FALSE, &model[0][0]);
glUniform4f(Shaders::debug.uniform("color"), 1.0, 1.0, 1.0, 1.0);
glUniform4f(Shaders::debug.uniform("color_flash_to"), 1.0, 0.0, 1.0, 1.0);
glUniform1f(Shaders::debug.uniform("time"), glfwGetTime());
Expand Down Expand Up @@ -1715,7 +1716,7 @@ void drawEditorGui(EntityManager &entity_manager, AssetManager &asset_manager){
else
ImGui::TextWrapped("Multiple Entities Selected");

const float img_w = glm::min(sidebar_w - pad, 70.0f);
const float img_w = glm::min(sidebar_w - pad, 150.0f);
static const std::vector<std::string> image_file_extensions = { ".jpg", ".png", ".bmp", ".tiff", ".tga" };
static bool editing_gizmo_position_offset = false;

Expand Down Expand Up @@ -2104,7 +2105,7 @@ void drawEditorGui(EntityManager &entity_manager, AssetManager &asset_manager){
}
}
void* tex_water_collider = (void*)(intptr_t)graphics::water_collider_buffers[graphics::water_collider_final_fbo];
ImGui::Image(tex_water_collider, ImVec2(sidebar_w, sidebar_w));
ImGui::Image(tex_water_collider, ImVec2(img_w, img_w));

if (ImGui::Button("Update", button_size)) {
RenderQueue q;
Expand Down
8 changes: 4 additions & 4 deletions src/graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,7 @@ void bindDrawWaterColliderMap(const RenderQueue& q, WaterEntity* water) {
gl_state.bind_framebuffer(water_collider_fbos[0]);
gl_state.bind_viewport(WATER_COLLIDER_SIZE, WATER_COLLIDER_SIZE);

gl_state.add_flags(GlFlags::DEPTH_WRITE);
glClearColor(0, 0, 0, 1);
gl_state.set_flags(GlFlags::DEPTH_WRITE);
glClear(GL_COLOR_BUFFER_BIT);

gl_state.bind_program(Shaders::plane_projection.program());
Expand All @@ -383,7 +382,6 @@ void distanceTransformWaterFbo(WaterEntity* water) {
gl_state.set_flags(GlFlags::NONE);
gl_state.bind_program(Shaders::jump_flood.program());


glUniform1f(Shaders::jump_flood.uniform("num_steps"), (float)num_steps);
glUniform2f(Shaders::jump_flood.uniform("resolution"), WATER_COLLIDER_SIZE, WATER_COLLIDER_SIZE);

Expand All @@ -404,7 +402,8 @@ void distanceTransformWaterFbo(WaterEntity* water) {
drawQuad();
}

glGenerateTextureMipmap(water_collider_buffers[(num_steps + 1) % 2]);
gl_state.bind_texture_any(water_collider_buffers[(num_steps + 1) % 2]);
glGenerateMipmap(GL_TEXTURE_2D);
water_collider_final_fbo = (num_steps + 1) % 2;

gl_state.bind_program(Shaders::gaussian_blur.program());
Expand All @@ -418,6 +417,7 @@ void distanceTransformWaterFbo(WaterEntity* water) {
}

// Reset viewport
gl_state.bind_framebuffer(GL_FALSE);
gl_state.bind_viewport(window_width, window_height);
}

Expand Down
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ int main() {

AssetManager local_assets;
initDefaultLevel(loaded_level, local_assets);
//loadLevel(loaded_level, local_assets, "data/levels/water_test.level");
Cameras::update_cameras_for_level();

double last_time = glfwGetTime();
Expand Down
Loading

0 comments on commit a0a12a2

Please sign in to comment.