Rotating camera with mouse

Started by
4 comments, last by LeeBrowm 9 years, 9 months ago

Hello,

I've decided implement camera rotation based on mouse input, but somewhere during the process it went wrong.

Basically I tried following this tutorial: http://www.opengl-tutorial.org/beginners-tutorials/tutorial-6-keyboard-and-mouse/

Instead of working properly the programm actually rotates camera but in a very peculiar manner: no matter in what direction I move my mouse the image always moves in the same direction and then flips and so on.

After doing the tutorial I ended up with something like this;


void Camera::Rotate(Sint32 dx, Sint32 dy){
    m_horizontalAngle+= mouseSpeed*float(width/2-dx);
    m_verticalAngle+=mouseSpeed*float(height/2-dy);
    m_forward.x = cosf(m_verticalAngle)*sinf(m_horizontalAngle);
    m_forward.y = sinf(m_verticalAngle);
    m_forward.z = cosf(m_verticalAngle)*cosf(m_horizontalAngle);
    m_right = glm::vec3(sinf(m_horizontalAngle-3.14f/2.0f),0,cosf(m_horizontalAngle-3.14f/2.0f));
    m_up=glm::cross(m_right,m_forward);
}

The function itself is called from the main loop


void mainLoop(Display* disp, World * wrld){
  SDL_Event e;
  while(SDL_PollEvent(&e)){
   
    if(e.type==SDL_MOUSEMOTION){
        std::cout<<"("<<e.motion.xrel<<","<<e.motion.yrel<<")"<<std::endl;
        wrld->CameraPtr()->Rotate(e.motion.xrel,e.motion.yrel);

    }
  }
  wrld->Draw();
}

wrld->Draw() is made this way


void World::Draw(){
    glClearColor(0.2f,0.3f,0.1f,1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glm::mat4 VP =m_camera->GetViewProjection();
    for(unsigned int i =0; i<m_list.size();i++){
        m_list[i]->TexturePtr()->Bind(0);
        m_shader.Update(*(m_list[i]->PositionPtr()),*(m_list[i]->RotationPtr()),*(m_list[i]->ScalePtr()),VP);
        m_list[i]->MeshPtr()->Draw();
    }
}

m_camera->GetViewProjection() is the member of Camera class


inline glm::mat4 GetViewProjection() const{
return m_perspective* glm::lookAt(m_position,m_position+m_forward,m_up); }

m_shader.Update(..) is


void Shader::Update(glm::vec3& position,glm::vec3& rotation, glm::vec3& scale, glm::mat4 viewProjection)
{
        glm::mat4 posMatrix = glm::translate(position);
        glm::mat4 rotXMatrix = glm::rotate(rotation.x,glm::vec3(1,0,0));
        glm::mat4 rotYMatrix = glm::rotate(rotation.y,glm::vec3(0,1,0));
        glm::mat4 rotZMatrix = glm::rotate(rotation.z,glm::vec3(0,0,1));
        glm::mat4 scaleMatrix = glm::scale(scale);

        glm::mat4 wmat = viewProjection* posMatrix * rotZMatrix * rotYMatrix * rotXMatrix * scaleMatrix;
        glUniformMatrix4fv(m_uniforms[TRANSFORM_U], 1, GL_FALSE,&wmat[0][0]);
}

Without the rotation part all the object display correctly and I can move in space using WASD keys.

I would greatly appreciate any help:)

Advertisement

m_horizontalAngle+= mouseSpeed*float(width/2-dx);
m_verticalAngle+=mouseSpeed*float(height/2-dy);

Since you are adding to the angle, you should be adding 0 when the mouse doesnt move. However, if the mouse doesnt move (dx=dy=0), you end up adding mouseSpeed*float(width/2) horizontally and same for vertical.

If you want to move the camera when the mouse moves, remove the width/2 and height/2 parts and it might work like you intended it to.

If you want to move the camera whenever the mouse is not at the center of the screen, pass in the mouse position relative to the center of the screen (mouse.x-width/2, mouse.y-height/2) instead of the delta position.

o3o

It doesn't actually do anything unless I move the mouse since it's called only if(e.type==SDL_MOUSEMOTION)

The problem is caused by mixing absolute and relative mouse co-ordinates. In the mainLoop you read relative co-ordinates xrel and yrel, i.e. the "mouse is moved by" co-ordinates. In the Camera::Rotate routine you then subtract that from the half width and half height, resp., what hints that you wanted to use absolute co-ordinates instead. Because your mouse motion is always lower than half width or height, you always get positive value for angle calculations, and hence your camera moves always in the same direction.

So, try to use e.motin.x and e.motion.y in the mainLoop. This should give you absolute co-ordinates. The effect is, of course, that the position but its motion of the mouse pointer defines your camera rotation angles. If that is not your desire then follow Waterlimon's advice "remove the width/2 and height/2 parts and it might work like you intended it to".

Thank you, I will try that.

Never mind the text below, I found a solution to it - checking for multiple key presses in each update.

Thanks to your help I managed to get it working correctly. Though I have another question now. While I am rotating my camera with a mouse or move it with keys the picture on the screen really seems jittery, it doesn't feel smooth. I've tried recording it on a video (with glc) but the movement/ rotation on the video is smooth. Any idea what might cause this? Right now my loop looks like this


void mainLoop(Display* disp, World * wrld){
    m_previousTime = m_currentTime;
    m_currentTime =SDL_GetTicks();
    m_dt=float(m_currentTime-m_previousTime);
  SDL_Event e;
  while(SDL_PollEvent(&e)){
    if(e.type == SDL_QUIT){
      disp->Close();
    }
    if(e.type == SDL_KEYDOWN)
    {
        switch(e.key.keysym.sym)
        {
            case SDLK_ESCAPE:
                disp->Close();
            case SDLK_w:
                *(wrld->CameraPtr()->PositionPtr())+=*(wrld->CameraPtr()->ForwardPtr())**(wrld->CameraPtr()->SpeedPtr())*m_dt;
                break;
            case SDLK_s:
                *(wrld->CameraPtr()->PositionPtr())-=*(wrld->CameraPtr()->ForwardPtr())**(wrld->CameraPtr()->SpeedPtr())*m_dt;
                break;
            case SDLK_a:
                *(wrld->CameraPtr()->PositionPtr())-=*(wrld->CameraPtr()->RightPtr())**(wrld->CameraPtr()->SpeedPtr())*m_dt;  
                break;
            case SDLK_d:
                *(wrld->CameraPtr()->PositionPtr())+=*(wrld->CameraPtr()->RightPtr())**(wrld->CameraPtr()->SpeedPtr())*m_dt;
                 break;

        }
    }
    if(e.type==SDL_MOUSEMOTION){
 
        wrld->CameraPtr()->Rotate(-e.motion.xrel,-e.motion.yrel);

    }
    }
    wrld->Draw();
    disp->Update();
}

This topic is closed to new replies.

Advertisement