 Книги
КнигиЗдесь планировалось рассказать о точечных источниках света, но я думаю, что вы честно заработали небольшую перемену. Эта глава рассказывает о списках отображения (display lists). Как вы увидите, они не только сокращают размер OpenGL кода, но и повышают производительность, экономят место на диске, готовят кофе и бутербродами и проч. Что такое списки отображения? Говоря по-простому: это список вызовов OpenGL, хранящийся в одной переменной.
Чтобы показать пользу списков отображения, давайте рассмотрим простой пример. Создадим колонну с четырьмя сторонами, состоящую из низа (4 четырехугольника), средней части (4 четырехугольника), и верха (4 треугольника). Итого 12 поверхностей или 44 вершины.
  glBegin(GL_QUADS);
  glColor3f( 0.0, 0.0, 0.5 );
  
   glNormal3f(0.0,0.0,1.0);
    glVertex3f( 10.0,-10.0, 0.0);
    glVertex3f( 10.0, 10.0, 0.0);
    glVertex3f(-10.0, 10.0, 0.0);
    glVertex3f(-10.0,-10.0, 0.0);
  glEnd();
   
  glTranslatef( 0.0, 0.0, 1.0);
  glColor3f( 0.9, 0.0, 0.0 );
  
  glBegin(GL_QUADS);
   glNormal3f(1.0, 0.0, 0.0);
    glVertex3f( 1.0, 1.0,-1.0);
    glVertex3f( 1.0, 1.0, 1.0); // rechts unten
    glVertex3f( 1.0,-1.0, 1.0);
    glVertex3f( 1.0,-1.0,-1.0);
    
   glNormal3f(-1.0, 0.0, 0.0);
    glVertex3f(-1.0, 1.0, 1.0);
    glVertex3f(-1.0, 1.0,-1.0); // links unten
    glVertex3f(-1.0,-1.0,-1.0);
    glVertex3f(-1.0,-1.0, 1.0);
    
   glNormal3f(0.0,1.0,0.0);
    glVertex3f( 1.0, 1.0, 1.0);
    glVertex3f( 1.0, 1.0,-1.0); // hinten unten
    glVertex3f(-1.0, 1.0,-1.0);
    glVertex3f(-1.0, 1.0, 1.0);
    
   glNormal3f(0.0, -1.0, 0.0);
    glVertex3f( 1.0,-1.0,-1.0);
    glVertex3f( 1.0,-1.0, 1.0); // vorne unten
    glVertex3f(-1.0,-1.0, 1.0);
    glVertex3f(-1.0,-1.0,-1.0);
    
   FindNormal(-0.5,0.5,6.0,0.5,0.5,6.0,1.0,1.0,1.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f(-0.5, 0.5, 6.0);
    glVertex3f( 0.5, 0.5, 6.0); // vorne oben
    glVertex3f( 1.0, 1.0, 1.0);
    glVertex3f(-1.0, 1.0, 1.0);
    
   FindNormal(0.5,-0.5,6.0,-0.5,-0.5,6.0,-1.0,-1.0,1.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f( 0.5,-0.5, 6.0);
    glVertex3f(-0.5,-0.5, 6.0); // hinten oben
    glVertex3f(-1.0,-1.0, 1.0);
    glVertex3f( 1.0,-1.0, 1.0);
    
   FindNormal(1.0,1.0,1.0,0.5,0.5,6.0,0.5,-0.5,6.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f( 1.0, 1.0, 1.0);
    glVertex3f( 0.5, 0.5, 6.0); // rechts oben
    glVertex3f( 0.5,-0.5, 6.0);
    glVertex3f( 1.0,-1.0, 1.0);
    
   FindNormal(-0.5,0.5,6.0,-1.0,1.0,1.0,-1.0,-1.0,1.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f(-0.5, 0.5, 6.0);
    glVertex3f(-1.0, 1.0, 1.0); // links oben
    glVertex3f(-1.0,-1.0, 1.0);
    glVertex3f(-0.5,-0.5, 6.0);
glEnd(); 
glBegin(GL_TRIANGLES);
   FindNormal(-0.5,0.5,6.0,0.0,0.0,7.0,0.5,0.5,6.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f(-0.5, 0.5, 6.0);
    glVertex3f( 0.0, 0.0, 7.0);
    glVertex3f( 0.5, 0.5, 6.0); // vorne oben
   FindNormal(0.5,-0.5,6.0,0.0,0.0,7.0,-0.5,-0.5,6.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f( 0.5,-0.5, 6.0);
    glVertex3f( 0.0, 0.0, 7.0);
    glVertex3f(-0.5,-0.5, 6.0); // hinten oben
   FindNormal(0.5,0.5,6.0,0.0,0.0,7.0,0.5,-0.5,6.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f( 0.5, 0.5, 6.0); // rechts oben
    glVertex3f( 0.0, 0.0, 7.0);
    glVertex3f( 0.5,-0.5, 6.0);
    
   FindNormal(-0.5,-0.5,6.0,0.0,0.0,7.0,-0.5,0.5,6.0);
   glNormal3f(CNormal[1], CNormal[2], CNormal[3]);
    glVertex3f(-0.5,-0.5, 6.0);
    glVertex3f( 0.0, 0.0, 7.0);
    glVertex3f(-0.5, 0.5, 6.0); // links oben
glEnd;
Это все. Скачайте пример отсюда и посмотрите на него.
Все в порядке? Увидели? А теперь проделайте вот что: нарисуйте 4 колонны, стоящие на одной плоскости друг за дружкой. Вперед — и с песней!
Вы, наверно, подумали: "Это ведь так и умотаться можно!". Конечно, придется рассчитать координаты еще 220 вершин. Веселого здесь мало. Однако, с помощью списков отображения, можно использовать заново объект много раз.
Список отображения хранит такие вызовы OpenGL, как "установить вершину" или "осветить" и тому подобное. Сейчас сохраним в списке нашу колонну. Для этого нам потребуется целочисленная переменная и ID для нашего списка. И после присваивания Variable := glGenLists() наша ID будет указывать на список.
После создания списка нам следует его заполнить. Во-первых, нужно указать OpenGL, какой список хотим заполнить. Это делается при помощи glNewList(). Первый аргумент — имя списка, второй — то, как следует обращаться со списком. Для нашего случая выберем GL_COMPILE, что означает, что мы просто его заполним, а запускать будем потом.
Теперь последуют обычные вызовы OpenGL. Делайте, что хотите. Можно даже вызывать другие процедуры (например, вычисляющие нормали, и прочее). Если список заполнен, его следует закрыть посредством glEndList();
После создания списка, его можно запускать с помощью glCallList(). Каждый раз, когда мы его запускаем, список исполняется, рисуя ту хрень, что в него была занесена. В нашем примере мы нарисуем колонну, сделаем трансляцию, и нарисуем следующую.
glColor3f( 0.0, 0.0, 0.5 ); glTranslatef( 0.0, 0.0, 1.0); glCallList(Ground); glColor3f( 0.9, 0.0, 0.0 ); glTranslatef( 5.0,5.0,0.0); glCallList(Pillar); glColor3f( 0.0, 0.9, 0.0 ); glTranslatef( 0.0,-10.0,0.0); glCallList(Pillar); glColor3f( 0.9, 0.9, 0.0 ); glTranslatef(-10.0,0.0,0.0); glCallList(Pillar); glColor3f( 0.0, 0.9, 0.9 ); glTranslatef(0.0,10.0,0.0); glCallList(Pillar);
То есть рисование четырех колонн занимает меньше места, чем рисование одной непосредственным способом. Наша процедура OpenGL стала намного более читабельной. Теперь берите пример и пробуйте свои силы.
Другим преимуществом является то, что теперь нам не надо каждый раз вычислять нормали. Они рассчитываются один раз в начале, а затем просто вызываются из списка. Кроме того, большинство 3d карт могут выполнять списки отображения быстрее, чем обычные вызовы OpenGL, поскольку они производят кэширование.
А теперь, в качестве приза за то, что дочитали до этого места, леденец на палочке. Скомпилируйте и наслаждайтесь ;)
| FPC | 3.2.2 | release | 
| Lazarus | 3.2 | release | 
| MSE | 5.10.0 | release | 
| fpGUI | 1.4.1 | release |