如何减慢从 BVH 文件读取的 opengl 动画?
How to slow down opengl animation read from BVH files?
我目前使用 GLFW3 制作了一个 bvh 文件解析器,它读取文件并将其转换为我在 opengl 中制作的人体模型。但是,每当我启动它时,动作太快以至于眼睛看不到动画。所以我想把动画速度调低一点。这是我的渲染循环
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();
}
if语句bvh.setMotionPerFrame(bvh.root, 0)
中的函数是动画读取文件中每帧数据的JOINT配置,并相应地设置每个关节的旋转矩阵和平移矩阵。 (moveFlag
和 resetMatrices
分别是在按下空格键和 r 按钮时设置的标志)
由于在每个渲染循环中读取每帧的通道数据是不可更改的,我想想出一种方法来降低渲染循环本身的速度。有什么建议吗?
您需要在代码中添加计时。当您像这样解析 BVH MOTION 时:
MOTION
Frames: 20
Frame Time: 0.033333
您应该提取 Frame Time
值,该值是帧之间的时间(以秒为单位)。现在,根据您的代码架构,您需要正确地安排渲染时间。我习惯了一些
bool _redraw=false;
告诉整个应用程序在下一个可能的场合(比如计时器)重绘,这是由任何东西设置的,从 mouse/keyboard 事件改变视图或场景到调整 window 大小等...
对于时间变化的东西,我通常也有一个功能:
void update(double dt);
定期从处理 interpolation/simulation 的应用程序中调用,并在自上次调用后 dt
时间后处理内容。现在 dt
可以是调用它的计时器间隔,或者如果我需要更高的准确性,我直接使用 windows PerformanceCounter
测量 dt
。如果你只是无限循环你仍然可以使用:
Sleep(dt*1000.0);
虽然不准确,但可以。
可以在此处和子链接中找到有关动画和计时主题的更多信息:
现在回到 BVH,这是我的 C++ 更新方法的样子:
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);
}
}
这里是我的 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
和 tper
函数测量从我的计时库中获取的后续调用之间的时间:
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;
}
现在在主应用程序 loop/timer 中,只需定期调用 update
,如果 _redraw
为真,则将其设置为假并重新绘制您的应用程序。当心我的 bvh::dt
被转换为 [ms] !!!
我目前使用 GLFW3 制作了一个 bvh 文件解析器,它读取文件并将其转换为我在 opengl 中制作的人体模型。但是,每当我启动它时,动作太快以至于眼睛看不到动画。所以我想把动画速度调低一点。这是我的渲染循环
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();
}
if语句bvh.setMotionPerFrame(bvh.root, 0)
中的函数是动画读取文件中每帧数据的JOINT配置,并相应地设置每个关节的旋转矩阵和平移矩阵。 (moveFlag
和 resetMatrices
分别是在按下空格键和 r 按钮时设置的标志)
由于在每个渲染循环中读取每帧的通道数据是不可更改的,我想想出一种方法来降低渲染循环本身的速度。有什么建议吗?
您需要在代码中添加计时。当您像这样解析 BVH MOTION 时:
MOTION
Frames: 20
Frame Time: 0.033333
您应该提取 Frame Time
值,该值是帧之间的时间(以秒为单位)。现在,根据您的代码架构,您需要正确地安排渲染时间。我习惯了一些
bool _redraw=false;
告诉整个应用程序在下一个可能的场合(比如计时器)重绘,这是由任何东西设置的,从 mouse/keyboard 事件改变视图或场景到调整 window 大小等...
对于时间变化的东西,我通常也有一个功能:
void update(double dt);
定期从处理 interpolation/simulation 的应用程序中调用,并在自上次调用后 dt
时间后处理内容。现在 dt
可以是调用它的计时器间隔,或者如果我需要更高的准确性,我直接使用 windows PerformanceCounter
测量 dt
。如果你只是无限循环你仍然可以使用:
Sleep(dt*1000.0);
虽然不准确,但可以。
可以在此处和子链接中找到有关动画和计时主题的更多信息:
现在回到 BVH,这是我的 C++ 更新方法的样子:
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);
}
}
这里是我的 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
和 tper
函数测量从我的计时库中获取的后续调用之间的时间:
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;
}
现在在主应用程序 loop/timer 中,只需定期调用 update
,如果 _redraw
为真,则将其设置为假并重新绘制您的应用程序。当心我的 bvh::dt
被转换为 [ms] !!!