Jerky movement when vsync turned on (wglSwapIntervalEXT).

Started by
22 comments, last by V-man 12 years, 9 months ago
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.
Advertisement
What FPS are you getting with v-sync enabled? v-sync disabled?
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
When off about 800-1200, and when on 60.
What do you mean by jerky? Could you show some code?
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).
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.

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
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.
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]
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)

This topic is closed to new replies.

Advertisement