Как замедлить чтение анимации opengl из файлов BVH?

Используя 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 нажимаются соответственно)

Поскольку считывание данных канала на кадр в каждом цикле рендеринга невозможно изменить, я хочу найти способ замедления самой скорости цикла рендеринга. Какие-либо предложения?

0

Решение

Вам нужно добавить время в ваш код. пока вы разбираете BVH MOTION вот так:

MOTION
Frames:     20
Frame Time: 0.033333

Вы должны извлечь Frame Time значение, которое является временем между кадрами в секундах. Теперь, в зависимости от вашей архитектуры кода, вам нужно правильно рассчитать время рендеринга. Я привык иметь немного

bool _redraw=false;

указание всему приложению перерисовать при следующем возможном случае (например, по таймеру), который задается чем угодно, от событий мыши / клавиатуры, изменения вида или сцены, до изменения размера окна и т. д.

Для изменения времени у меня также обычно есть функция:

void update(double dt);

периодически вызывается из приложения, обрабатывающего интерполяцию / симуляцию и прочее для dt время, прошедшее с последнего звонка. Теперь dt может быть интервал таймера, который вызывает это или в случае, если мне нужна лучшая точность, я измеряю dt напрямую используя окна PerformanceCounter, Если вы только что получили бесконечный цикл, вы все равно можете использовать:

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:

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 Функция измеряет время между своими последующими вызовами, взятыми из моей библиотеки 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;
}

Теперь в главном цикле приложения / таймере просто вызовите update и если _redraw Значение true, установите значение false и перекрасьте ваше приложение. Осторожно, мой bvh::dt был преобразован в [мс] !!!

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]