• Advertisement
Sign in to follow this  

Jerky movement when vsync turned on (wglSwapIntervalEXT).

This topic is 2473 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I've been searching previous posts here, but I can't find anything to explain my problem. My problem is that with vsync on, my movement is very jerky. I enabled vsync in my program like so:
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
if(wglSwapIntervalEXT) {
	wglSwapIntervalEXT(1);
} else {	
	std::cout << "No vsync";
}
I am using win32 api for my window. My movement is based on deltaTime. I am using the QueryPerformanceCounter to calculate the deltaTime. Am I missing something here? I haven't been able to find any difference between my vsync code and other peoples'. Thanks.

Share this post


Link to post
Share on other sites
Advertisement
You need to interpolate between one frame to the next or else you will always have jerky motion even if you are moving based on delta time.

I have a video in the Physics series that describes this in details (see space ship motion).

Share this post


Link to post
Share on other sites
Like if I move forward it will freeze for a quarter of a second and then move, though for some reason it seems to be doing with less frequency now.

My movement code is:



float walk = (keyDown(VkKeyScan(k[0]))?-1.0f:0.0f)+ (keyDown(VkKeyScan(k[2]))?1.0f:0.0f);
float strafe = (keyDown(VkKeyScan(k[1]))?-1.0f:0.0f)+ (keyDown(VkKeyScan(k[3]))?1.0f:0.0f);
Vector3 dir = camera.front*walk*-1.0f + camera.right*strafe;

if(dir.length2()) {
camera.position += dir.normalise()*6.0f*dt;
}




My timer is:


QueryPerformanceCounter((LARGE_INTEGER*)&startTime);

/*game run code*/

_int64 freq;
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);

_int64 stopTime;
QueryPerformanceCounter((LARGE_INTEGER*)&stopTime);

dt = (startTime)?float(stopTime-startTime)/(float)freq:0;




Edit:

I just noticed that the jerkiness stopped when I outputted text to the console window every loop.

Share this post


Link to post
Share on other sites
are you by chance moving the mouse whilst the jerkiness occurs?

Ive noticed that.

Also try a difference timer than QueryPerformanceFrequency, eg timeGetTime() + report back here your results
cheers zed

Share this post


Link to post
Share on other sites
Yeah I've got that problem too.

Quote:
Original post by zedz
Also try a difference timer than QueryPerformanceFrequency, eg timeGetTime() + report back here your results
cheers zed



Ok I'll let you know when I get home.

Share this post


Link to post
Share on other sites
Ok so same problem with using timeGetTime().

Also the problem is more like this:
* moving the mouse seems a little shakey or jerky, but not too bad
* movement pauses for a moment every now and then, and then jumps forward to pos+=movementDir*deltaTime
* when I output the dt every loop to console, the jumping on the movement seems to disapear
* with vsync off I get finer movements, and not so with it on

I'll post most of the related code:

This is my winmain code

/*#if defined(_DEBUG)
#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif*/


#pragma comment(linker, "/subsystem:\"console\" /entry:\"WinMainCRTStartup\"")

#include <windows.h>
#include <GL/gl.h>
#include "Timer.h"
#include "Main.h"
#include "Window.h"
#include <iostream>
#include "wglext.h"

//
HWND windowHandle;

//
RECT clientRect;
RECT windowRect;

//
BYTE keyState[256];
BYTE keyPrevState[256];

//
POINT cursor = {0,0};
POINT prevCursor = {0,0};

float mx = 0, my = 0;

//
Timer timer;

//
bool lockCursorEnabled = false;

//
//
int Window::clientWidth() {
return clientRect.right;
}
int Window::clientHeight() {
return clientRect.bottom;
}

//
bool Window::keyDown(int key) {
return (keyState[key] & 0x80) && 1;
}
bool Window::keyUpped(int key) {
return (!(keyState[key] & 0x80) && (keyPrevState[key] & 0x80));
}
bool Window::keyDowned(int key) {
return ((keyState[key] & 0x80) && !(keyPrevState[key] & 0x80));
}

//
int Window::cursorX() {
return cursor.x;
}
int Window::cursorY() {
return cursor.y;
}

//
float Window::mouseMoveX() {
return mx;
}
float Window::mouseMoveY() {
return my;
}
//
float Window::deltaTime() {

return timer.get();
}

//
int Window::left() {
return windowRect.left;
}
int Window::top() {
return windowRect.top;
}
int Window::width() {
return windowRect.right-windowRect.left;
}
int Window::height() {
return windowRect.bottom-windowRect.top;
}

//
void Window::lockCursor(bool enabled) {
lockCursorEnabled = enabled;

if(!enabled) {
ClipCursor(0);
}

}

//
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
//for mouse move
if(msg == WM_INPUT) {
UINT dwSize = 40;
static BYTE lpb[40];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));

RAWINPUT* raw = (RAWINPUT*)lpb;

if (raw->header.dwType == RIM_TYPEMOUSE) {
int x =raw->data.mouse.lLastX;
int y = raw->data.mouse.lLastY;

mx = (float)x;
my = (float)y;
}
}
static bool in = false;

if(msg == WM_MOUSEMOVE) {
in = true;

}

if(msg == WM_MOUSELEAVE) {
in = false;
}

//escape key
if(msg == WM_KEYDOWN && wParam == VK_ESCAPE) {
DestroyWindow(hWnd);
}

//
if(msg == WM_KEYDOWN && wParam == VK_CONTROL) {

}

//close button
if(msg == WM_DESTROY) {
PostQuitMessage(0);
return 0;
}

//
return DefWindowProc(hWnd, msg, wParam, lParam);
}



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
/*#if defined(_DEBUG)
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)|_CRTDBG_DELAY_FREE_MEM_DF|_CRTDBG_LEAK_CHECK_DF);
#endif*/


//
const char title[] = "title";
int windowWidth = 1024;
int windowHeight = 800;

//desktop size
RECT desktopRect;
GetWindowRect(GetDesktopWindow(), &desktopRect);

//init window
WNDCLASS wc = {CS_CLASSDC|CS_DBLCLKS, WndProc, 0, 0, hInstance, 0, LoadCursor(0, IDC_ARROW), 0, 0, "abc"};
RegisterClass(&wc);
windowHandle = CreateWindow(wc.lpszClassName, title,
WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_MAXIMIZEBOX|WS_THICKFRAME|WS_VISIBLE,
(desktopRect.right-windowWidth)/2/*CW_USEDEFAULT*/, (desktopRect.bottom-windowHeight)/2/*CW_USEDEFAULT*/, windowWidth, windowHeight, 0, 0, hInstance, 0);


//window dc
HDC windowDc = GetDC(windowHandle);

//for mouse move
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01; //HID_USAGE_PAGE_GENERIC
Rid[0].usUsage = 0x02; //HID_USAGE_GENERIC_MOUSE
Rid[0].dwFlags = RIDEV_INPUTSINK;
Rid[0].hwndTarget = windowHandle;
RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]));

//init opengl
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory( &pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
int iFormat = ChoosePixelFormat(windowDc, &pfd);
SetPixelFormat(windowDc, iFormat, &pfd);
SwapBuffers(windowDc);
HGLRC rc = wglCreateContext(windowDc);
wglMakeCurrent(windowDc, rc);

//turn on vsync
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) wglGetProcAddress("wglGetSwapIntervalEXT");

if(!wglSwapIntervalEXT) {
std::cout << "No vsync";
} else {
wglSwapIntervalEXT(1);
std::cout << "vsync " << wglGetSwapIntervalEXT() << std::endl;
}

//
//init key state
ZeroMemory(keyState, sizeof(keyState));
ZeroMemory(keyPrevState, sizeof(keyPrevState));


//
if(Main::create()) {


//
MSG msg;
ZeroMemory(&msg, sizeof(msg));

while(msg.message != WM_QUIT) {
if(IsIconic(windowHandle) || (GetForegroundWindow() != windowHandle /*&& GetForegroundWindow() != GetConsoleWindow()*/)) {
if(GetMessage(&msg, 0,0,0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}

//
ClipCursor(0);

//
//mx = 0;
//my = 0;
} else {
if(PeekMessage(&msg, 0,0,0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
//
timer.stop(); //edit
timer.start();

//
GetClientRect(windowHandle, &clientRect);
GetWindowRect(windowHandle, &windowRect);

//keystate
memcpy(&keyPrevState, &keyState, sizeof(keyPrevState));
GetKeyboardState(keyState);

//cursor
if(!lockCursorEnabled) {
prevCursor = cursor;
GetCursorPos(&cursor);
ScreenToClient(windowHandle, &cursor);
}

//
if(lockCursorEnabled) {
POINT clientTopLeft = {0,0};
POINT clientBottomRight = {clientRect.right, clientRect.bottom};
ClientToScreen(windowHandle, &clientTopLeft);
ClientToScreen(windowHandle, &clientBottomRight);
RECT clipRect;
SetRect(&clipRect, clientTopLeft.x, clientTopLeft.y, clientBottomRight.x, clientBottomRight.y);
ClipCursor(&clipRect);

POINT clientMid = cursor;//{clientRect.right/2, clientRect.bottom/2};
ClientToScreen(windowHandle, &clientMid);
SetCursorPos(clientMid.x, clientMid.y);
}

//


if(!Main::run()) {
break;
}

//
mx=0;
my=0;

//
SwapBuffers(windowDc);



}
}
}
}

//
Main::destroy();

//cleanup opengl
wglMakeCurrent(0, 0);
wglDeleteContext(rc);

//
ReleaseDC(windowHandle, windowDc);

//
OutputDebugString("\nexited.\n\n");
//system("pause");

return 0;
}






And this is my movement code

void runPlayer() {
static bool mouseView = false;
static bool mouseRightView = false;

int lookKey = VK_LBUTTON;
int heightKey = VK_RBUTTON;

if(Window::keyDowned(lookKey) || Window::keyDowned(heightKey)) {
Window::lockCursor(true);
ShowCursor(false);
}

if(Window::keyUpped(lookKey) || Window::keyUpped(heightKey)) {
Window::lockCursor(false);
ShowCursor(true);
}

if(Window::keyDowned(lookKey)) {
mouseView = true;
}

if(Window::keyUpped(lookKey)) {
mouseView = false;
}

if(Window::keyDowned(heightKey)) {
mouseRightView = true;
}

if(Window::keyUpped(heightKey)) {
mouseRightView = false;
}

const char *k =
"esdf"
// "wasd"
;

//
float walk = (Window::keyDown(VkKeyScan(k[0]))?-1.0f:0.0f)+ (Window::keyDown(VkKeyScan(k[2]))?1.0f:0.0f);
float strafe = (Window::keyDown(VkKeyScan(k[1]))?-1.0f:0.0f)+ (Window::keyDown(VkKeyScan(k[3]))?1.0f:0.0f);

Vector3 dir = camera.front*walk*-1.0f + camera.right*strafe;

if(mouseRightView) {
dir.y = 0;
}

if(dir.length2()) {
camera.position += dir.normalise()*((Window::keyDown(VK_SHIFT))?26.0f:13.0f)*Window::deltaTime();
}

const float lookSpeed = 3.0f;

camera.rotateAngle += ((Window::keyDown(VK_UP)?1.0f:0.0f)+ (Window::keyDown(VK_DOWN)?-1.0f:0.0f))*lookSpeed*Window::deltaTime();
camera.aroundAngle += ((Window::keyDown(VK_LEFT)?1.0f:0.0f)+ (Window::keyDown(VK_RIGHT)?-1.0f:0.0f))*lookSpeed*Window::deltaTime();

static float yawVel = 0;
static float pitchVel = 0;

if(mouseView || mouseRightView) {
camera.aroundAngle -= (float)Window::mouseMoveX()*lookSpeed*Window::deltaTime();//*0.5f;
camera.rotateAngle -= (float)Window::mouseMoveY()*lookSpeed*Window::deltaTime();//*0.5f;
}

const float pi2 = 1.5707f;

if(camera.rotateAngle > pi2) {
camera.rotateAngle = pi2;
}

if(camera.rotateAngle < -pi2) {
camera.rotateAngle = -pi2;
}

camera.calculate();
}






The camera code is just

Camera::Camera()
: transform(4), aroundAngle(0), aroundBack(0), rotateAngle(0)
{
transform.setIdentity();
}
void Camera::calculate() {
Camera::Camera()
: transform(4), aroundAngle(0), aroundBack(0), rotateAngle(0)
{
transform.setIdentity();
}
void Camera::calculate() {
Matrix positionMat(4), rotateMat(4), aroundMat(4), aroundBackMat(4);

positionMat.setPosition(position);
rotateMat.setRotation(rotateAxis, rotateAngle);
aroundMat.setRotation(aroundAxis, aroundAngle);
aroundBackMat.setPosition(Vector3(0,0,aroundBack));

transform = (positionMat*(aroundMat*aroundBackMat))*rotateMat;

//
front = transform.getZAxis()*-1.0f;
at = position + front;
right = transform.getXAxis();
up = transform.getYAxis();
}






Also the Main::run() is


bool Main::run() {
std::cout << Window::deltaTime() << std::endl;

runPlayer();

//
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, Window::clientWidth(), Window::clientHeight());

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, float(Window::clientWidth())/float(Window::clientHeight()), 0.1f, 950);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

//sky
glUseProgram(0);

glPushMatrix();
gluLookAt(0,0,0, camera.front.x,camera.front.y,camera.front.z, camera.up.x,camera.up.y,camera.up.z);
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyTexture);
renderSky();
glDisable(GL_TEXTURE_CUBE_MAP);
glPopMatrix();

//
gluLookAt(camera.position.x,camera.position.y,camera.position.z, camera.at.x,camera.at.y,camera.at.z, camera.up.x,camera.up.y,camera.up.z);

//light

glPushMatrix();
glTranslatef(2,3,0);
Light light;
light.position[3] = 1;
light.run(GL_LIGHT0);
light.render(quadratic);
glPopMatrix();

//test
glPushMatrix();
glColor4f(1,1,1,1);
testMesh->render();
glPopMatrix();

//other
glUseProgram(0);
runFps();
renderAxises();

//
return true;
}



Thanks.

[Edited by - andrew111 on August 15, 2009 12:24:27 AM]

Share this post


Link to post
Share on other sites
I was just about to suggest to turn vsync off + then I notice having it on causes the problem (from your post)

>>My movement is based on deltaTime.

u say your FPS is 800-1200, in this case u really should use a fixed loop update, i.e. ditch the deltaTime stuff

something else to try is stick a sleep(1)/SDL_Delay(1); command somewhere in your main loop (so it gets called once per bufferswap)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement