Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

0 Neutral

About whitwhoa

  • Rank

Personal Information

  • Interests


  • Github
  1. The stutter appears to be gone for all of the values you had suggested: 72tps (you had listed 78 but I believe you meant 72) 48tps 36tps 24tps I'm still processing your explanation, as I really am trying to understand what's going on here. I appreciate the level of detail you have provided, and the picture! I like pictures
  2. This would make sense to me if I did not include an interpolation phase. I thought the purpose of interpolation was to smooth out this issue, or have I misunderstood?
  3. window.vsync() Is really just calling glfwSwapInterval(1) I realized this could be done once outside of my loop during my investigation of this issue and have since moved the call outside of the render loop so that it is not needlessly begin called every frame. Thinking that this issue might be related to vsync timing, I added code to limit my framerate without vsync, and the issue persists when I limit the framerate to my refresh rate. I'm starting to wonder if there is an issue with how I'm calculating my position and direction in relation to how I am interpolating the two? Or if there is a precision issue when I calculate the `alpha` as a double, but pass as a float (however if that were the case I would think that the linear side-to-side movement would also be affected).
  4. I have spent some time generating several log files (and staring at them intently 😵) for the various combinations I have described. The only pattern I have made out so far is that the stutter is happening when more logic ticks are performed, except when the logic tick happens at the exact rate as the render rate. The interpolation appears to be functioning as expected, however I am currently wondering if there is an accuracy issue with the interpolation that is only noticeable at specific logic/render ratios? If anyone would like to take a look at the generated log files I have uploaded them to my server: 128 ticks per second with vsync - not smooth 128 ticks per second no vsync - smooth 144 ticks per second with vsync - smooth 64 ticks per second with vsync - not smooth 30 ticks per second with vsync - smooth Refresh rate is 144 when vsync enabled, without vsync fps is over 1000. Each row of the log is a snapshot of a render loop. If a logic update has occurred, the word LOGIC is included in the row. I will be investigating this until a resolution is found. Any/All feedback greatly appreciated!
  5. I am currently in the process of implementing a fixed timestep game loop following the legendary "Fix Your Timestep" article. I have managed to get everything setup and working...or so I thought, until I started to change my timestep value. I seem to be running into an issue where a stutter is produced during rotation at specific timesteps (linear movement (forwards, backwards, left, right) is always smooth when rotation is not changed). Below are the different timesteps and encountered results when running with vsync enabled on a 144hz panel: 144 updates per second - smooth rotation, minor stutter every once in awhile but barely noticeable (possibly in my head) 128 updates per second - rotation stutter noticeable (may not be completely obvious at first but as you rotate around the crate you will see it) 30 updates per second - smooth rotation, no stutter noticed When the above timesteps are used with vsync disabled they all appear to have smooth rotation. The takeaway (at least my takeaway) is that the more render cycles that happen between update steps, the smoother the rotation. I have been going back and forth as to why this could be (this is the first time I have attempted to implement something like this so it's possible I have missed something someone else might instantly notice) and the thing that throws me is the fact that the interpolation appears to be working as expected for lower update rates (as seen from the 30 updates per second test (if I attempt the 30 updates per second test with interpolation disabled everything stutters horribly as you would expect until interpolation is enabled again)), but then appears to not be working when the render cycles more closely match the number of update cycles. I have included my code below which I believe to be relative to the question (complete source available here). Is there anything that points out as being horribly wrong??? I have been obsessing over trying to figure this out for days now. Any advice greatly appreciated! int main() { glm::vec2 screen_size = glm::vec2(1280, 720); InputState input; Window window(&screen_size, &input); if (window.getInitFailed()) { std::cout << window.getInitMessage() << std::endl; return -1; } auto scene = std::make_unique<Scene>(&screen_size); auto game = std::make_unique<GameLogic>(&input); double delta_time = 0.0078125; // 128 tps //double delta_time = 0.0069444444444444; // 144 tps //double delta_time = 0.0166666666666667; // 60 tps //double delta_time = 0.03333333333; // 30 tps double current_time = window.time(); double accumulator = 0.0; glEnable(GL_DEPTH_TEST); scene->addModel("data/models/bin/props/crate1/crate1.obj"); // Render loop while (!window.shouldClose()) { // per-frame time logic double new_time = window.time(); double frame_time = new_time - current_time; if (frame_time > 0.25) { frame_time = 0.25; } current_time = new_time; accumulator += frame_time; // exit if key_esc pressed if (input.key_esc) { window.setToClose(); continue; } // capture input state window.update(); // process game logic while (accumulator >= delta_time) { game->update(delta_time); accumulator -= delta_time; } scene->render(game->getCurrentGameState(), game->getPreviousGameState(), (accumulator / delta_time)); window.vsync(); window.swapBuffers(); } return 0; } // From GameLogic.cpp //------------------------------- GameLogic::GameLogic(InputState* is) : player(is) {} GameLogic::~GameLogic() {} void GameLogic::update(double delta) { player.update(delta); updateState(); } void GameLogic::updateState() { previous_state = current_state; current_state.player_position = player.getPlayerPosition(); current_state.player_front = player.getPlayerFront(); current_state.view_position = player.getViewPosition(); current_state.view_front = player.getViewFront(); } GameState GameLogic::getCurrentGameState() { return current_state; } GameState GameLogic::getPreviousGameState() { return previous_state; } // From Player.cpp //------------------------------- Player::Player(InputState* is) { this->input_state = is; }; Player::~Player() {}; void Player::update(double delta) { this->delta = delta; updateRotation(); onScroll(input_state->scroll_x, input_state->scroll_y); move(); rotate(); look(); } void Player::move() { float speed = player_move_speed * delta; if (input_state->key_w) player_position += speed * player_front; if (input_state->key_s) player_position -= speed * player_front; if (input_state->key_a) player_position -= glm::normalize(glm::cross(player_front, player_up)) * speed; if (input_state->key_d) player_position += glm::normalize(glm::cross(player_front, player_up)) * speed; view_position = player_position + view_offset; } void Player::rotate() { glm::vec3 front; front.x = cos(glm::radians(yaw)); front.y = 0.0f; front.z = sin(glm::radians(yaw)); player_front = glm::normalize(front); } void Player::look() { 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)); view_front = glm::normalize(front); } void Player::updateRotation() { if (first_mouse) { last_x = input_state->mouse_xpos; last_y = input_state->mouse_ypos; first_mouse = false; } float xoffset = input_state->mouse_xpos - last_x; float yoffset = last_y - input_state->mouse_ypos; last_x = input_state->mouse_xpos; last_y = input_state->mouse_ypos; float sensitivity = 0.1f; xoffset *= sensitivity; yoffset *= sensitivity; yaw += xoffset; pitch += yoffset; if (pitch > 89.0f) pitch = 89.0f; if (pitch < -89.0f) pitch = -89.0f; } glm::vec3 Player::getPlayerPosition() { return player_position; } glm::vec3 Player::getPlayerFront() { return player_front; } glm::vec3 Player::getViewPosition() { return view_position; } glm::vec3 Player::getViewFront() { return view_front; } // From Scene.cpp //------------------------------- Scene::Scene(glm::vec2* screen_size) : camera(screen_size), shader(GlobalConstants::VERTEX_SHADER, GlobalConstants::FRAGMENT_SHADER) {} Scene::~Scene(){} void Scene::render(GameState current_state, GameState previous_state, float alpha) { GameState lerp_render_state = lerpRenderState(current_state, previous_state, alpha); camera.setPosition(lerp_render_state.view_position); camera.setDirection(lerp_render_state.view_front); camera.update(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); shader.setMat4("view", camera.getViewMatrix()); shader.setMat4("projection", camera.getProjectionMatrix()); glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(0.f, 2.f, -3.f)); shader.setMat4("model", model); for (auto &m : models) { m.draw(shader); } } void Scene::addModel(std::string path) { models.push_back(Model(path)); } GameState Scene::lerpRenderState(GameState current_state, GameState previous_state, float alpha) { GameState lerp_render_state; lerp_render_state.player_position = glm::lerp(previous_state.player_position, current_state.player_position, alpha); if (current_state.player_front != previous_state.player_front) { lerp_render_state.player_front = glm::slerp(previous_state.player_front, current_state.player_front, alpha); } else { lerp_render_state.player_front = glm::lerp(previous_state.player_front, current_state.player_front, alpha); } lerp_render_state.view_position = glm::lerp(previous_state.view_position, current_state.view_position, alpha); if (current_state.view_front != previous_state.view_front) { lerp_render_state.view_front = glm::slerp(previous_state.view_front, current_state.view_front, alpha); } else { lerp_render_state.view_front = glm::lerp(previous_state.view_front, current_state.view_front, alpha); } return lerp_render_state; } // From Camera.cpp //------------------------------- Camera::Camera(glm::vec2* screen_size) { this->screen_size = screen_size; } Camera::~Camera() {} void Camera::update() { updateViewMatrix(); updateProjectionMatrix(); } void Camera::updateViewMatrix() { view_matrix = glm::lookAt(camera_position, camera_position + camera_front, camera_up); } void Camera::updateProjectionMatrix() { projection_matrix = glm::perspective(glm::radians(fov), (float)screen_size->x / (float)screen_size->y, 0.1f, 100.0f); } void Camera::setPosition(glm::vec3 position) { camera_position = position; } void Camera::setDirection(glm::vec3 direction) { camera_front = direction; } glm::mat4 Camera::getViewMatrix() { return view_matrix; } glm::mat4 Camera::getProjectionMatrix() { return projection_matrix; }
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!