Time based rendering placement problems (updated)

Started by
12 comments, last by Demus79 17 years, 10 months ago
Skip to the last post for the newer stuff. Yeah I know that the title is kind of confusing, but I didn't really know what else to have it as. Anyway, the problem is that the code that I have to do time based rendering so I restrict the fps of the engine is currently in my SceneManager class. When I need to render, I simply call SceneManager::render() and that traverses the scene graph tree and calls 'render' for everything. So, the code to restrict the engine fps needs to be in SceneManager::render(). I recently realised that if I call SceneManager::render() more than once every frame, I get problems. For instance if I need to render twice for shadows, or to draw reflections, or something like that. It's a little bit of a story, so here goes: This is the code that restricts the fps of the engine:

/**
 * Render all objects in the scene graph.
 */
void CSceneGraph::render()
{

	while( (m_time += m_hiResTimer.getElapsedSeconds()) < m_minTimeBetweenFrames );

	//if( (m_time += m_hiResTimer.getElapsedSeconds()) < m_minTimeBetweenFrames )
	//	return;


	util::list<ISceneGraphNode*>::iterator i;

	// pre render
	for(i = m_nodeList.begin() ; i != m_nodeList.end(); i++)
		(*i)->preRender( m_time );

	// render
	for(i = m_nodeList.begin() ; i != m_nodeList.end(); i++)
		(*i)->render();

	// post render
	for(i = m_nodeList.begin() ; i != m_nodeList.end(); i++)
		(*i)->postRender( m_time );

	// reset time to 0.0f because we have just drawn a frame
	m_time = 0.0f;

}




I currently have to use the while statement, otherwise I get serious flickering and no restriction of the fps. I think I know why this is. Whenever VideoDriver::endScene is called, it swaps the buffers for the window, and obviously if no rendering is done then nothing gets drawn to the back buffer and a blank buffer gets swapped to the screen, causing the flickering. I think. So, for both these reasons, (blank buffer swap, and calling SceneManager::render more than once a frame) I need to move the fps code to the video driver, so I can prevent the buffer being swapped when nothing has been drawn to it. Should I just have a pointer to the scene graph inside the video driver, move the fps code to the video driver and instead of calling 'render' on the scene graph object, do it on the video driver object? How have other people done this bit? Or did you all do the smart thing and have a better design than I did? [Edited by - Endar on May 23, 2006 4:17:16 AM]
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Advertisement
Time restriction does not below in a scene graph.

When you call "render" on a scene graph, it should traverse the graph, and render all the items to the indicated target, using the current state of the objects. It should not change the state of the objects, or check the time, or anything like that. When it comes to object state, the scene graph should be absolutely dumb (only the user changes the objects).

If calling Render() twice in a row in your scene graph causes an empty frame to be rendered, you have a bug in your scene graph.

If you need to limit the frame rate, you should first try turning on vSync in your code -- D3DPRESENTINTERVAL_xxx has some options for you. This will remove all tearing. Only after that should you start throttling in the application -- and, in that case, in the high-level code. I e, your code might look something like:

  forever() {    toSleep = nextTime - time();    Sleep(toSleep);    nextTime = time() + desiredFrameTime;    ReadInput();    ProcessPhysics(desiredFrameTime);    RenderScene();  }


Note that Sleep() may be a little bit jittery on some systems; you may have better results with something like MsgWaitForMultipleObjectsEx() with a timeout.

enum Bool { True, False, FileNotFound };
Quote:Original post by hplus0603
If you need to limit the frame rate, you should first try turning on vSync in your code -- D3DPRESENTINTERVAL_xxx has some options for you.


Do you know the equivalent for OGL? Oh, well I don't think it matters as I'm not currently using full screen, I'm just doing it windowed.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Okay, I thought this would work, but I'm having problems with the code and it's better to post here than start up a new thread.

void IVideoDriver::render(){	// If the total time since the last frame is less than the time between frames for the desired fps	// ie. If to restrict to the desired fps, we don't have to draw yet	if( (m_time += m_hiResTimer.getElapsedSeconds()) < m_minTimeBetweenFrames )		return;	// if we get here, then we should be rendering a frame			// if we have a scene manager	if( m_sceneManager )		m_sceneManager->render( m_time );		// render the scene graph	// reset the time	m_time = 0.0f;	// indicate we should be rendering	m_renderFrame = true;}/** * Does housekeeping for the end of rendering a frame. */virtual void IVideoDriver::endScene(){	// if we should be rendering a frame	if( m_renderFrame ){		m_fpsCounter.endFrame();	// register the end of a frame, so, calculate the FPS		m_renderFrame = false;	// it's the beginning of a new frame	}}/** * Does OGL housekeeping for the end of rendering a frame. * Flushes the pipeline, swap buffers, counts fps. */void COpenGLDriver::endScene(){	// If the time since the last frame is greater than the min time between frames	// ie. If we should be rendering	if( m_renderFrame ){		glFlush();			// flush the pipeline		SwapBuffers(m_hdc);	// render the scene to the window		// do the FPS calculating, etc		IVideoDriver::endScene();	}}


Note:: COpenGLDriver inherits from IVideoDriver.

If I use the code was is, the FPS counter says the fps is ~50. But when I do some rotation on the cube, which is the only thing is the scene, it rotates way too fast for 50 fps.

If I comment out the first if statement, and don't add to 'm_time' at all, I get about ~87.

This is really confusing.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
bump
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
You are only restricting the rendering frame rate by putting checks in a render() function, not the physics frame rate. Your high-level message loop is the place to restrict speed, not a rendering function.

And you don't need to bump after 7 hours.
Quote:Original post by Bob Janova
You are only restricting the rendering frame rate by putting checks in a render() function, not the physics frame rate. Your high-level message loop is the place to restrict speed, not a rendering function.


At the moment, I'm only trying to restrict the rendering speed (I currently have no physics).

Why is the high-level message loop the place to restrict speed? Can't I have each system restricting it's own speed to whatever it needs or wants?

Quote:Original post by Bob Janova
And you don't need to bump after 7 hours.


Uh, 3:45am I wrote the post, and bumped it at 10:55pm.
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Okay, you don't need to bump after X hours, where X < 24 and your page is still on the first screen :P.

Quote:At the moment, I'm only trying to restrict the rendering speed (I currently have no physics).

Uh, where does rotating this model happen, then? The rate at which that occurs will be related to your input framerate, which I presume is not called from within render(). You don't restrict the framerate of your message loop at all by returning from render() (to do that you need to wait).

Quote:Why is the high-level message loop the place to restrict speed? Can't I have each system restricting it's own speed to whatever it needs or wants?

Well, yes, it's just more complicated. By restricting frame rate at the highest level you ensure all your game modules run at the same speed. If you want to restrict each component separately then that's fine, but don't expect your input and rendering to happen at the same frame rate!
Quote:Original post by Bob Janova
Uh, where does rotating this model happen, then? The rate at which that occurs will be related to your input framerate, which I presume is not called from within render(). You don't restrict the framerate of your message loop at all by returning from render() (to do that you need to wait).


I thought that eventually I'd be able to do something like this:
while( running ){	processInput();	render();	physicsUpdate();	sleep();}


And for the rendering and physics, or at least the rendering calc the seconds (fractions obviously) between each render to get a specific fps, and if we've not hit it yet, then just don't render and go on to the physics. Kind of the same with the physics (kind of, I know nothing about physics yet).

Or was this what you were telling me and it's just not entering my thick, thick head?
[size="2"][size=2]Mort, Duke of Sto Helit: NON TIMETIS MESSOR -- Don't Fear The Reaper
Okay, so in that case what is the problem with the cube rotating faster than 50 fps :P ? If you're just not rendering then you'd expect the other parts of the game (input, physics) to go faster. Sounds like your solution is working just like you wanted it to 8).

This topic is closed to new replies.

Advertisement