Search code examples
rust3dglium

Very Slow and Choppy Camera Controller in Rust


I am currently working on simple Rendering in Rust using the OpenGL Wrapper Glium. I have a simple 3D model and a Camera ready set up and started working on a fitting camera controller. I'm using device_query to check for keyboard input and if it's a Specific Keyboard input I just change the x and y coordinates. This works, however it works really bad, inconstantly and choppy.

My Event loop:

event_loop.run(move |event, _, control_flow| {
        let next_frame_time =
            std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
####### This is where I change the coordinates ########        
        x = keyboardinput::keyboard_input_x(x);
        y = keyboardinput::keyboard_input_y(y);
        *control_flow = glutin::event_loop::ControlFlow::WaitUntil(next_frame_time);

        match event {
            glutin::event::Event::WindowEvent { event, .. } => match event {
                glutin::event::WindowEvent::CloseRequested => {
                    *control_flow = glutin::event_loop::ControlFlow::Exit;
                    return;
                }
                _ => return,
            },
            glutin::event::Event::NewEvents(cause) => match cause {
                glutin::event::StartCause::ResumeTimeReached { .. } => (),
                glutin::event::StartCause::Init => (),
                _ => return,
            },
            _ => return,
        }

This is my Keyboard input rs file:

use device_query::{DeviceQuery, DeviceState, Keycode};

pub fn keyboard_input_x(mut x: f32) -> f32 {
    let device_state = DeviceState::new();
    let keys: Vec<Keycode> = device_state.get_keys();
    for key in keys.iter() {
        println!("Pressed key: {:?}", key);
        if key == &Keycode::W {
            x -= 0.03;
            return x;
        }
        if key == &Keycode::S {
            x += 0.03;
            return x;
        }
    }
    return x;
}

pub fn keyboard_input_y(mut y: f32) -> f32 {
    let device_state = DeviceState::new();
    let keys: Vec<Keycode> = device_state.get_keys();
    for key in keys.iter() {
        println!("Pressed key: {:?}", key);
        if key == &Keycode::Space {
            y += 0.03;
            return y;
        }
        if key == &Keycode::LControl {
            y -= 0.03;
            return y;
        }
    }
    return y;
}

What can I do the make the camera as smooth as possible?


Solution

  • Instead of directly updating your x/y position in the input handler, create two variables holding your x velocity and y velocity (xv/yv), and then in your input handler do something like this:

    bool space_pressed = false;
    for key in keys.iter() {
        if key == &Keycode::Space {
            space_pressed = true;
        }
    }
    
    if space_pressed {
        yv = 1.0; // Move up.
    } else {
        yv = 0.0; // Don't move.
    }
    

    And in your main loop where you compute each frame, count the amount of time since the last frame in seconds (often called delta-t or dt), and integrate your x velocity and y velocity to a new position:

    // Update camera position.
    x += xv * dt;
    y += yv * dt;
    

    Now when you hold space you will move up at a constant velocity, rather than unpredictably and choppy.