Animation using OpenGL

  • Thread starter Thread starter Alhexx
  • Start date Start date
Status
Not open for further replies.
I suppose animations with frames missing beyond the end of the animation can be assumed to be repeating and the frames be 'extended' as a loop?

That does make things more interesting to decode though doesn't it :D

Cyb
 
Well, this might sound newbish, but how do I do that animation when not using a timer? Using that DWORD value L.Spiro said is no problem - I did this using the "clock" command, which returns the current process' lifetime in milliseconds.

Once I have drawn Frame 1, I have to make the engine redraw. Redrawing calling CWnd's UpdateWindow() function does not work - I have to invalidate the client area by moving the mouse for example...
Invalidating the client area using "Invalidate()" or "RedrawWindow()" mess up the window's other childs as the toolbar. Calling "PostMessage(WM_PAINT)" maks my app run in some sort of endless-loop - so I can't even close the window without killing it using the task manager... -_-

Here's the code of a test program I wrote - it simply simutes a "second pointer" of an analog clock:
Code: [Select]
Code:
void COpenGLView::Render(void){ // Get current time clock_t CurTime = clock();  // Calculate difference between last click and now double dDiff = double(CurTime - m_LastTime); m_LastTime = CurTime; m_Angle += dDiff * CLK_TO_RAD;  if(m_Angle >= 360)  m_Angle -= 360; glColor3f(1, 1, 1); glRotatef(m_Angle, 0, 0, -1.0f); glBegin(GL_LINES); glVertex3f(0, 0, 0); glVertex3f(0, 2, 0); glEnd(); //Invalidate(); //RedrawWindow(); UpdateWindow(); //PostMessage(WM_PAINT);}

 - Alhexx
 
Handle this in your window message loop.

As you know, you will already have a loop created to catch all incoming messages and dispatch them.

Use this loop to draw the scene as well.
Usually the loop checks for messages, and if there are any in the queue, it dispatches them and continues.
Then, if there are no message, it calls the game engine function (usually Tick()) which will handle an entire single frame of the game engine, from physics to rendering.

Depending on how you have set up your engine, you would handle input either at the beginning of your Tick() function or use the WM_* messages dispatched by your message handler.
For your project, you would definitely want to use the WM_* messages, which means your Tick() will only need to calculate the current frame of the object being displayed, attach its bones, and then render it.
Your current method of accepting input will remain in tact and you don’t need to change it at all.


There is one last thing.
Be careful how you use my DWORD method with clock().
You are probably already doing it correctly, but the only thing about which you have to be careful is using a very high DWORD and converting it to a FLOAT.
As you know, FLOAT’s lose accuracy when they reach higher numbers, which may cause your animation to be jerky, especially when using interpolation.
So you must always calculate the time that has passed since the start of the animation rather than using the time the computer has been on (timeGetTime()) or the time since all existance as we know it began (clock()).
Of course, to calculate the time since the animation began, you can use any method you want, be it clock() or timeGetTime() or another.


L. Spiro
 
Well, there's a problem with the message loop - I do not handle it.
I'm using MFC for the application, including document-view-architecture...

The function "Render()" is called in "OnDraw()", CView's handler for the WM_PAINT message...


I have tried overriding CWinApp's OnIdle() and Run() methods, but it didn't help...

 - Alhexx
 
The function "Render()" is called in "OnDraw()", CView's handler for the WM_PAINT message...
It has been a while... but can you send a repaint message from a timer?
 
No, I was told not to use timers since they're inaccurate.

Finally, I have found a solution. I had to override CWinApp's OnIdle() function to achieve instant redrawing without letting the rest of the window die:

Code: [Select]
Code:
BOOL COpenGLApp::OnIdle(LONG lCount){ CMainFrame* pFrame = (CMainFrame*)GetMainWnd(); if(pFrame) {  COpenGLView* pView = (COpenGLView*)pFrame->GetActiveView();  if(pView)   //pView->Invalidate();   //pView->PostMessage(WM_PAINT);   pView->OnDraw(pView->GetDC()); } return TRUE; //return CWinApp::OnIdle(lCount);}

Okay, problem solved.

 - Alhexx
 
Sorry, for double-posting, but I want to give it another try:


I've been trying around to programm a test tool to practice with Key frames.
The tool is very simple, it simply draws a line, the only animation is a rotation of the line around (0,0,0).

There is a total of 100 Frames in the loop. There are 4 Keyframes:

KeyFrame #0 (Frame #0): Rotation value: 0°
KeyFrame #1 (Frame #10): Rotation value: -45°
KeyFrame #2 (Frame #20): Rotation value: 0°
KeyFrame #3 (Frame #60): Rotation value: 45°

Member explanation:
m_iKeyFramesIndex tells the frame offset of a keyframe (e.g. m_iKeyFramesIndex[1] = 10 )
m_fKeyFrames is the rotation of the keyframe.

Here's the code I used:
Code: [Select]
Code:
void COpenGLView::Render(void){ glColor3f(1, 1, 1); if(m_bAnimate) {  // Get elapsed time  long lTime = clock() - m_StartTime;  // Convert to frame offset  double dFrameOff = double(lTime) / 1000 * double(m_iFramesPerSec);  // Simulate modulo: dFrameOff % m_iTotalFrames  dFrameOff -= double(int(dFrameOff / m_iTotalFrames) * m_iTotalFrames);  // Find the 2 neighbours  int iKey1 = 0;  int iKey2 = 0;  // Find left neighbour  for(int i = 0; i < m_iNumKeyFrames; i++)  {   if(double(m_iKeyFramesIndex[i]) <= dFrameOff)    iKey1 = i;   if(double(m_iKeyFramesIndex[i]) > dFrameOff)    break;  }  // Find right neighbour  if((iKey1+1) >= m_iNumKeyFrames)   iKey2 = 0;  else   iKey2 = iKey1 + 1;  // Calculate frame position  double dFramePos = dFrameOff - double(m_iKeyFramesIndex[iKey1]);  if(iKey2 > 0)   dFramePos /= double(m_iKeyFramesIndex[iKey2] - m_iKeyFramesIndex[iKey1]);  else   dFramePos /= double(m_iTotalFrames - m_iKeyFramesIndex[iKey1]);  // Calculate current frame  float fCurFrame =   (m_fKeyFrames[iKey1] * (1.0 - dFramePos)) +   (m_fKeyFrames[iKey2] * dFramePos);  // Rotate  glRotatef(fCurFrame, 0, 0, 1.0f); } // Render our line glBegin(GL_LINES); glVertex3f(0, 0, 0); glVertex3f(0, -3, 0); glEnd();}

Surprisingly, the code does what it should do :P
However, I have problem:
When I start the app, the frame rate is ~120 FPS. After a minute of running it goes down to ~50 FPS...

Does anyone know why? And does anyone have suggestions to improve the code?

 - Alhexx

 - edit -
I have uploaded the compiled tool incl. source code here:
http://www.alhexx.com/stuff/OpenGL_Anim.rar
 
Status
Not open for further replies.
Back
Top