A question regarding physics and graphics wrapping

nord

15-02-2011 17:03:18

Hi all.

I have saved a physx scene replay log. Log format is like

frame 1
nodeID x y z yaw pitch roll
nodeID x y z yaw pitch roll
nodeID x y z yaw pitch roll
...
frame 2
nodeID x y z yaw pitch roll
nodeID x y z yaw pitch roll
nodeID x y z yaw pitch roll
...
frame n
...


The positions and orientations in a frame belong to scene nodes identified by "nodeID". This log is created by running physx engine solely on a C++ program (There is no relation with Ogre or NxOgre). Each frame is a snapshot of physx world at that time stamp. There are (almost) 16.6 miliseconds between frames. So that makes the input signal (replay log) 60Hz.

In my replay log, actually there are 20 cars, and 4 x 20 = 80 tires. So at each frame, I have 100 scenenodes, with changing x y z yaw pitch roll values. When i replay my log in my "X" rendering engine, I see that cars move very smoothly. So I am sure that my log is correct and smooth.

My first test :
I created a very basic Ogre application, and before rendering, i filled a std::dequeue<frame> inputFrames with the log. frame (c++ struct) consists of std::vector<int> ids and std::vector<double> data, simply holding ids and x y z h p r values of the sceneNodes for that frame. Then I created 20 cubes and 80 cylinders in my Ogre application with appropriate "nodeID" s. During my each render loop, I dequeued a single frame, and updated my whole scene with the the information extracted from that frame.

Results :
When the scene is simple, Ogre runs at 60 fps (Vsync is enabled always). And since my input signal is 60Hz, everything is rendered correctly, there is no jitter, cars and their tires (actually cubes and cylinders :) move smoothly. If i decrease the Ogre fps by increasing (for example) triangle count, car movements slow down as expected, since Ogre consume a 60Hz input signal in for eg 40Hz (fps).

But,
if the Ogre fps is not stable, for example if it fluctuates between 28 and 37, then I see jitter, which is (you can disagree with me at any point) because of the changing velocities (Consuming 60Hz input signal at varying frequencies).

My second test :
What I also tried is, I launched a tester thread prior to rendering with Ogre. This tester thread reads all the replay log file, and fills its own std::dequeue<frame>. When Ogre starts rendering, this tester thread behaves like a physx engine, it dequeues a frame, and puts this frame in a temp variable that also Ogre application has access to. Than during the render loop, after each renderOneFrame, i check this temp variable (frame bufferFrame;) and update the Ogre scene with this information.

In other words :
Ogre runs at 60fps, so it reads the bufferFrame temp variable 60 times a second, updating its whole scenegraph. Tester thread (my primitive physx engine simulator:) loop runs at 60Hz, it writes the current frame to bufferFrame 60 times a second.

Results
If Ogre runs at 60fps, there is some little jitter : Because even if both reader(Ogre) and writer(tester thread) seem to run at 60Hz, sometimes Ogre reads the same frame from bufferFrame, and sometimes it skips a frame. So depending on (slightly) changing frequencies of Ogre due to unpredictable nature of rendering, i see skips or freezes (you may disagree with my conclusions :).

If Ogre runs at 30fps, or especially at a range of 30-40fps, there is terrible jitter which i believe that the great increase in number of frame skips cause this stalls and jitters.

(Note that i tried to use bufferFrame write&read operations with/without a slim lock, it doesnt change anything in terms of jitter and performance, but i think the lock prevents the "very rare" crushes during read.)

Question
How can I smoothly carry my physics world's x y z yaw pitch roll information to my Ogre scenegraph?
My limitations are :
I do not want to count on stable 60 fps.
My physx has to run on a different thread (which was tester thread in the example above) than Ogre rendering thread.



-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


I am an ex Ogre, NxOgre and Axiom(C# Ogre) user and rightnow i am working on a piece of Openscenegraph code working with physx (no wrapper between).
We had kind of jitter, or stall (whatever it is called) problem (we even have network between physx and graphics, this is an extremely simplified version of our nightmare jitter&stall problem), and I remembered NxOgre community had a similar problem and it was fixed (around 2008 i guess). So i tried to reproduce my jitter problem with an ogre application. I obviously lack the knowledge to connect a physx engine to a graphics engine. And here i am :)

Thanks in advance for all the comments.

Arif Yetkin

betajaen

15-02-2011 17:45:29

I've read quickly through what you said.

What you may want to have a look at is Linear Interpolation aka "lerp" and fix your timestep.

I'll have another full read of your post later, if I can come up with something more concise. The fix your timestep which deals with low frame rate issues, basically you move the objects by "lerping", which calculates a position between frames based on the accumulator.

nord

17-02-2011 08:46:15

Thanks for the reply betajaen. I have already tried interpolation, and now I read "fix your timestep" and other articles of Glenn Fiedler. Although not the same, I think i tried a similar thing that is being told in the article.

From the tester thread, i enqueue the replay frames on a queue on Ogre thread with timestamps. The Ogre samples the buffer queue with its own timestamp, always getting an interpolated frame that falls within the queue. But i still see jittering. :( I am sure my interpolation and sampling code works correct. And it takes 0-1 miliseconds to sample the buffer queue which is ok i guess.

betajaen

17-02-2011 13:40:54

The only other thing I can think of is walaber years ago implemented that car game in Newton, if I remember correctly he had saved replays. If it's open source you could take a look at that.

Also; I'd ask on the main forums, since it's a pretty generic question. Your bound to get a better response than in here.

nord

18-02-2011 07:56:13

To clarify our problem, I have prepared a simple VS2005 solution. In the solution there is my physx replay, and it is being fed to Ogre from a terster thread. Tester thread sends each frame to Ogre either putting them on a single frame buffer or a queue of frames. Ogre application gets the next frame from the single frame buffer, or from the queue either by simply dequeueing or sampling with timestamp.

As soon as you set the working directory of the project to : $(SolutionDir)$(ConfigurationName), it should work in release mode. (I have deleted debug folder and its dlls because they were taking much space.)

You can easily see jittering in my application if you examine carefully. Whatever method of updating with tester thread you choose (by commenting&uncommenting), there is jittering, except when OGRE runs in 60fps, and it reads an 60Hz replay log from an already filled queue (it never skips frames, nor reads the same frame again to update the scene).

Regards.

LINK : http://rapidshare.com/files/448506023/K ... oDebug.rar

betajaen

18-02-2011 08:05:49

Downloading the file now. I'll try and look at it today for you.

nord

18-02-2011 08:45:44

Thank you betajaen :)

For those people who would like to inspect this test bed, here are some explanations :

There is a function called
void KtIGLibOGRE::performPendingUpdateRequestsOGRE()
It is called in render loop and updates Ogre scene.
You can switch between different methods of updating scene by simply commenting&uncommenting the chunks in this function.
1.SINGLE FRAME BUFFER : use a single frame for tester thread to write the new frame, Ogre to read the new frame.
2.BUFFER QUEUE : use a buffer of frames, where tester thread will enqueue new frames, Ogre will dequeue them.
3.BUFFER QUEUE WITH SAMPLING : use the same buffer queue, but also take the timestamps into account when sampling the queue instead of simple dequeueing from the front Tester thread writes timestamps when generating (actually reading them from file) new frames. On the other hand, Ogre checks the time at each render loop, and samples the queue accordingly.

There is another function called
void KtIGLibOGRE::updateEntityBatchedSerialOGRE(long timeStamp, std::vector<int> &ids, std::vector<double> &data)
which is used by the tester thread to send the frame information to Ogre.
1.You can put frames on the SINGLE FRAME BUFFER. Ogre may read the same frame more than once if it loops fast, or Ogre may not even read some frames and skip to others, if it loops slow, relative to the tester thread.
2.You can put frames on the BUFFER QUEUE. Ogre may read the frames either by simple dequeue, or sampling.

Feel free to test VSYNC on & off to alter OGRE fps, change tester thread run frequency
void TesterThread::run()
{
runPhysxTest(16);//feed OGRE at ~60Hz - 16 miliseconds
}

and use different methods to write and read frames. You can also decrease the fps of Ogre by
// create athene statue
for (int i=-5000;i<5000;i=i+500)
{
for (int j=-5000;j<5000;j=j+500)
{
SceneNode* mBodyNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(i,25,j),Quaternion::IDENTITY);
Ogre::Entity* mBodyEnt = mSceneMgr->createEntity("athene.mesh");
mBodyNode->attachObject(mBodyEnt);
mBodyNode->setScale(0.3,0.3,0.3);
}
}

altering the number of sceneNodes in the scene.

Also in Main.cpp if you use this chunk of code, it will create a thread to feed ogre:

testerThread->initPhysxTest();//read physx file
testerThread->start();//launch the tester thread that will feed Ogre with new x y z yaw pitch roll
iglib->startRenderLoopOGRE();//start our render loop, exit if escape is hit
testerThread->cancel();//kill the thread if its not already dead
iglib->destroyOGRE();//deinit ogre


and use this chunk of code in Main.cpp, it will not create a thread, but fill your buffer before rendering starts. :

testerThread->initPhysxTest(); //read physx file
testerThread->runPhysxTest(1);//fill in the buffer queue BEFORE starting rendering (1 means, sleep 1 miliseconds before putting another frame on the queue, parameter is actually used to adjust frequency, in this case we want to fill our queue asap)
iglib->startRenderLoopOGRE();//start our render loop, exit if escape is hit
iglib->destroyOGRE();//deinit ogre, no need to kill thread, since thread is not launched, but its functions are used sync.


Cheers!

nord

24-02-2011 07:50:20

For those that may want to take a look at the test bed, I discovered two bugs in my code. When calculating the ratio for interpolation, i did not cast the long values to double, so division always yielded 1 or 0. Make sure you add a (double) cast on that division. Also, in interpolation I didnt use inverse ratio (replace "ratio"s with "(1-ratio)"s , "(1-ratio)"s with "ratio"s in interpolation function).

Now when I save the interpolation results and plot it together with the actual physx data with their timestamps (on matlab), interpolation seems to be yielding correct results. Also visually, it keeps 3D object velocities kind of constant no matter the fps. Now I know that "fixing my timestep" works. However this still didnt solve my problem completely. I still see some stalls. I will appreciate if you tell me whether the replay is how it is supposed to be or not (when fps is decreased artificially). I will come up with more explanation and maybe with a video or VS solution to explain further. Thanks.