problem with camera movement(SDL2 + OpenGL) - SDL_Event

im trying to create flying 3d camera which can dynamically change it’s direction and can recognize if player presses many buttons in the same time. I made it, but there is a problem, when i press as example W + D all is ok, camera is moving, but if i start rotating camera , movement slows down , is there any easier way to make flying 3d camera which changes direction dynamically and can move even if i press multiple keys?

int main(int argc,char** argv){
    bool quit = false;
    SDL_Event e;

    if(!init()){
        printf("na");
    }
    else{
        glUseProgram(programShader);

        glm::vec3 cameraStep = glm::vec3(0.f,0.f,0.f);

        unsigned int projectionLoc, viewLoc, modelLoc;
        float movementSensitivity = 0.0005f, cameraSensitivity = 0.01f;
    
        glm::mat4 projection = glm::mat4(1.f);
        glm::mat4 view = glm::mat4(1.f);
        glm::mat4 model = glm::mat4(1.f);
    
        glm::vec3 cameraPos = glm::vec3(0.0,0.0,2.0);
        glm::vec3 cameraUp = glm::vec3(0.0,1.f,0.0);
        glm::vec3 cameraFront = glm::vec3(0.0,0.0,-1.f);
    
        view = glm::lookAt(cameraPos,cameraPos + cameraFront, cameraUp);
    
        projection = glm::perspective(glm::radians(45.f),1.f,0.1f,100.f);
    
        projectionLoc = glGetUniformLocation(programShader,"projection");
        viewLoc = glGetUniformLocation(programShader,"view");
        modelLoc = glGetUniformLocation(programShader,"model");
        
        // std::cout << projectionLoc << " " << viewLoc << " " << modelLoc << std::endl;

        glUniformMatrix4fv(projectionLoc,1,GL_FALSE,glm::value_ptr(projection));
        glUniformMatrix4fv(viewLoc,1,GL_FALSE,glm::value_ptr(view));
        glUniformMatrix4fv(modelLoc,1,GL_FALSE,glm::value_ptr(model));
        
        glBindVertexArray(VAOs[0]);
        glBindTexture(GL_TEXTURE_2D,textures[0]);

        float frameBasedCorrection, thisTicks = 0, previousTicks = 0;
        glm::vec3 lastPosFrontSpeed, lastNegFrontSpeed, lastPosSideSpeed, lastNegSideSpeed;

        int previousMouseX, previousMouseY;
        float pitch = 0, yaw =-90;

        

        while(!quit){
            thisTicks = SDL_GetTicks();
            frameBasedCorrection = thisTicks - previousTicks;
            previousTicks = thisTicks;

            float movementCorrection = movementSensitivity * frameBasedCorrection;
            float cameraCorrection = cameraSensitivity * frameBasedCorrection;

            while(SDL_PollEvent(&e)!=0){
                
                if(e.type == SDL_QUIT){quit = true;}
                else if(e.type == SDL_KEYDOWN && e.key.repeat == 0){
                    switch (e.key.keysym.sym){
                        case SDLK_w: lastPosFrontSpeed = cameraFront * movementCorrection; 
                        cameraStep += lastPosFrontSpeed; break;
                        case SDLK_s: lastNegFrontSpeed = cameraFront * movementCorrection; 
                        cameraStep -= lastNegFrontSpeed; break;
                        case SDLK_d: lastPosSideSpeed = glm::normalize(glm::cross(cameraFront, cameraUp)) * movementCorrection;
                        cameraStep += lastPosSideSpeed; break;
                        case SDLK_a: lastNegSideSpeed = glm::normalize(glm::cross(cameraFront, cameraUp)) * movementCorrection;
                        cameraStep -= lastNegSideSpeed; break;
                    }
                }
                else if(e.type == SDL_KEYDOWN && e.key.repeat > 0){
                    switch (e.key.keysym.sym){
                        case SDLK_w:  
                        cameraStep -= lastPosFrontSpeed; lastPosFrontSpeed = cameraFront * movementCorrection;
                        cameraStep += lastPosFrontSpeed; break;

                        case SDLK_s: 
                        cameraStep += lastNegFrontSpeed;lastNegFrontSpeed = cameraFront * movementCorrection;
                        cameraStep -= lastNegFrontSpeed; break;

                        case SDLK_d: cameraStep -= lastPosSideSpeed;
                        lastPosSideSpeed = glm::normalize(glm::cross(cameraFront, cameraUp)) * movementCorrection;
                        cameraStep += lastPosSideSpeed; break;

                        case SDLK_a: cameraStep += lastNegSideSpeed; 
                        lastNegSideSpeed = glm::normalize(glm::cross(cameraFront, cameraUp)) * movementCorrection; 
                        cameraStep -= lastNegSideSpeed; break;
                    }
                }
                else if(e.type == SDL_KEYUP && e.key.repeat == 0){
                    switch (e.key.keysym.sym){
                        case SDLK_w: cameraStep -= lastPosFrontSpeed; break;
                        case SDLK_s: cameraStep += lastNegFrontSpeed; break;
                        case SDLK_d: cameraStep -= lastPosSideSpeed; break;
                        case SDLK_a: cameraStep += lastNegSideSpeed; break;
                    }
                }
                else if(e.type == SDL_MOUSEMOTION){
                    int thisMouseX, thisMouseY;
                    SDL_GetMouseState(&thisMouseX,&thisMouseY);
                    if(thisMouseX > previousMouseX){
                        if(thisMouseX - previousMouseX < 200){
                            yaw += 1.f * cameraCorrection * (thisMouseX - previousMouseX);
                        }else{yaw += 1.f * cameraCorrection * (100);}
                    }
                    if(thisMouseX < previousMouseX ){
                        if(previousMouseX - thisMouseX < 200){
                            yaw -= 1.f * cameraCorrection * (previousMouseX - thisMouseX);
                        }else{yaw -= 1.f * cameraCorrection * 100;}
                    }
                    if(thisMouseY > previousMouseY && pitch > -80.f){
                        if(thisMouseY - previousMouseY < 100){
                            pitch -= 1.f * cameraCorrection * (thisMouseY-previousMouseY);
                        }else{pitch -= 1.f * cameraCorrection * 10.f;}
                    }
                    if(thisMouseY < previousMouseY && pitch < 80.f){
                        if(previousMouseY - thisMouseY < 100){
                            pitch+=1.f*cameraCorrection * (previousMouseY - thisMouseY);
                        }else{pitch+= 1.f* cameraCorrection * 10.f;}
                    }
                    previousMouseX = thisMouseX; previousMouseY = thisMouseY;
                    cameraFront = glm::vec3(cos(glm::radians(yaw)) * cos(glm::radians(pitch)),sin(glm::radians(pitch)),sin(glm::radians(yaw)) * cos(glm::radians(pitch)));
                }
            }
            cameraPos += cameraStep ;
            view = glm::lookAt(cameraPos,cameraPos + cameraFront, cameraUp);
            glUniformMatrix4fv(viewLoc,1,GL_FALSE,glm::value_ptr(view));
            
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,0);
            if(SDL_GetTicks() - thisTicks < ONE_FRAME_TIME){
                SDL_Delay(ONE_FRAME_TIME- (SDL_GetTicks() - thisTicks));
            }
            SDL_GL_SwapWindow(gWindow);
        }
    }
}

Don’t use e.key.repeat for movement.

Instead just set some bools (or use SDL_GetKeyboardState) to keep track of which keys are down and use them, outside of the event loop, to decide how the camera should be updated once every frame.

1 Like

thank you, ill try this!

it works! thank you so much! now it works perfectly!

int main(int argc,char** argv){
    bool quit = false;
    SDL_Event e;

    if(!init()){
        printf("na");
    }
    else{
        glUseProgram(programShader);

        glm::vec3 cameraStep = glm::vec3(0.f,0.f,0.f);

        unsigned int projectionLoc, viewLoc, modelLoc;
        float movementSensitivity = 0.0005f, cameraSensitivity = 0.01f;
    
        glm::mat4 projection = glm::mat4(1.f);
        glm::mat4 view = glm::mat4(1.f);
        glm::mat4 model = glm::mat4(1.f);
    
        glm::vec3 cameraPos = glm::vec3(0.0,0.0,2.0);
        glm::vec3 cameraUp = glm::vec3(0.0,1.f,0.0);
        glm::vec3 cameraFront = glm::vec3(0.0,0.0,-1.f);
    
        view = glm::lookAt(cameraPos,cameraPos + cameraFront, cameraUp);
    
        projection = glm::perspective(glm::radians(45.f),1.f,0.1f,100.f);
    
        projectionLoc = glGetUniformLocation(programShader,"projection");
        viewLoc = glGetUniformLocation(programShader,"view");
        modelLoc = glGetUniformLocation(programShader,"model");
        
        // std::cout << projectionLoc << " " << viewLoc << " " << modelLoc << std::endl;

        glUniformMatrix4fv(projectionLoc,1,GL_FALSE,glm::value_ptr(projection));
        glUniformMatrix4fv(viewLoc,1,GL_FALSE,glm::value_ptr(view));
        glUniformMatrix4fv(modelLoc,1,GL_FALSE,glm::value_ptr(model));
        
        glBindVertexArray(VAOs[0]);
        glBindTexture(GL_TEXTURE_2D,textures[0]);

        float frameBasedCorrection, thisTicks = 0, previousTicks = 0;

        int previousMouseX, previousMouseY;
        float pitch = 0, yaw =-90;

        

        while(!quit){
            thisTicks = SDL_GetTicks();
            frameBasedCorrection = thisTicks - previousTicks;
            previousTicks = thisTicks;

            float movementCorrection = movementSensitivity * frameBasedCorrection;
            float cameraCorrection = cameraSensitivity * frameBasedCorrection;

            while(SDL_PollEvent(&e)!=0){
                
                if(e.type == SDL_QUIT){quit = true;}
                
                
            }

            int thisMouseX, thisMouseY;
            SDL_GetMouseState(&thisMouseX,&thisMouseY);
            if(thisMouseX > previousMouseX){
                if(thisMouseX - previousMouseX < 200){
                    yaw += 1.f * cameraCorrection * (thisMouseX - previousMouseX);
                }else{yaw += 1.f * cameraCorrection * (100);}
            }
            if(thisMouseX < previousMouseX ){
                if(previousMouseX - thisMouseX < 200){
                    yaw -= 1.f * cameraCorrection * (previousMouseX - thisMouseX);
                }else{yaw -= 1.f * cameraCorrection * 100;}
            }
            if(thisMouseY > previousMouseY && pitch > -80.f){
                if(thisMouseY - previousMouseY < 100){
                    pitch -= 1.f * cameraCorrection * (thisMouseY-previousMouseY);
                }else{pitch -= 1.f * cameraCorrection * 10.f;}
            }
            if(thisMouseY < previousMouseY && pitch < 80.f){
                if(previousMouseY - thisMouseY < 100){
                    pitch+=1.f*cameraCorrection * (previousMouseY - thisMouseY);
                }else{pitch+= 1.f* cameraCorrection * 10.f;}
            }
            previousMouseX = thisMouseX; previousMouseY = thisMouseY;
            cameraFront = glm::vec3(cos(glm::radians(yaw)) * cos(glm::radians(pitch)),sin(glm::radians(pitch)),sin(glm::radians(yaw)) * cos(glm::radians(pitch)));

            const Uint8* keystates = SDL_GetKeyboardState(NULL);

            cameraStep = glm::vec3(0.f,0.f,0.f);

            if(keystates[SDL_SCANCODE_W]){
                cameraStep += cameraFront * movementCorrection;
            }
            if(keystates[SDL_SCANCODE_S]){
                cameraStep -= cameraFront * movementCorrection;
            }
            if(keystates[SDL_SCANCODE_D]){
                cameraStep += glm::normalize(glm::cross(cameraFront ,cameraUp )) * movementCorrection;
            }
            if(keystates[SDL_SCANCODE_A]){
                cameraStep -= glm::normalize(glm::cross(cameraFront ,cameraUp)) * movementCorrection;
            }

            cameraPos += cameraStep ;

            view = glm::lookAt(cameraPos,cameraPos + cameraFront, cameraUp);
            glUniformMatrix4fv(viewLoc,1,GL_FALSE,glm::value_ptr(view));
            
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            glDrawElements(GL_TRIANGLES,36,GL_UNSIGNED_INT,0);
            if(SDL_GetTicks() - thisTicks < ONE_FRAME_TIME){
                SDL_Delay(ONE_FRAME_TIME- (SDL_GetTicks() - thisTicks));
            }
            SDL_GL_SwapWindow(gWindow);
        }
    }
}