Skip to content

Commit

Permalink
Teste esfera-AABB; renderiza texto para ray cast e mouse coords
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardoazzi committed Aug 6, 2024
1 parent c89e70c commit f9d02d1
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 52 deletions.
5 changes: 3 additions & 2 deletions include/collisions.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

#include "globals.h"

bool CubeIntersectsCube(AABB a, AABB b);
bool RayIntersectsCube(glm::vec4 rayOrigin, glm::vec3 rayDirection, AABB cube);
bool AABBIntersectsAABB(AABB a, AABB b);
bool RayIntersectsAABB(glm::vec4 rayOrigin, glm::vec3 rayDirection, AABB cube);
bool SphereIntersectsAABB(Sphere sphere, AABB aabb);
AABB GetWorldAABB(SceneObject obj, glm::mat4 model);
glm::vec3 MouseRayCasting(glm::mat4 projectionMatrix, glm::mat4 viewMatrix);

Expand Down
16 changes: 15 additions & 1 deletion include/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ struct AABB {
glm::vec3 max;
};

/**
* @brief Struct que representa uma esfera.
*
* Contém as informações necessárias para representar uma esfera no espaço tridimensional.
* Ela armazena o centro da esfera e o raio da mesma.
*/
struct Sphere {
glm::vec3 center;
float radius;
};


// Abaixo definimos variáveis globais utilizadas em várias funções do código.

// A cena virtual é uma lista de objetos nomeados, guardados em um dicionário
Expand Down Expand Up @@ -181,4 +193,6 @@ extern bool D_key_pressed;

// Variável para modificar o tipo de câmera (look-at/free camera)
extern bool freeCamera;
extern bool lookatCamera;
extern bool lookatCamera;

extern glm::vec3 g_rayPoint;
3 changes: 2 additions & 1 deletion include/textrendering.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ void TextRendering_PrintMatrixVectorProductDivW(GLFWwindow* window, glm::mat4 M,
// Funções abaixo renderizam como texto na janela OpenGL algumas matrizes e
// outras informações do programa. Definidas após main().
void TextRendering_ShowModelViewProjection(GLFWwindow* window, glm::mat4 projection, glm::mat4 view, glm::mat4 model, glm::vec4 p_model);
void TextRendering_ShowEulerAngles(GLFWwindow* window);
void TextRendering_ShowMouseCoords(GLFWwindow* window);
void TextRendering_ShowProjection(GLFWwindow* window);
void TextRendering_ShowFramesPerSecond(GLFWwindow* window);
void TextRendering_ShowRayCast(GLFWwindow* window);

#endif // _TEXT_RENDERING_H
58 changes: 44 additions & 14 deletions src/collisions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,32 @@
* @param b O segundo cubo AABB.
* @return True se os cubos AABB se intersectam, false caso contrário.
*/
bool CubeIntersectsCube(AABB a, AABB b){
bool AABBIntersectsAABB(AABB a, AABB b){
int intersectedAxes = 0;

if (a.min.x <= b.max.x && a.max.x >= b.min.x) intersectedAxes++;
if (a.min.y <= b.max.y && a.max.y >= b.min.y) intersectedAxes++;
if (a.min.z <= b.max.z && a.max.z >= b.min.z) intersectedAxes++;

std::cout << "Eixos com intersecção: em " << intersectedAxes << std::endl;

return intersectedAxes == 3;
}

/**
* Verifica se um raio intersecta com um cubo.
*
* @param rayOrigin O ponto de origem do raio.
* @param rayDirection A direção do raio.
* @param cube O eixo-alinhado bounding box (AABB) que representa o cubo.
* @return True se o raio intersectar com o cubo, false caso contrário.
*
* Adaptado de: https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection.html
* Referência:
* Shirley, P., Wald, I., Marrs, A. (2021). Ray Axis-Aligned Bounding Box Intersection.
* In: Marrs, A., Shirley, P., Wald, I. (eds) Ray Tracing Gems II. Apress, Berkeley, CA.
* https://doi.org/10.1007/978-1-4842-7185-8_2
*
*/

// Adaptado de: https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-box-intersection.html
bool RayIntersectsCube(glm::vec4 rayOrigin, glm::vec3 rayDirection, AABB cube){
bool RayIntersectsAABB(glm::vec4 rayOrigin, glm::vec3 rayDirection, AABB cube){
float tmin_x = (cube.min.x - rayOrigin.x) / rayDirection.x;
float tmax_x = (cube.max.x - rayOrigin.x) / rayDirection.x;

Expand Down Expand Up @@ -63,6 +69,34 @@ bool RayIntersectsCube(glm::vec4 rayOrigin, glm::vec3 rayDirection, AABB cube){
return true;
}

/**
* Verifica se uma esfera intersecta uma AABB (Axis-Aligned Bounding Box).
* Referência: https://learnopengl.com/In-Practice/2D-Game/Collisions/Collision-detection
*
* @param sphere A esfera a ser verificada, definida por seu centro e seu raio.
* @param aabb O AABB a ser testada.
* @return true se houver interseção, false caso contrário.
*/
bool SphereIntersectsAABB(Sphere sphere, AABB aabb) {
float distance = 0.0f;

// Calcula o ponto mais próximo da AABB ao centro da esfera
for (int i = 0; i < 3; ++i) {
float min = aabb.min[i];
float max = aabb.max[i];
float center = sphere.center[i];

if (center < min) {
distance += (min - center) * (min - center);
} else if (center > max) {
distance += (center - max) * (center - max);
}
}

// Verifica se a distância ao quadrado é menor ou igual ao raio da esfera ao quadrado
return distance <= (sphere.radius * sphere.radius);
}

/**
* @brief Calcula o axis-aligned bounding box (AABB) para um objeto da cena em coordenadas de mundo.
*
Expand All @@ -75,11 +109,10 @@ AABB GetWorldAABB(SceneObject obj, glm::mat4 model){
glm::vec4 min = model * glm::vec4(obj.bbox_min.x, obj.bbox_min.y, obj.bbox_min.z, 1.0f);
glm::vec4 max = model * glm::vec4(obj.bbox_max.x, obj.bbox_max.y, obj.bbox_max.z, 1.0f);

// @DEBUG
// std::cout << "BBox Local Min: " << obj.bbox_min.x << " " << obj.bbox_min.y << " " << obj.bbox_min.z << std::endl;
// std::cout << "BBox Local Max: " << obj.bbox_max.x << " " << obj.bbox_max.y << " " << obj.bbox_max.z << std::endl;
std::cout << "BBox World Min: " << min.x << " " << min.y << " " << min.z << std::endl;
std::cout << "BBox World Max: " << max.x << " " << max.y << " " << max.z << std::endl;
// Quando há rotação, os valores mínimos e máximos dos pontos da bounding box podem ser corrigidos.
for (int i = 0; i < 3; i++) {
if (min[i] > max[i]) std::swap(min[i], max[i]);
}

// Retorna a bounding box em coordenadas de mundo
return AABB{min, max};
Expand Down Expand Up @@ -112,9 +145,6 @@ glm::vec3 MouseRayCasting(glm::mat4 projectionMatrix, glm::mat4 viewMatrix){
glm::vec3 ray_world = glm::vec3(glm::inverse(viewMatrix) * ray_camera);
ray_world = glm::normalize(ray_world);

// @DEBUG
// std::cout << "Ray World: " << ray_world.x << " " << ray_world.y << " " << ray_world.z << std::endl;

return ray_world;

}
5 changes: 3 additions & 2 deletions src/globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ float g_TorsoPositionY = 0.0f;

bool g_UsePerspectiveProjection = true;

bool g_ShowInfoText = true;
bool g_ShowInfoText = false;

GLuint g_GpuProgramID = 0;
GLint g_model_uniform;
Expand All @@ -41,4 +41,5 @@ GLint g_bbox_max_uniform;

GLuint g_NumLoadedTextures = 0;

double g_LastCursorPosX, g_LastCursorPosY;
double g_LastCursorPosX, g_LastCursorPosY;
glm::vec3 g_rayPoint;
66 changes: 38 additions & 28 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ int main(int argc, char* argv[])
// movimento no modo câmera livre
glm::vec4 camera_movement = glm::vec4(0.0f,0.0f,0.0f,0.0f);

// Inicializa a flag de colisão com a mesa
bool isTableCollision = false;

// Ficamos em um loop infinito, renderizando, até que o usuário feche a janela
while (!glfwWindowShouldClose(window))
{
Expand Down Expand Up @@ -163,6 +166,7 @@ int main(int argc, char* argv[])

// Câmera livre
if (freeCamera == true){
camera_movement.y = 1.0f; // Fixa o movimento no eixo Y para evitar que a câmera livre suba ou desça
camera_position_c = glm::vec4(x_fixed,y_fixed,z_fixed,1.0f) + camera_movement; // Ponto "c", centro da câmera
camera_view_vector = glm::vec4(-x,-y,-z,0.0f); // Vetor "view", sentido para onde a câmera está virada
};
Expand Down Expand Up @@ -241,6 +245,7 @@ int main(int argc, char* argv[])

// Guardamos matriz model atual na pilha
PushMatrix(model);

// Desenhamos o modelo da mesa
model *= Matrix_Rotate_Z(M_PI/2.0f)
* Matrix_Rotate_X(M_PI/2.0f)
Expand All @@ -265,14 +270,6 @@ int main(int argc, char* argv[])
glUniform4f(g_bbox_max_uniform, bbox_max.x, bbox_max.y, bbox_max.z, 1.0f);
float tableHeight = bbox_max.z - bbox_min.z;
float tableWidth = bbox_max.x - bbox_min.x;
float tableDepth = bbox_max.y - bbox_min.y;

// Cálculo da altura da lâmpada
bbox_min = g_VirtualScene["lightbulb_01"].bbox_min;
bbox_max = g_VirtualScene["lightbulb_01"].bbox_max;
glUniform4f(g_bbox_min_uniform, bbox_min.x, bbox_min.y, bbox_min.z, 1.0f);
glUniform4f(g_bbox_max_uniform, bbox_max.x, bbox_max.y, bbox_max.z, 1.0f);
float lightBulbHeight = bbox_max[1] - bbox_min[1];

PushMatrix(model);
// Posição da altura dos circuitos. 0.025 é por conta da altura da mesa corresponder à medida entre a base e a borda da mesa, que é mais alta que a parte onde os objetos estarão posicionados
Expand Down Expand Up @@ -599,31 +596,42 @@ int main(int argc, char* argv[])
// @TODO: os else if serão refatorados!
// ================================================================
// Projeta um ray casting em coord. do mundo a partir das coord. do mouse
glm::vec3 mousePoint = MouseRayCasting(projectionMatrix, viewMatrix);
glm::vec3 rayVec = glm::normalize(glm::vec4(mousePoint, 1.0f));

std::cout << "Mouse point: " << mousePoint.x << " " << mousePoint.y << " " << mousePoint.z << std::endl;
std::cout << "Ray vector: " << rayVec.x << " " << rayVec.y << " " << rayVec.z << std::endl;

// if (CubeIntersectsCube(wirePlaneBbox,wireBulbBbox)){
g_rayPoint = MouseRayCasting(projectionMatrix, viewMatrix);
glm::vec3 rayVec = glm::normalize(glm::vec4(g_rayPoint, 1.0f));
// if (AABBIntersectsAABB(wirePlaneBbox,wireBulbBbox)){
// std::cout << "Plano de Wire e Lâmpada do Wire intersectam" << std::endl;
// }
// else if (CubeIntersectsCube(wirePlaneBbox,andBulbBbox)){
// else if (AABBIntersectsAABB(wirePlaneBbox,andBulbBbox)){
// std::cout << "Plano de Wire e Lâmpada do AND intersectam" << std::endl;
// }

if (RayIntersectsCube(camera_position_c, rayVec, wireBulbBbox)){
if (RayIntersectsAABB(camera_position_c, rayVec, wireBulbBbox)){
std::cout << "!!Ray intersecta a lâmpada do Wire" << std::endl;
}
if (RayIntersectsCube(camera_position_c, rayVec, andInput1Bbox)){
if (RayIntersectsAABB(camera_position_c, rayVec, andInput1Bbox)){
std::cout << "!!Ray intersecta o input 2 do AND" << std::endl;
}
if (RayIntersectsCube(camera_position_c, rayVec, andInput2Bbox)){
if (RayIntersectsAABB(camera_position_c, rayVec, andInput2Bbox)){
std::cout << "!!Ray intersecta o input 1 do AND" << std::endl;
}
if (RayIntersectsCube(camera_position_c, rayVec, tableBbox)){
if (RayIntersectsAABB(camera_position_c, rayVec, tableBbox)){
std::cout << "!!Ray intersecta a mesa!!" << std::endl;
}
if (RayIntersectsAABB(camera_position_c, rayVec, wirePlaneBbox)){
std::cout << "!!Ray intersecta o plano!!" << std::endl;
}
// Define a hitsphere da câmera
Sphere cameraSphere = {camera_position_c, 0.2f};

// Aumenta a AABB da mesa em y para detectar a colisão com a hitsphere da câmera
tableBbox.max.y += 100.0f;

if (SphereIntersectsAABB(cameraSphere, tableBbox)){
std::cout << "Camera intersecta a mesa!!" << std::endl;
isTableCollision = true;
} else {
isTableCollision = false;
}

glUniformMatrix4fv(g_view_uniform, 1, GL_FALSE, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(g_projection_uniform, 1, GL_FALSE, glm::value_ptr(projectionMatrix));
Expand All @@ -633,14 +641,15 @@ int main(int argc, char* argv[])
// glUniformMatrix4fv(g_model_uniform, 1 , GL_FALSE , glm::value_ptr(model));
// glUniform1i(g_object_id_uniform, PLANE_AND);
// DrawVirtualObject("the_plane");

// Imprimimos na tela os ângulos de Euler que controlam a rotação do
// terceiro cubo.
TextRendering_ShowEulerAngles(window);

// Imprimimos na informação sobre a matriz de projeção sendo utilizada.
TextRendering_ShowProjection(window);

// Imprimimos na tela as coordenadas do mouse
TextRendering_ShowMouseCoords(window);

// Imprimimos a informação sobre o ray casting
TextRendering_ShowRayCast(window);

// Imprimimos na tela informação sobre o número de quadros renderizados
// por segundo (frames per second).
TextRendering_ShowFramesPerSecond(window);
Expand All @@ -651,11 +660,12 @@ int main(int argc, char* argv[])
float delta_t = current_time - prev_time;
prev_time = current_time;

// Realiza movimentação de objetos
if (W_key_pressed)
// Realiza movimentação de objetos.
// A flag isTableCollision é um protótipo de resolução de colisão entre a câmera e a mesa
if (W_key_pressed && !isTableCollision) {
// Movimenta câmera para frente
camera_movement += -camera_w * speed * delta_t;

}
if (A_key_pressed)
// Movimenta câmera para esquerda
camera_movement += -camera_u * speed * delta_t;
Expand Down
21 changes: 17 additions & 4 deletions src/textrendering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,21 +359,34 @@ void TextRendering_ShowModelViewProjection(
TextRendering_PrintMatrixVectorProductMoreDigits(window, viewport_mapping, p_ndc, -1.0f, 1.0f-26*pad, 1.0f);
}

// Escrevemos na tela os ângulos de Euler definidos nas variáveis globais
// g_AngleX, g_AngleY, e g_AngleZ.
void TextRendering_ShowEulerAngles(GLFWwindow* window)
// Escrevemos na tela as coordenadas do mouse na janela
void TextRendering_ShowMouseCoords(GLFWwindow* window)
{
if ( !g_ShowInfoText )
return;

float pad = TextRendering_LineHeight(window);

char buffer[80];
snprintf(buffer, 80, "Euler Angles rotation matrix = Z(%.2f)*Y(%.2f)*X(%.2f)\n", g_AngleZ, g_AngleY, g_AngleX);
snprintf(buffer, 80, "Cursor = X(%.2f), Y(%.2f)\n", g_LastCursorPosX, g_LastCursorPosY);

TextRendering_PrintString(window, buffer, -1.0f+pad/10, -1.0f+2*pad/10, 1.0f);
}

// Escrevemos na tela as coordenadas do ponto de ray casting
void TextRendering_ShowRayCast(GLFWwindow* window)
{
if ( !g_ShowInfoText )
return;

float pad = TextRendering_LineHeight(window);

char buffer[80];
snprintf(buffer, 80, "Raycast = x(%.2f), y(%.2f), z(%.2f)\n", g_rayPoint.x, g_rayPoint.y, g_rayPoint.z);

TextRendering_PrintString(window, buffer, -1.0f+pad/10, -1.0f+2*pad/1, 1.0f);
}

// Escrevemos na tela qual matriz de projeção está sendo utilizada.
void TextRendering_ShowProjection(GLFWwindow* window)
{
Expand Down

0 comments on commit f9d02d1

Please sign in to comment.