How to slow down opengl animation read from BVH files?

瘦欲@ 提交于 2019-12-13 03:24:20

问题


Using GLFW3, I currently made a bvh file parser which reads the file in and converts it to a human model I made in opengl. However, whenever I launch it, the movement is so fast that the animation cannot be seen in the eye. So I want to tone the animation speed a little down. Here is my render loop

while (!glfwWindowShouldClose(window))
    {
        // per-frame time logic
        // --------------------
        float currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // input
        // -----
        processInput(window);

        // render
        // ------
        glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        (Some Shader Settings)

        glm::mat4 model = glm::mat4(1.0f);

        if (moveFlag == true) {
            bvh.clearVISITED();
            bvh.setMotionPerFrame(bvh.root, 0);
        }
        if (resetMatrices == true) {
            bvh.clearVISITED();
            bvh.resetMatrices(bvh.root);
        }

        drawBones(shader, bvh.root, model);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

The function inside the if statement bvh.setMotionPerFrame(bvh.root, 0) is where the animation reads in the JOINT configurations per Frame data inside the file, and sets each joint's rotation matrix and translation matrix accordingly. (moveFlag and resetMatricesare flags that are set if spacebar and r button are hit respectively)

Since reading the channel data per frame in each render loop unchangeable, I want to come up with a way that I can slower the render loop speed itself. Any suggestions?


回答1:


You need to add timing to your code. while you are parsing BVH MOTION like this:

MOTION
Frames:     20
Frame Time: 0.033333

you should extract the Frame Time value which is the time between frames in seconds. Now depending on the code architecture of yours you need to properly time your rendering. I am used to have some

bool _redraw=false;

telling whole app to redraw on next possible occasion (like timer) which is set by anything from mouse/keyboard events changing view or scene to resizing of window etc...

For time changing stuff I also usually have a function:

void update(double dt);

periodically called from app handling interpolation/simulation and stuff for dt time elapsed from last call. Now the dt can be timer interval that calls this or in case I need better accuracy I measure dt directly using windows PerformanceCounter. In case you just got endless loop you still can use:

Sleep(dt*1000.0);

which is not precise but will work.

More on animation and timing topic can be found in here and the sublinks:

  • Sprites sequence control through DeltaTime

Now getting back to BVH here is how my C++ update method for it looks like:

void bvh::update() // call periodically to animate
 {
 if ((_play)&&(dt>1e-6))
  { 
  int f=frame;
  t+=tper(&t0);
  while (t>=dt)
   {
   t-=dt;
   frame++;
   if (frame>=frames)
    {
    frame=0;
    if (!_loop){ stop(); break; }
   }
  }
  if (f!=frame) setframe(frame);
 }
}

here some selected stuff from my BVH class:

List<int> root;             // root bones ix
List<bvh_bone> bone;        // HIERARCHY bvh
List<double> data;          // MOTION data
int frames;                 // MOTION frames
double dt;                  // MOTION delta time [ms]
int channels;               // channels/frame
// render
bool _redraw;               // out redraw needed?
// animation
bool _loop;                 // in loop playback?
bool _play,_pause,_stop;    // out animation buttons state?
int frame;                  // actual set frame
double t,t0;                // time elapsed from start of actual frame, measurement start time
void play() { tper(&t0); t=0.0; if (!_pause) frame=0; _play=1; _pause=0; _stop=0; setframe(frame); _redraw=true; }
void stop() { tper(&t0); t=0.0;                       _play=0; _pause=0; _stop=1; frame=0; setframe(frame); _redraw=true; }
void pause(){ tper(&t0); t=0.0; if (_stop) return;    _play=_pause; _pause=!_pause; }
void setframe(int frame);   // compute bones from frame data

And tper function measures time between its subsequent calls taken from my timing lib:

const int   performance_max=64;                 // push levels
double      performance_Tms=-1.0,               // counter period [ms]
            performance_tms=0.0,                // measured time after tend [ms]
            performance_t0[performance_max];    // measured start times [ms]
int         performance_ix=-1;                  // actual time stack index

double tper(double *t0=NULL)    // return duration [ms] between tper() calls
    {
    double t,tt;
    LARGE_INTEGER i;
    if (performance_Tms<=0.0)
        {
        for (int j=0;j<performance_max;j++) performance_t0[j]=0.0;
        QueryPerformanceFrequency(&i); performance_Tms=1000.0/double(i.QuadPart);
        }
    QueryPerformanceCounter(&i); t=double(i.QuadPart); t*=performance_Tms;
    if (t0) { tt=t-t0[0]; t0[0]=t; performance_tms=tt; return tt; }
    performance_ix++;
    if ((performance_ix>=0)&&(performance_ix<performance_max))
        {
        tt=t-performance_t0[performance_ix];
        performance_t0[performance_ix]=t;
        }
    else { t=0.0; tt=0.0; };
    performance_ix--;
    performance_tms=tt;
    return tt;
    }

Now in main app loop/timer just call periodicaly the update and if _redraw is true set it to false and repaint your app. Beware my bvh::dt was converted to [ms] !!!



来源:https://stackoverflow.com/questions/52804160/how-to-slow-down-opengl-animation-read-from-bvh-files

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!