You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中相机控制器卡顿缓慢问题的优化方案咨询

相机移动卡顿、不稳定的优化方案

问题背景

使用Rust语言结合OpenGL封装库Glium开发3D渲染程序,已完成基础3D模型与相机搭建,正在适配相机控制器。目前通过device_query检测键盘输入修改相机x、y坐标实现移动,但存在移动不稳定、卡顿的问题。

当前事件循环代码

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,
        }

当前键盘输入模块代码

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;
}

优化方案

1. 替换轮询式输入为Glutin原生事件驱动

device_query采用轮询方式检测输入,容易导致状态不一致、响应延迟,改用Glutin原生键盘事件跟踪按键状态:

  • 定义按键状态结构体,用于记录按键按下/释放状态:
#[derive(Default)]
struct KeyState {
    w_pressed: bool,
    s_pressed: bool,
    space_pressed: bool,
    lctrl_pressed: bool,
}

// 在事件循环外部初始化按键状态
let mut key_state = KeyState::default();
  • 修改事件循环,处理键盘按下/释放事件,更新按键状态:
event_loop.run(move |event, _, control_flow| {
    let next_frame_time = std::time::Instant::now() + std::time::Duration::from_nanos(16_666_667);
    *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;
            }
            glutin::event::WindowEvent::KeyboardInput { input, .. } => {
                let pressed = input.state == glutin::event::ElementState::Pressed;
                match input.virtual_keycode {
                    Some(glutin::event::VirtualKeyCode::W) => key_state.w_pressed = pressed,
                    Some(glutin::event::VirtualKeyCode::S) => key_state.s_pressed = pressed,
                    Some(glutin::event::VirtualKeyCode::Space) => key_state.space_pressed = pressed,
                    Some(glutin::event::VirtualKeyCode::LControl) => key_state.lctrl_pressed = pressed,
                    _ => {}
                }
            }
            _ => {}
        },
        glutin::event::Event::NewEvents(cause) => match cause {
            glutin::event::StartCause::ResumeTimeReached { .. } |
            glutin::event::StartCause::Init => {
                // 仅在帧更新阶段处理相机移动
                update_camera_position(&mut x, &mut y, &key_state);
                // 执行渲染逻辑
            }
            _ => return,
        },
        _ => return,
    }
});
  • 实现相机位置更新函数:
fn update_camera_position(x: &mut f32, y: &mut f32, key_state: &KeyState) {
    // 可根据需求调整移动速度
    let move_speed = 0.1;

    if key_state.w_pressed {
        *x -= move_speed;
    }
    if key_state.s_pressed {
        *x += move_speed;
    }
    if key_state.space_pressed {
        *y += move_speed;
    }
    if key_state.lctrl_pressed {
        *y -= move_speed;
    }
}

2. 基于帧间隔时间(Delta Time)稳定移动速度

固定每帧移动距离会因帧率波动导致速度不稳定,通过计算帧间隔时间,将移动速度与时间绑定,保证移动速度恒定:

  • 在事件循环外记录上一帧时间:
let mut last_frame_time = std::time::Instant::now();
  • 在帧更新阶段计算Delta Time并传入移动函数:
glutin::event::Event::NewEvents(cause) => match cause {
    glutin::event::StartCause::ResumeTimeReached { .. } |
    glutin::event::StartCause::Init => {
        let now = std::time::Instant::now();
        let delta_time = now.duration_since(last_frame_time).as_secs_f32();
        last_frame_time = now;

        update_camera_position(&mut x, &mut y, &key_state, delta_time);
        // 执行渲染逻辑
    }
    _ => return,
},
  • 修改移动函数,使用Delta Time计算实际移动距离:
fn update_camera_position(x: &mut f32, y: &mut f32, key_state: &KeyState, delta_time: f32) {
    // 基础移动速度(单位:单位/秒)
    let base_speed = 2.0;
    let move_speed = base_speed * delta_time;

    if key_state.w_pressed {
        *x -= move_speed;
    }
    if key_state.s_pressed {
        *x += move_speed;
    }
    if key_state.space_pressed {
        *y += move_speed;
    }
    if key_state.lctrl_pressed {
        *y -= move_speed;
    }
}

3. 移除性能消耗操作

原代码中每次调用输入函数都创建DeviceState实例并打印按键信息,会额外消耗系统资源,优化后这些操作全部移除,减少性能开销。


内容的提问来源于stack exchange,提问作者Teer 2008

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:09:21