I'm making a game in openGL using c++ and GLFW libraries.
I made my camera movement function working, here is the code
void Player::mouse_callback(double xpos, double ypos) {
static float lastX = 0.0;
static float lastY = 0.0;
GLfloat xoffset = xpos - lastX;
GLfloat yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;
GLfloat sensitivity = 0.1;
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw -= xoffset;
pitch -= yoffset;
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
this->viewDirection = glm::normalize(front);
cout << "ViewDirection: " << viewDirection.x << " " << viewDirection.y << " " << viewDirection.z << endl;
}
(there is also some glrotate in another class)
glRotatef(this->pov->pitch, 1, 0, 0);
glRotatef(this->pov->yaw, 0, -1, 0);
Now I think that viewDirection is a vector that indicates the direction I'm going.
I tried now to place a marker next to me that stays always in front of me while I am moving the camera, but its positioning is not correct. This is the part of the code from the draw function of the marker class
this->setPosition(this->scene->getPov()->getPosition() + this->scene->getPov()->getViewDirection() * 4.0f );
(the 4x is to place it at some distance from me)
Do you have a clue of how can I make the mark always to stay in front of me?
Related
I'm studying opengl and following the tutorials on the learnopengl website (https://learnopengl.com/)
Could someone please help me convert this camera from the learnopengl tutorial, from free camera to third person ?
I've tried to put the values of the object (character), but I can't make the camera rotate around the player. Only the object walks in front of the camera, if I turn to the side, the object turns along, look like FPS camera and the object (character) being the weapon.
The code to walk (keyboard):
void processKeyboard(Camera_Movement direction, float deltaTime)
{
frontY = Front.y;//para tirar o freeCamera
if (cameraStyle == FPS_CAMERA) {
Front.y = 0;
}
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
Front.y = frontY;
}
Mouse event:
void processMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// Update Front, Right and Up Vectors using the updated Euler angles
updateCameraVectors();
}
To update values:
void updateCameraVectors()
{
// Calculate the new Front vector
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
// Also re-calculate the Right and Up vector
Right = glm::normalize(glm::cross(Front, WorldUp)); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
Up = glm::normalize(glm::cross(Right, Front));
}
And to use:
glm::vec3 playerPosition = glm::vec3(Position.x, terrainY, Position.z) + glm::vec3(1, -0.06f, 1)
has anyone been through this and who could help me?
Thank you
Here is the code I use to create a third person camera:
float pitch = -Pitch;
// I use a 90.0f offset
// but you can play around with that value to suit your needs
float yaw = Yaw - 90.0f;
// constrain pitch so you don't look from below ground level
if (pitch < 0.0) {
pitch = 0.0;
}
// algorithm from ThinMatrix video on third person cameras
float distance = 20.0f;
float x = distance * cos(glm::radians(pitch)) * sin(radians(-yaw));
float y = distance * sin(glm::radians(pitch));
float z = distance * cos(glm::radians(pitch)) * cos(glm::radians(yaw));
glm::vec3 tpCamPos = playerPosition + vec3(-x, y, -z);
I have been using OpenGL to create a 3D first person shooter game. I decided to abstract the camera movement to a separate player class and I have managed to get these methods to work but my only problem is that the camera makes a big jump whenever the mouse first enters the screen.
I know that the fix for this is to check for the first time mouse is moved but I have done this however it still causes a jump. Here is the code:
void player::mouse_input(double &mouse_x_coordinate, double &mouse_y_coordinate, bool &first_mouse)
{
if (first_mouse)
{
last_x = mouse_x_coordinate;
last_y = mouse_y_coordinate;
first_mouse = false;
}
float xoffset = mouse_x_coordinate - last_x;
float yoffset = last_y - mouse_y_coordinate;
last_x = mouse_x_coordinate;
last_y = mouse_y_coordinate;
xoffset *= sensitivity;
yoffset *= sensitivity;
yaw += xoffset;
pitch += yoffset;
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
a_forward_direction = glm::normalize(front);
}
the mouse_x_coordinate and mouse_y_coordinate parameters are global variables containing the mouses x and y coordinates which I got through the glfwSetCursorPosCallback() function.
The first_mouse Boolean is also a global variable initialised as true.
Here is the initialisation of the a_forward_direction vector:
glm::vec3 a_forward_direction = glm::vec3(0.0, 0.0, -1.0);
after following through the mouse_input method, I find that the values for front should match but it still causes a jump.
Can anyone tell me why the mouse still jumps?
So i have been learning opengl and 3d game programming, i started trying to make a camera class and implement movement and viewing with mouse.
Moving works flawlessly but looking around with mouse isn't working as it should.
Looking up without any problems only works when yaw is 0°, then i can look straight up. But when, yaw < 0 or yaw > 0, looking up wont be straight up but more like this ) or ( .
i also noticed that when yaw isn't 0 looking forces yaw to 0 while either looking down or up.
i dont understand why this is happening, why does pitch only work correctly when yaw is 0 and when it is not why does it forced yaw to be 0.
im following a tutorial nothing really seems wrong
processing mouse movement and updating
void Camera::processMouseMovement(GLfloat xOffset, GLfloat yOffset)
{
GLboolean constrainPitch = true;
xOffset *= this->mouseSensitivity;
yOffset *= this->mouseSensitivity;
this->yaw += xOffset;
this->pitch += yOffset;
if(constrainPitch)
{
if(this->pitch > 90.0f)
{
this->pitch = 90.0f;
}
if(this->pitch < -90.0f)
{
this->pitch = -90.0f;
}
}
this->updateCameraVectors();
}
here's is my update function
void Camera::updateCameraVectors()
{
Vector3 front;
Matrix4 mat4;
front.x = cos((DEG2RAD * this->yaw) * cos(DEG2RAD * this->pitch));
front.y = sin(DEG2RAD * this->pitch);
front.z = sin((DEG2RAD * this->yaw) * cos(DEG2RAD * this->pitch));
this->front = mat4.normalize(front);
this->right = mat4.normalize(mat4.cross(this->front, this->worldUp));
this->up = mat4.normalize(mat4.cross(this->right, this->front));
std::cout << "yaw: " << yaw << std::endl;
std::cout << "pitch: " << pitch << std::endl;
}
in main.cpp
Camera camera(Vector3(0.0f, 0.0f, 0.0f));
GLfloat lastX = width / 2.0f;
GLfloat lastY = height / 2.0f;
GLboolean key[1024];
GLboolean firstMouse = true;
GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;
input with glfw, aslo in main.cpp
glfwSetKeyCallback(window, keyCallBack);
glfwSetCursorPosCallback(window, mouseCallBack);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
in main loop
GLfloat currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
glfwPollEvents();
doMovement();
proj = proj.perspective(camera.getZoom(), float(700 / 600), 1.0f, 1000.0f);
glUniformMatrix4fv(uniProj, 1, GL_FALSE, proj.get());
view = camera.getViewMatrix();
mouse callback function
void mouseCallBack(GLFWwindow *window, GLdouble xPos, GLdouble yPos)
{
if(firstMouse)
{
lastX = xPos;
lastY = yPos;
firstMouse = false;
}
GLfloat xOffset = lastX - xPos;
GLfloat yOffset = yPos - lastY;
lastX = xPos;
lastY = yPos;
std::cout << "mouse position x: " << xPos << std::endl;
std::cout << "mouse position y: " << yPos << std::endl;
camera.processMouseMovement(xOffset, yOffset);
}
thank you :)
Assuming front is your average-everyday forward vector, I would calculate it like so:
front.x = cos(DEG2RAD * this->yaw) * sin(DEG2RAD * this->pitch);
front.y = sin(DEG2RAD * this->yaw);
front.z = cos(DEG2RAD * this->yaw) * cos(DEG2RAD * this->pitch);
I'm not keen enough on my trigonometry to understand what your code is doing.
UPDATE: I stared at your code for a while... It looks like the outer set of parenthesis in your code is a mistake. The only other difference between my code and that is my use of sin when calculating forward.x, which would just swap an axis.
I am trying to implement 3D camera mouse rotation. Right now what I can do is only rotate if my mouse is in the bound of the window. What it means is if my window is 1280 width I cannot rotate more if mouse coordinates rich 0 or 1279. I've read that relative mouse should help. It does not work for me though.
before the main loop
SDL_ShowCursor(SDL_DISABLE);
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_WarpMouseInWindow(window, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);
The function that rotates xyz
glm::vec3 MouseMotion(float x, float y)
{
float lastX = SCREEN_WIDTH / 2, lastY = SCREEN_HEIGHT / 2;
float pitch = 0.0f, yaw = -90.0f;
float offsetX = x - lastX;
float offsetY = lastY - y;
lastX = x;
lastY = y;
float sensitivity = 0.3f;
yaw += offsetX * sensitivity;
pitch += offsetY * sensitivity;
if (pitch > 89.0f)
pitch = 89.0f;
if (pitch < -89.0f)
pitch = -89.0f;
glm::vec3 front;
front.x = std::cos(glm::radians(yaw)) * std::cos(glm::radians(pitch));
front.y = std::sin(glm::radians(pitch));
front.z = std::sin(glm::radians(yaw)) * std::cos(glm::radians(pitch));
//std::cout << "Mouse: " << offsetX << ", " << offsetY << std::endl;
//std::cout << "YAW AND PITCH: " << yaw << ", " << pitch << std::endl;
return glm::normalize(front);
}
and the event loop
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
exit(0);
}
if (event.type == SDL_MOUSEMOTION)
{
float mouseX = (float)event.motion.x;
float mouseY = (float)event.motion.y;
cameraFront = MouseMotion(mouseX, mouseY);
}
}
it is working, but only if my mouse is in the bound.
Changing to event.motion.xrel and event.motion.yrel do not fix this. It makes it more bugged because my camera shakes, i.e. going a little bit right and get back to center or left and back to center.
How to make my camera move fully, infinitely move around?
Following on from the comments, here is a list of problems:
You need to call SDL_WarpMouseInWindow every time after an SDL_MOUSEMOTION event to reset the mouse, or it will quickly hit the "bound" you were talking about.
pitch and yaw need to be higher in scope than the game loop, or they will be reset every time and you won't be able to achieve "infinite rotation".
sensitivity is far too high. A typical mouse movement of ~500 units translates to a ~180 degree turning.
Here is an attempt at fixing the above issues, with some code refactoring:
glm::vec3 polarVector(float p, float y)
{
// this form is already normalized
return glm::vec3(std::cos(y) * std::cos(p),
std::sin(p),
std::sin(y) * std::cos(p));
}
// clamp pitch to [-89, 89]
float clampPitch(float p)
{
return p > 89.0f ? 89.0f : (p < -89.0f ? -89.0f : p);
}
// clamp yaw to [-180, 180] to reduce floating point inaccuracy
float clampYaw(float y)
{
float temp = (y + 180.0f) / 360.0f;
return y - ((int)temp - (temp < 0.0f ? 1 : 0)) * 360.0f;
}
int main(int argc, char*args[])
{
// ...
// experiment with this
const float sensitivity = 0.001f;
#define CTR_X (SCREEN_WIDTH / 2)
#define CTR_Y (SCREEN_HEIGHT / 2)
#define RESET_MOUSE SDL_WarpMouseInWindow(window, CTR_X, CTR_Y)
// call once at the start
RESET_MOUSE;
// keep outside the loop
float pitch = 0.0f, yaw = 0.0f;
while (!quit)
{
// ...
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT)
{
exit(0);
}
if (event.type == SDL_MOUSEMOTION)
{
float deltaX = (float)event.motion.x - CTR_X;
float deltaY = (float)event.motion.y - CTR_Y;
yaw = clampYaw(yaw + sensitivity * deltaX);
pitch = clampPitch(pitch - sensitivity * deltaY);
// assumes radians input
cameraFront = polarVector(glm::radians(pitch), glm::radians(yaw));
// reset *every time*
RESET_MOUSE;
}
}
// ...
}
}
I am farly new to Open GL, and c++ and have come across the issue of creating a first person camera. I don't understand matrix math so that makes it all the more harder for me. So far, for calculating the rotation of the camera I have gone for this:
void CameraFP::calculate_view() {
m_view = glm::rotate(m_view, this->get_rotation_x(), glm::vec3(1, 0, 0));
m_view = glm::rotate(m_view, this->get_rotation_y(), glm::vec3(0, 1, 0));
}
That function is called every update call.
For handling the rotation of the camera via the mous, I've done the following:
void CameraFP::process_mouse(sf::Window *app) {
GLfloat mouse_x = app->GetInput().GetMouseX();
GLfloat mouse_y = app->GetInput().GetMouseY();
GLfloat mouse_x_delta = std::max(mouse_x, old_mouse_x) - std::min(mouse_x, old_mouse_x);
GLfloat mouse_y_delta = std::max(mouse_y, old_mouse_y) - std::min(mouse_y, old_mouse_y);
y_rot += mouse_x_delta / (float)app->GetWidth();
x_rot += mouse_y_delta / (float)app->GetHeight();
this->old_mouse_x = mouse_x;
this->old_mouse_y = mouse_y;
app->SetCursorPosition(app->GetWidth() / 2, app->GetHeight() / 2);
}
and for handling the movement I've done the following:
void CameraFP::process_keyboard(sf::Window *app) {
const sf::Input *input = &app->GetInput();
if (input->IsKeyDown(sf::Key::W)) {
position.z += 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::S)) {
position.z -= 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::A)) {
position.x -= 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::D)) {
position.x += 1.0f / 100.0f;
}
}
My issues lie in the fact that my camera does not move in the direction you face, and that it never stops rotating :/. Also, if you could point me to a guide or something on Matrix math that would be awesome :)
Edit 2:'
I just started a new process mouse function, and it a movement along the x axis of the screen as a y rotation for the camera correctly. However, it doesn't matter if I move the mouse left or right, both movements rotate me right. Same with the x axis in 3d space, but this happens downwards. Any ideas on what is causing this?
void CameraFP::process_mouse(sf::Window *app) {
GLfloat mouse_x = app->GetInput().GetMouseX();
GLfloat mouse_y = app->GetInput().GetMouseY();
GLfloat mouse_x_delta = old_mouse_x - mouse_x;
GLfloat mouse_y_delta = old_mouse_y - mouse_y;
if (mouse_x_delta > 0) {
y_rot += mouse_x_delta / (float)app->GetWidth() * 0.1f;
} else if (mouse_x_delta < 0) {
y_rot -= mouse_x_delta / (float)app->GetWidth() * 0.1f;
}
if (mouse_y_delta > 0) {
x_rot += mouse_y_delta / (float)app->GetWidth() * 0.1f;
} else if (mouse_y_delta < 0) {
x_rot -= mouse_y_delta / (float)app->GetWidth() * 0.1f;
}
if (mouse_x != old_mouse_x) {
m_view = glm::rotate(m_view, y_rot, glm::vec3(0, 1, 0));
}
if (mouse_y != old_mouse_y) {
m_view = glm::rotate(m_view, x_rot, glm::vec3(1, 0, 0));
}
this->old_mouse_x = mouse_x;
this->old_mouse_y = mouse_y;
app->SetCursorPosition(app->GetWidth() / 2, app->GetHeight() / 2);
}
I don't have time to look for my camera code at the moment, but what I can tell you right now is, that your movement calculation is simply wrong. You aren't taking the camera rotation into account.
You have to do something like this:
if (input->IsKeyDown(sf::Key::W)) {
position.z += sin(camera_rot_y);
}
else if (input->IsKeyDown(sf::Key::S)) {
position.z -= sin(camera_rot_y);
}
if (input->IsKeyDown(sf::Key::A)) {
position.x -= cos(camera_rot_y);
}
else if (input->IsKeyDown(sf::Key::D)) {
position.x += cos(camera_rot_y);
}
Also you can use "else if"s, because you cannot move forward and backward at the same time.^^
Also, why are you using std::min() and max() in the following code?:
GLfloat mouse_x_delta = std::max(mouse_x, old_mouse_x) - std::min(mouse_x, old_mouse_x);
GLfloat mouse_y_delta = std::max(mouse_y, old_mouse_y) - std::min(mouse_y, old_mouse_y);
If you want to rotate in the opposite direction you need to get a negative delta, which is impossible with your code. Get rid of the min() and max() functions.
BTW: My camera code is not the most efficient (uses rotate instead of direct calculations), but it works.
You didn't show usage of position in CameraFP and m_view but I think problem si here:
void CameraFP::process_keyboard(sf::Window *app) {
const sf::Input *input = &app->GetInput();
if (input->IsKeyDown(sf::Key::W)) {
position.z += 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::S)) {
position.z -= 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::A)) {
position.x -= 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::D)) {
position.x += 1.0f / 100.0f;
}
}
You must multiply matrix, with this translation, and m_view. In matrix multiplication is important order of matrices. First must be m_view because it is main matrix, and you want move forward from m_view rotation. But there is glm namespace and there is method glm::translate which them multiply in right order and you just create glm::vec3 as parameter of that method (translation with x, y, z).
(If you use relative position ... only difference between frames)
So you must change it like this:
void CameraFP::process_keyboard(sf::Window *app) {
const sf::Input *input = &app->GetInput();
glm::vec3 pos;
if (input->IsKeyDown(sf::Key::W)) {
pos.z += 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::S)) {
pos.z -= 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::A)) {
pos.x -= 1.0f / 100.0f;
}
if (input->IsKeyDown(sf::Key::D)) {
pos.x += 1.0f / 100.0f;
}
//Make translation
m_view = glm::translate(m_view, pos);
//Values at position 12, 13, 14 are translation x, y, z
//Save absolute position of camera
position = glm::vec3(m_view[12], m_view[13], m_view[14]);
}
PS: Sorry for my poor english.