Как сделать пошаговое отображение анимации в openGL ??
Я делаю проект принтера reprap, чтобы прочитать файл GCode и интерпретировать его в графический.
теперь мне сложно сделать пошаговую анимацию рисования всего объекта.
Мне нужно нарисовать много коротких линий, чтобы составить целый объект.
например:
|-----|
| |
| |
|-----|
квадрат состоит из множества коротких линий, и каждая строка генерируется кодом, подобным следующему:
glPushMatrix();
.....
for(int i=0; i< instruction[i].size(),i++)
{ ....
glBegin(GL_LINES);
glVertex3f(oldx, oldy, oldz);
glVertex3f(x, y, z);
glEnd();
}
glPopMatrix();
Теперь я хочу сделать пошаговую анимацию, чтобы показать, как сделан этот квадрат. Я пытался обновлять экран каждый раз, когда рисуется новая линия, но она не работает, сразу появляется весь квадрат. Кто-нибудь знает, как это сделать?
Типичные реализации OpenGL помещают в очередь большое количество вызовов, чтобы объединить их в пакеты активности для оптимального использования доступной пропускной способности связи и временных ресурсов графического процессора.
То, что вы хотите сделать, это в основном противоположность рендеринга с двойной буферизацией, то есть рендеринга, где каждый шаг рисования сразу виден. Одним из способов сделать это является рендеринг в одно буферизованное окно и вызов glFinish()
после каждого шага. Основной недостаток: вероятно, он не будет хорошо работать на современных системах, которые используют композитные оконные менеджеры и тому подобное.
Другой подход, который я рекомендую, заключается в использовании отдельного буфера для инкрементного рисования и постоянного обновления основного кадрового буфера из этого. Ключевыми предметами являются Объект буфера кадра а также Render To Texture.
Сначала вы создаете FBO (множество учебных пособий и ответы на StackOverflow). FBO — это, по сути, абстракция, к которой вы можете подключить целевые буферы, такие как текстуры или рендеринг-буферы, и которые могут быть связаны как назначение вызовов при рисовании.
Так как решить вашу проблему с ними? Во-первых, вы не должны делать анимацию, задерживая цикл рисования. У этого есть несколько причин, но главная проблема заключается в том, что вы теряете интерактивность программы. Вместо этого вы поддерживаете (глобальный) счетчик, на котором вы находитесь. Давайте назовем это step
:
int step = 0;
Затем в вашей функции рисования вы должны поэтапно: 1) Обновление текстуры 2) Обновление экрана
Первая фаза состоит в связывании вашего объекта кадрового буфера как цели рендеринга. Чтобы это работало, целевая текстура должна быть свободной
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, animFBO);
glViewport(0, 0, fbo.width, fbo.height);
set_animFBO_projection();
Хитрость заключается в том, что вы очищаете animFBO только один раз, а именно после создания, а затем никогда больше. Теперь вы рисуете свои линии в соответствии с шагом анимации
draw_lines_for_step(step);
и увеличить счетчик шагов (можно сделать это как составной оператор, но это более явно)
step++;
После обновления анимации FBO самое время обновить экран. Сначала уберите animFBO
glBindFramebuffer(GL_FRAMEBUFFER, 0);
Теперь мы находимся в основном экранном фреймбуфере
glViewport(0, 0, window.width, window.height);
set_window_projection(); //most likely a glMatrixMode(GL_PROJECTION); glOrtho(0, 1, 0, 1, -1, 1);
Теперь свяжите прикрепленную текстуру FBO и нарисуйте ее в полный квад квадрата
glBindTexture(GL_TEXTURE_2D, animFBOTexture);
draw_full_viewport_textured_quad();
Наконец, сделайте замену буфера, чтобы показать итерацию шага анимации
SwapBuffers();
Вы должны вызывать метод SwapBuffer после каждого вызова draw.
Убедитесь, что вы не завинчиваете стек матрицы, и вам, вероятно, понадобится что-то, чтобы «приостановить» рендеринг, как точка останова.
Если вы хотите, чтобы строки появлялись одна за другой, и вам не нужно придирчиво относиться к эффективности или хорошему стилю программирования, попробуйте что-то вроде:
(в вашем обычном рисовании)
if (timer > 100)
{
//draw the next line
timer = 0;
}
else
timer++;
//draw all the other lines (you have to remember wich one already appeared)
//for example using a boolean array "lineDrawn[10]"
Таймер — это целое число, которое говорит вам, как часто вы рисуете сцену. Если вы увеличите его, то при запуске программы на экране будет происходить медленнее.
Конечно, это работает, только если у вас есть процедура розыгрыша. Если нет, я настоятельно рекомендую использовать один.
-> множество учебных пособий довольно везде, например
http://nehe.gamedev.net/tutorial/creating_an_opengl_window_%28win32%29/13001/
Удачи тебе!
PS: я думаю, что вы сделали почти то же самое, но без таймера. Вот почему все было нарисовано так быстро, что вы подумали, что оно появилось одновременно.