diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3db9c3351ab442c30de1699aafcf6cf84ab0544e..506ac54f9e14bc217e208a72cf675f5fb14742a7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories( "${PROJECT_SOURCE_DIR}/src/common/include" "${PROJECT_SOURCE_DIR}/src/controls/include" "${PROJECT_SOURCE_DIR}/src/editor/include" + "${PROJECT_SOURCE_DIR}/src/algo/include" ) set(ROFIBOTS_LIBRARIES_TO_LINK_WITH @@ -19,6 +20,7 @@ set(ROFIBOTS_LIBRARIES_TO_LINK_WITH common controls editor + algo ) message("Including the following libraries to the build:") @@ -38,6 +40,8 @@ add_subdirectory(./controls) message("-- controls") add_subdirectory(./editor) message("-- editor") +add_subdirectory(./algo) +message("-- algo") message("Including the following executables to the build:") add_subdirectory(./studio) diff --git a/src/algo/CMakeLists.txt b/src/algo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9ebd3ef67b9cce39363892ee65d9c6ca3b5ba470 --- /dev/null +++ b/src/algo/CMakeLists.txt @@ -0,0 +1,15 @@ +set(THIS_TARGET_NAME algo) + +add_library(${THIS_TARGET_NAME} + ./include/algo/cursor.hpp + ./src/cursor.cpp + + ) + +set_target_properties(${THIS_TARGET_NAME} PROPERTIES + DEBUG_OUTPUT_NAME "${THIS_TARGET_NAME}_${CMAKE_SYSTEM_NAME}_Debug" + RELEASE_OUTPUT_NAME "${THIS_TARGET_NAME}_${CMAKE_SYSTEM_NAME}_Release" + RELWITHDEBINFO_OUTPUT_NAME "${THIS_TARGET_NAME}_${CMAKE_SYSTEM_NAME}_RelWithDebInfo" + ) + +#install(TARGETS ${THIS_TARGET_NAME} DESTINATION "lib") diff --git a/src/algo/include/algo/cursor.hpp b/src/algo/include/algo/cursor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..28e02897db2da76887e90ca78006a833ba87d654 --- /dev/null +++ b/src/algo/include/algo/cursor.hpp @@ -0,0 +1,23 @@ +#ifndef CURSOR_INCLUDED +#define CURSOR_INCLUDED + +#include <common/node.hpp> +#include <editor/scene.hpp> +#include <osi/mouse.hpp> +#include <osi/window.hpp> +#include <utils/math.hpp> + +#include <memory> +#include <utility> +#include <vector> + +using scene_ptr = std::shared_ptr<Scene>; + +std::pair<float, float> intersect_axis(float ray_direction_a, float ray_position_a, float LH_first_a, float LH_second_a); +std::pair<float, float> intersect(glm::vec3 ray_position, glm::vec3 ray_direction, std::pair<glm::vec3, glm::vec3> LH); +// findIntersection uses functions 'intersect_axis' and 'intersect' and is NOT node tree compatible yet +node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction); + +std::pair<glm::vec3, glm::vec3> getPickRay(const scene_ptr &scene, const osi::Mouse &mouse, const osi::Window &window); + +#endif \ No newline at end of file diff --git a/src/algo/src/cursor.cpp b/src/algo/src/cursor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4eea6f282b6776066decb701d98a799be15a97f9 --- /dev/null +++ b/src/algo/src/cursor.cpp @@ -0,0 +1,118 @@ +#include <algo/cursor.hpp> +#include <gfx/camera.hpp> +#include <gfx/mesh.hpp> +#include <gfx/render.hpp> + +#include <limits> + +std::pair<float, float> intersect_axis(float ray_direction_a, float ray_position_a, + float LH_first_a, float LH_second_a) +{ + float t_low; + float t_high; + if (ray_direction_a == 0 && LH_first_a <= ray_position_a && ray_position_a <= LH_second_a) + { + t_low = -std::numeric_limits<float>::infinity(); + t_high = std::numeric_limits<float>::infinity(); + } + else + { + t_low = glm::min((LH_first_a - ray_position_a) / ray_direction_a, + (LH_second_a - ray_position_a) / ray_direction_a); + t_high = glm::max((LH_first_a - ray_position_a) / ray_direction_a, + (LH_second_a - ray_position_a) / ray_direction_a); + } + + return { t_low, t_high }; +} + +std::pair<float, float> intersect(glm::vec3 ray_position, glm::vec3 ray_direction, + std::pair<glm::vec3, glm::vec3> LH) +{ + auto [ tx, tX ] = intersect_axis(ray_direction.x, ray_position.x, LH.first.x, LH.second.x); + auto [ ty, tY ] = intersect_axis(ray_direction.y, ray_position.y, LH.first.y, LH.second.y); + auto [ tz, tZ ] = intersect_axis(ray_direction.z, ray_position.z, LH.first.z, LH.second.z); + + float t0 = glm::max(tx, glm::max(ty, tz)); + float t1 = glm::min(tX, glm::min(tY, tZ)); + + return {t0, t1}; +} + +node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction) +{ + node_ptr nearest_node = nullptr; + float nearest_t = std::numeric_limits<float>::infinity(); + for (auto &node : scene) + { + for (auto &object : node->getObjects()) + { + auto obj = dynamic_pointer_cast<Mesh>(object); + if (!obj || !obj->isSelectable()) + continue; + + auto LH_world = obj->getAABB().getLHWorld(node); + auto [ t0, t1 ] = intersect(ray_position, ray_direction, LH_world); + + if ( t1 < t0 || t1 < 0) + continue; + if (t0 < 0 && t1 < nearest_t) + { + nearest_t = t1; + nearest_node = node; + } + else if (t0 < nearest_t) + { + nearest_t = t0; + nearest_node = node; + } + } + } + + return nearest_node; +} + +std::pair<glm::vec3, glm::vec3> getPickRay(const scene_ptr &scene, const osi::Mouse &mouse, const osi::Window &window) +{ + camera_ptr camera = scene->getActiveCameras()[0].lock(); // Should be changed to which viewport is in focus + glm::mat4 view = get_view_matrix(camera); + glm::mat4 projection = get_projection_matrix(camera); + + // https://gamedev.stackexchange.com/questions/12360/how-do-you-determine-which-object-surface-the-users-pointing-at-with-lwjgl/12370#12370 + //get the mouse position in screenSpace coords + float aspect_ratio = camera->getWindowSize().x / camera->getWindowSize().y; + float screen_space_X = ((float) mouse.pos().x / (window.size().x / 2) - 1.0f) * aspect_ratio; + float screen_space_Y = (1.0f - (float) mouse.pos().y / (window.size().y / 2)); + + float view_ratio = glm::tan((glm::pi<float>() / (180.f/camera->getFOV()) / 2.0f)); // * zoomFactor; + + screen_space_X = screen_space_X * view_ratio; + screen_space_Y = screen_space_Y * view_ratio; + + //Find the far and near camera spaces + float near_plane = 0.1f; + float far_plane = 100.0f; + glm::vec4 camera_space_near = glm::vec4(screen_space_X * near_plane, screen_space_Y * near_plane, -near_plane, 1); + glm::vec4 camera_space_far = glm::vec4(screen_space_X * far_plane, screen_space_Y * far_plane, -far_plane, 1); + + //Unproject the 2D window into 3D to see where in 3D we're actually clicking + glm::mat4 inv_view = glm::inverse(view); + // Matrix4f.transform(invView, cameraSpaceNear, world_space_near); ?????????????? + glm::vec4 world_space_near = inv_view * camera_space_near; + // Matrix4f.transform(invView, cameraSpaceFar, world_space_far); ??????????????? + glm::vec4 world_space_far = camera_space_far * world_space_far; + + //calculate the ray position and direction + glm::vec3 ray_position = glm::vec3(world_space_near.x, world_space_near.y, world_space_near.z); + glm::vec3 ray_direction = -glm::vec3(world_space_far.x - world_space_near.x, + world_space_far.y - world_space_near.y, + world_space_far.z - world_space_near.z); + + ray_direction = camera->getFrame()->getRotation() * ray_direction; + + /* VISUAL REPRESENTATION OF RAY */ + // addRay(ray_position, ray_direction); + + ray_direction = glm::normalize(ray_direction); + + return {ray_position, ray_direction};} \ No newline at end of file diff --git a/src/controls/CMakeLists.txt b/src/controls/CMakeLists.txt index 4ff3517e4afec4ea300e1a2be2cb6d1ce0b318e4..14a49763f2d5e12e371ca6e5dad1ab39004874c5 100644 --- a/src/controls/CMakeLists.txt +++ b/src/controls/CMakeLists.txt @@ -10,6 +10,8 @@ add_library(${THIS_TARGET_NAME} ./include/controls/obj_control.hpp ./src/obj_control.cpp + ./include/controls/control_hub.hpp + ./src/control_hub.cpp ) set_target_properties(${THIS_TARGET_NAME} PROPERTIES diff --git a/src/controls/include/controls/control_hub.hpp b/src/controls/include/controls/control_hub.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d2425616648a7bb18d3df626acde6094c59b302f --- /dev/null +++ b/src/controls/include/controls/control_hub.hpp @@ -0,0 +1,9 @@ +#ifndef CONTROL_HUB_INCLUDED +#define CONTROL_HUB_INCLUDED + +class ControlHub +{ + +}; + +#endif \ No newline at end of file diff --git a/src/controls/src/control_hub.cpp b/src/controls/src/control_hub.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d67a4774a34a0febf64f85ca0222994fe96e1540 --- /dev/null +++ b/src/controls/src/control_hub.cpp @@ -0,0 +1 @@ +#include <controls/control_hub.hpp> \ No newline at end of file diff --git a/src/studio/include/studio/simulator.hpp b/src/studio/include/studio/simulator.hpp index e513decf389209d38e023467fb63f46f7ac23a75..bf10ee7ac01fa7575d2f93d644bb0d7f2a3a87f3 100644 --- a/src/studio/include/studio/simulator.hpp +++ b/src/studio/include/studio/simulator.hpp @@ -43,7 +43,7 @@ struct Simulator : public osi::Simulator void processInput(); - std::pair<glm::vec3, glm::vec3> getPickRay(); + // std::pair<glm::vec3, glm::vec3> getPickRay(); void selectObject(); void rotateObject(); @@ -72,13 +72,6 @@ private: /* SHADERS */ std::map<std::string, shader_ptr> my_shaders; }; - -std::pair<float, float> intersect_axis(float ray_direction_a, float ray_position_a, float LH_first_a, float LH_second_a); -std::pair<float, float> intersect(glm::vec3 ray_position, glm::vec3 ray_direction, std::pair<glm::vec3, glm::vec3> LH); -// findIntersection uses functions 'intersect_axis' and 'intersect' and is NOT node tree compatible yet -// Also unsure if it should be a free function -node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction); - } #endif diff --git a/src/studio/src/simulator.cpp b/src/studio/src/simulator.cpp index bf71180c2395dcbcc56527f0c910074b84cfc3a6..e5a0a0407e2f768bd5f183f03fc5c95cb39ab4b4 100644 --- a/src/studio/src/simulator.cpp +++ b/src/studio/src/simulator.cpp @@ -1,5 +1,6 @@ #include <studio/simulator.hpp> +#include <algo/cursor.hpp> // TEMPORARY #include <filein/obj_loader.hpp> #include <gfx/render.hpp> #include <gui/ui.hpp> @@ -92,58 +93,12 @@ void Simulator::processInput() ASSUMPTION(glGetError() == GL_NO_ERROR); } -std::pair<glm::vec3, glm::vec3> Simulator::getPickRay() -{ - camera_ptr camera = scene->getActiveCameras()[0].lock(); // Should be changed to which viewport is in focus - glm::mat4 view = get_view_matrix(camera); - glm::mat4 projection = get_projection_matrix(camera); - - // https://gamedev.stackexchange.com/questions/12360/how-do-you-determine-which-object-surface-the-users-pointing-at-with-lwjgl/12370#12370 - //get the mouse position in screenSpace coords - float aspect_ratio = camera->getWindowSize().x / camera->getWindowSize().y; - float screen_space_X = ((float) mouse().pos().x / (window().size().x / 2) - 1.0f) * aspect_ratio; - float screen_space_Y = (1.0f - (float) mouse().pos().y / (window().size().y / 2)); - - float view_ratio = glm::tan((glm::pi<float>() / (180.f/camera->getFOV()) / 2.0f)); // * zoomFactor; - - screen_space_X = screen_space_X * view_ratio; - screen_space_Y = screen_space_Y * view_ratio; - - //Find the far and near camera spaces - float near_plane = 0.1f; - float far_plane = 100.0f; - glm::vec4 camera_space_near = glm::vec4(screen_space_X * near_plane, screen_space_Y * near_plane, -near_plane, 1); - glm::vec4 camera_space_far = glm::vec4(screen_space_X * far_plane, screen_space_Y * far_plane, -far_plane, 1); - - //Unproject the 2D window into 3D to see where in 3D we're actually clicking - glm::mat4 inv_view = glm::inverse(view); - // Matrix4f.transform(invView, cameraSpaceNear, world_space_near); ?????????????? - glm::vec4 world_space_near = inv_view * camera_space_near; - // Matrix4f.transform(invView, cameraSpaceFar, world_space_far); ??????????????? - glm::vec4 world_space_far = camera_space_far * world_space_far; - - //calculate the ray position and direction - glm::vec3 ray_position = glm::vec3(world_space_near.x, world_space_near.y, world_space_near.z); - glm::vec3 ray_direction = -glm::vec3(world_space_far.x - world_space_near.x, - world_space_far.y - world_space_near.y, - world_space_far.z - world_space_near.z); - - ray_direction = camera->getFrame()->getRotation() * ray_direction; - - /* VISUAL REPRESENTATION OF RAY */ - // addRay(ray_position, ray_direction); - - ray_direction = glm::normalize(ray_direction); - - return {ray_position, ray_direction}; -} - void Simulator::selectObject() { if (!mouse().just_released().contains("MouseLeft")) return; - auto [ ray_position, ray_direction ] = getPickRay(); + auto [ ray_position, ray_direction ] = getPickRay(scene, mouse(), window()); auto nearest_node = find_intersection(scene->getScene(), ray_position, ray_direction); @@ -166,7 +121,7 @@ void Simulator::moveObject() return; } - auto [ ray_position, ray_direction ] = getPickRay(); + auto [ ray_position, ray_direction ] = getPickRay(scene, mouse(), window()); // Initial click not onto the selected object if (!object_moving && find_intersection(scene->getScene(), ray_position, ray_direction) != scene->getSelection()) @@ -202,7 +157,7 @@ void Simulator::addObject() glm::quat rotation = scene->getSelection()->getFrame()->getRotation(); glm::vec3 scale = scene->getSelection()->getFrame()->getScale(); - auto [ ray_position , ray_direction ] = getPickRay(); + auto [ ray_position , ray_direction ] = getPickRay(scene, mouse(), window()); float distance = glm::length(ray_position - position); @@ -255,75 +210,6 @@ void Simulator::processMouse() } } -/* INDEPENDENT FUNCTIONS */ - -std::pair<float, float> intersect_axis(float ray_direction_a, float ray_position_a, - float LH_first_a, float LH_second_a) -{ - float t_low; - float t_high; - if (ray_direction_a == 0 && LH_first_a <= ray_position_a && ray_position_a <= LH_second_a) - { - t_low = -std::numeric_limits<float>::infinity(); - t_high = std::numeric_limits<float>::infinity(); - } - else - { - t_low = glm::min((LH_first_a - ray_position_a) / ray_direction_a, - (LH_second_a - ray_position_a) / ray_direction_a); - t_high = glm::max((LH_first_a - ray_position_a) / ray_direction_a, - (LH_second_a - ray_position_a) / ray_direction_a); - } - - return { t_low, t_high }; -} - -std::pair<float, float> intersect(glm::vec3 ray_position, glm::vec3 ray_direction, - std::pair<glm::vec3, glm::vec3> LH) -{ - auto [ tx, tX ] = intersect_axis(ray_direction.x, ray_position.x, LH.first.x, LH.second.x); - auto [ ty, tY ] = intersect_axis(ray_direction.y, ray_position.y, LH.first.y, LH.second.y); - auto [ tz, tZ ] = intersect_axis(ray_direction.z, ray_position.z, LH.first.z, LH.second.z); - - float t0 = glm::max(tx, glm::max(ty, tz)); - float t1 = glm::min(tX, glm::min(tY, tZ)); - - return {t0, t1}; -} - -node_ptr find_intersection(const std::vector<node_ptr> &scene, glm::vec3 ray_position, glm::vec3 ray_direction) -{ - node_ptr nearest_node = nullptr; - float nearest_t = std::numeric_limits<float>::infinity(); - for (auto &node : scene) - { - for (auto &object : node->getObjects()) - { - auto obj = dynamic_pointer_cast<Mesh>(object); - if (!obj || !obj->isSelectable()) - continue; - - auto LH_world = obj->getAABB().getLHWorld(node); - auto [ t0, t1 ] = intersect(ray_position, ray_direction, LH_world); - - if ( t1 < t0 || t1 < 0) - continue; - if (t0 < 0 && t1 < nearest_t) - { - nearest_t = t1; - nearest_node = node; - } - else if (t0 < nearest_t) - { - nearest_t = t0; - nearest_node = node; - } - } - } - - return nearest_node; -} - /* UNUSED */ std::vector<float> get_normals(std::vector<unsigned int> &indices, std::vector<float> &vertices) {