322 lines
21 KiB
C++
322 lines
21 KiB
C++
/***********************************************************************************************************************
|
|
*
|
|
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
|
|
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
|
|
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
|
|
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
|
|
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
|
|
* scope and manner of such use.
|
|
*
|
|
***********************************************************************************************************************/
|
|
|
|
#include "camera.h"
|
|
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
|
|
/**********************************************************************************************************************/
|
|
/*initialize_position: this function must be call once just after the camera has been created. It calculates the */
|
|
/* camera's position with the the model's bounding box. the initial position corresponds to an */
|
|
/* isometric view. The various member parameters are also initialized */
|
|
/*in : -bbox, used to calculate the appropriate camera position */
|
|
/*out: -orbital_center, the point which will be the center of the bounding, it also will be the orbital center of the */
|
|
/* camera movement */
|
|
/* -max_bbx_length, the diagonal length of the bounding box */
|
|
/* -position, the 3D point where the camera is located in the global space */
|
|
/* -up, the 3D vector of the camera which shows the up direction of the camera from his position */
|
|
/* -right, the 3D vector which shows the right direction of the camera from his position */
|
|
/* -front, the 3D vector which shows the front direction of the camera from his position, normal vector from */
|
|
/* position to the orbital center */
|
|
/* -start_position, 3D point of the initial position, allow the user to come back at the first view */
|
|
/* -start_right, 3D vector of the initial right vector, allow the user to come back at the first view */
|
|
/* -start_front, 3D vector of the initial front vector, allow the user to come back at the first view */
|
|
/* -start_up, 3D vector of the initial front vector, allow the user to come back at the first view */
|
|
/* -current_view, this setting is initialized to the isometric view, then we could switch step by step to the */
|
|
/* other views */
|
|
/*return : void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::initialize_position(const utils::geometry::BoundingBox& bbox)
|
|
{
|
|
orbital_center = bbox.center();
|
|
max_bbx_length = (float)glm::distance(bbox.min, bbox.max);
|
|
|
|
position = orbital_center - (max_bbx_length * 1.5f) * glm::vec3(-glm::sqrt(2.f) / 2.f, glm::sqrt(2.f) / 2.f, 0.f);
|
|
|
|
current_view = EView::ISO;
|
|
|
|
up = glm::vec3(0.f, 0.f, 1.f);
|
|
right = glm::vec3(glm::sqrt(2.f) / 2.f, glm::sqrt(2.f) / 2.f, 0.f);
|
|
front = glm::vec3(-glm::sqrt(2.f) / 2.f, glm::sqrt(2.f) / 2.f, 0.f);
|
|
|
|
start_position = position;
|
|
start_right = right;
|
|
start_front = front;
|
|
start_up = up;
|
|
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*get_view_matrix: a wrapper to the glm lookAt function which builds a "look at" view matrix based on the camera */
|
|
/* parameters. */
|
|
/*in :-void */
|
|
/*out:-void */
|
|
/*return: A glm::mat4 matrix corresponding to the "look at" of the camera position */
|
|
/**********************************************************************************************************************/
|
|
glm::mat4 Camera::get_view_matrix()
|
|
{
|
|
return glm::lookAt(position, position + front, up);
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*calculate_far: called by compute_projection_matrix in the main loop of the drawing, it is */
|
|
/* particularly useful when zooming, and the far plan will move closer or further away, then the model */
|
|
/* won't be cut off. */
|
|
/*in :-void */
|
|
/*out:-void */
|
|
/*return: a float which will be the new far to apply in the rendering model */
|
|
/**********************************************************************************************************************/
|
|
float Camera::calculate_far()
|
|
{
|
|
float far = glm::distance(orbital_center, position) + max_bbx_length / 2.f;
|
|
far *= 1.1f;
|
|
return far;
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*calculate_far: called by compute_projection_matrix in the main loop of the drawing, it is */
|
|
/* particularly useful when the distance is very great, the near performs better whenit is closer to */
|
|
/* the model */
|
|
/*in :-void */
|
|
/*out:-void */
|
|
/*return: a float which will be the new near to apply to the rendering model */
|
|
/**********************************************************************************************************************/
|
|
float Camera::calculate_near()
|
|
{
|
|
float near = glm::distance(orbital_center, position) - max_bbx_length / 2.f;
|
|
near *= 0.9f;
|
|
if (near <= 0)
|
|
{
|
|
near = max_bbx_length/1000.f;
|
|
}
|
|
return near;
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/* rotate_camera: private method to rotate the model, the camera is actually moved around the axis (axe_rotate), */
|
|
/* passing through the centre of the orbitand through an angle alpha(in parameter). */
|
|
/*in : -axe_rotate, the vector qualifying the axis passing through the orbital centre around which the camera will */
|
|
/* rotate */
|
|
/* -alpha, a float defining the angle of rotation */
|
|
/*out: -position, the point defining the new camera position after the rotation */
|
|
/* -front, the front vector after the rotation */
|
|
/* -right, the right vector after the rotation */
|
|
/* -up, the right vector after the rotation */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::rotate_camera(glm::vec3 axe_rotate, float alpha)
|
|
{
|
|
glm::mat4 rotate = glm::mat4(1.f);
|
|
glm::vec4 translate(-orbital_center.x, -orbital_center.y, -orbital_center.z, 1.f);
|
|
rotate = glm::rotate(rotate, alpha, axe_rotate);
|
|
|
|
position = glm::vec4(position, 1.f) + translate;
|
|
position = glm::vec4(position, 1.f) * rotate;
|
|
position = glm::vec4(position, 1.f) - translate;
|
|
|
|
front = glm::vec4(front, 1.f) * rotate;
|
|
right = glm::vec4(right, 1.f) * rotate;
|
|
up = glm::vec4(up, 1.f) * rotate;
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*set_to_origin: called after pressing the "O" button, to place the camera in the position it was in when the model */
|
|
/* was opened. */
|
|
/*in : -void */
|
|
/*out: -position, the point defining the camera position will be defined as it was at the begining */
|
|
/* -right, the right vector of the camera will be defined as it was at the beginning */
|
|
/* -front, the front vector of the camera will be defined as it was at the beginning */
|
|
/* -up, the up vector of the camera will be defined as it was at the beginning */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::set_to_origin()
|
|
{
|
|
position = start_position;
|
|
right = start_right;
|
|
front = start_front;
|
|
up = start_up;
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*process_keyboard: called after a keyboard event to move the camera by rotation or translation */
|
|
/*in : -direction, an EMovement enabling to know how to move the camera */
|
|
/*out: -position, the 3D point of the camera will be changed with the appropriate move */
|
|
/* -front (indirectly by rotate_camera), the front camera vector after the move */
|
|
/* -right (indirectly by rotate_camera), the right camera vector after the move */
|
|
/* -up (indirectly by rotate_camera), the up camera vector after the move */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::process_keyboard(Camera::EMovement direction)
|
|
{
|
|
switch (direction)
|
|
{
|
|
case Camera::EMovement::ZOOM_IN:
|
|
position += front * (max_bbx_length * 0.05f);
|
|
break;
|
|
case Camera::EMovement::ZOOM_OUT:
|
|
position -= front * (max_bbx_length * 0.05f);
|
|
break;
|
|
case Camera::EMovement::FRONT_DIRECT:
|
|
rotate_camera(front, glm::radians(1.f));
|
|
break;
|
|
case Camera::EMovement::FRONT_INV:
|
|
rotate_camera(front, glm::radians(-1.f));
|
|
break;
|
|
case Camera::EMovement::RIGHT_DIRECT:
|
|
rotate_camera(right, glm::radians(1.f));
|
|
break;
|
|
case Camera::EMovement::RIGHT_INV:
|
|
rotate_camera(right, glm::radians(-1.f));
|
|
break;
|
|
case Camera::EMovement::UP_DIRECT:
|
|
rotate_camera(up, glm::radians(1.f));
|
|
break;
|
|
case Camera::EMovement::UP_INV:
|
|
rotate_camera(up, glm::radians(-1.f));
|
|
break;
|
|
case Camera::EMovement::MV_RIGHT:
|
|
position -= right * (max_bbx_length * 0.05f);
|
|
break;
|
|
case Camera::EMovement::MV_LEFT:
|
|
position += right * (max_bbx_length * 0.05f);
|
|
break;
|
|
case Camera::EMovement::MV_UP:
|
|
//we lower the camera to move the model up
|
|
position -= up * (max_bbx_length * 0.05f);
|
|
break;
|
|
case Camera::EMovement::MV_DOWN:
|
|
position += up * (max_bbx_length * 0.05f);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*process_mouse_rotation: called by a mouse move event with his left button pressed and not release, this functions */
|
|
/* allows the user to move the 3D model by rotation around right, front, or up axes depending */
|
|
/* */
|
|
/*in : -xOffset, the mouse move in X axes since the last capture of the mouse position */
|
|
/* -yOffset, the mouse move in Y axes since the last capture of the mouse position */
|
|
/* -screenWidth, the current width of the opengl window where the model is displayed */
|
|
/* -screenHeight, the current length of the opengl window where the model is displayed */
|
|
/*out: -position (indirectly by rotate_camera), the 3D point of the camera will be changed with the appropriate move */
|
|
/* -front (indirectly by rotate_camera), the front camera vector after the move */
|
|
/* -right (indirectly by rotate_camera), the right camera vector after the move */
|
|
/* -up (indirectly by rotate_camera), the up camera vector after the move */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::process_mouse_rotation(float xOffset, float yOffset, int screenWidth, int screenHeight)
|
|
{
|
|
if (glm::abs(screenWidth) > glm::epsilon<float>() && glm::abs(screenHeight) > glm::epsilon<float>())
|
|
{
|
|
const float alphaX = xOffset / screenWidth * glm::pi<float>();
|
|
const float alphaY = yOffset / screenHeight * glm::pi<float>();
|
|
rotate_camera(up, alphaX);
|
|
rotate_camera(right, -alphaY);
|
|
}
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*process_mouse_translation: called by a mouse move event with his left button pressed and not release simultaneously */
|
|
/* with the shift key presses, this functions allows the user to move the 3D model by */
|
|
/* parallel translation with the screen */
|
|
/* */
|
|
/*in : -xOffset, the mouse move in X axes since the last capture of the mouse position */
|
|
/* -yOffset, the mouse move in Y axes since the last capture of the mouse position */
|
|
/*out: -position (indirectly by rotate_camera), the 3D point of the camera will be changed with the appropriate move */
|
|
/* -front (indirectly by rotate_camera), the front camera vector after the move */
|
|
/* -right (indirectly by rotate_camera), the right camera vector after the move */
|
|
/* -up (indirectly by rotate_camera), the up camera vector after the move */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::process_mouse_translation(float xOffset, float yOffset)
|
|
{
|
|
position -= right * xOffset * max_bbx_length / 1000.f;
|
|
position -= up * yOffset * max_bbx_length / 1000.f;
|
|
}
|
|
|
|
/**********************************************************************************************************************/
|
|
/*process_mouse_scroll: called by a mouse scroll event, the purpose of this function is to move the camera closer or */
|
|
/* further away */
|
|
/*in : -is_zoom_in, a boolean to know if the camera has to move closer or further */
|
|
/*out: -position, the 3D point which will be the new position of the camea */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::process_mouse_scroll(bool is_zoom_in)
|
|
{
|
|
float sign = is_zoom_in ? 2.f : -2.f;
|
|
position += sign * front * ( max_bbx_length * 0.05f );
|
|
}
|
|
|
|
|
|
/**********************************************************************************************************************/
|
|
/*process_switch_view: called by a mouse right click event, the purpose of this function is to swith the model view */
|
|
/* between the usual view know: Isometric, top, bottom, left, right,front and back */
|
|
/*in : void */
|
|
/*out: -position, the 3D point of the new position of the camera in the switched view */
|
|
/* -up, the 3D vector of the up camera in the switched view */
|
|
/* -right, the 3D vector of the right camera in the switched view */
|
|
/* -front, the 3D vector of the front camera in the switched view */
|
|
/*return: void */
|
|
/**********************************************************************************************************************/
|
|
void Camera::process_switch_view()
|
|
{
|
|
current_view = (Camera::EView)(((int)current_view + 1) % 7);
|
|
switch (current_view)
|
|
{
|
|
case Camera::EView::ISO:
|
|
position = orbital_center - (max_bbx_length * 1.5f) * glm::vec3(-glm::sqrt(2.f)/2.f, glm::sqrt(2.f) / 2.f, 0.f);
|
|
up = glm::vec3(0.f, 0.f, 1.f);
|
|
right = glm::vec3(glm::sqrt(2.f) / 2.f, glm::sqrt(2.f) / 2.f, 0.f);
|
|
front = glm::vec3(-glm::sqrt(2.f) / 2.f, glm::sqrt(2.f) / 2.f, 0.f);
|
|
break;
|
|
case Camera::EView::TOP:
|
|
position = orbital_center + (max_bbx_length * 1.5f) * glm::vec3(0.f, 0.f, 1.f);
|
|
up = glm::vec3(0.f, 1.f, 0.f);
|
|
right = glm::vec3(-1.f, 0.f, 0.f);
|
|
front = glm::vec3(0.f, 0.f, -1.f);
|
|
break;
|
|
case Camera::EView::BOTTOM:
|
|
position = orbital_center - (max_bbx_length * 1.5f) * glm::vec3(0.f, 0.f, 1.f);
|
|
up = glm::vec3(0.f, -1.f, 0.f);
|
|
right = glm::vec3(1.f, 0.f, 0.f);
|
|
front = glm::vec3(0.f, 0.f, 1.f);
|
|
break;
|
|
case Camera::EView::LEFT:
|
|
position = orbital_center - (max_bbx_length * 1.5f) * glm::vec3(1.f, 0.f, 0.f);
|
|
up = glm::vec3(0.f, 0.f, 1.f);
|
|
right = glm::vec3(0.f, -1.f, 0.f);
|
|
front = glm::vec3(1.f, 0.f, 0.f);
|
|
break;
|
|
case Camera::EView::RIGHT:
|
|
position = orbital_center + (max_bbx_length * 1.5f) * glm::vec3(1.f, 0.f, 0.f);
|
|
up = glm::vec3(0.f, 0.f, 1.f);
|
|
right = glm::vec3(0.f, 1.f, 0.f);
|
|
front = glm::vec3(-1.f, 0.f, 0.f);
|
|
break;
|
|
case Camera::EView::FRONT:
|
|
position = orbital_center - (max_bbx_length * 1.5f) * glm::vec3(0.f, 1.f, 0.f);
|
|
up = glm::vec3(0.f, 0.f, 1.f);
|
|
right = glm::vec3(1.f, 0.f, 0.f);
|
|
front = glm::vec3(0.f, 1.f, 0.f);
|
|
break;
|
|
case Camera::EView::BACK:
|
|
position = orbital_center + (max_bbx_length * 1.5f) * glm::vec3(0.f, 1.f, 0.f);
|
|
up = glm::vec3(0.f, 0.f, 1.f);
|
|
right = glm::vec3(-1.f, 0.f, 0.f);
|
|
front = glm::vec3(0.f, -1.f, 0.f);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} |