Скачиваний:
115
Добавлен:
23.02.2015
Размер:
702.98 Кб
Скачать
  1. Оптимизация программ

    1. Организация приложения

На первый взгляд может показаться, что производительность приложений, основанных на OpenGL, определяется в первую очередь производительностью реализации самой библиотекиOpenGL. Это верно, однако организация всего приложения также очень важна.

      1. Высокоуровневая оптимизация

Обычно от программы под OpenGLтребуется визуализация высокого качества на интерактивных скоростях. Но, как правило, и то и другое сразу получить не удается. Следовательно, необходим поиск компромисса между качеством и производительностью. Существует множество различных подходов, но их подробное описание выходит за пределы этого пособия. Приведем лишь несколько примеров.

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

  • Аналогично, объекты, которые располагаются далеко от наблюдателя, могут быть представлены моделями пониженной сложности. Это значительно снизит нагрузку на все ступени конвейера OpenGL. Объекты, которые находятся полностью вне поля видимости, могут быть эффективно отсечены без передачи на конвейерOpenGLс помощью проверки попадания ограничивающих их простых объемов (сфер или кубов) в пирамиду зрения.

  • Во время анимации можно отключить псевдотонирование (dithering), плавную заливку, текстуры. Опять-таки включать все это во время демонстрации статичных изображений. Этот подход особенно эффективен для систем без аппаратной поддержкиOpenGL.

      1. Низкоуровневая оптимизация

Объекты, отображаемые с помощью OpenGL, хранятся в некоторых структурах данных. Одни типы таких структур более эффективны в использовании, чем другие, что определяет скорость визуализации.

Желательно, чтобы использовались структуры данных, которые могут быть быстро и эффективно переданы на конвейер OpenGL. Например, если мы хотим отобразить массив треугольников, то использование указателя на этот массив значительно более эффективно, чем передача егоOpenGLпоэлементно.

Пример:

Предположим, что мы пишем приложение, которое реализует рисование карты местности. Один из компонентов базы данных – список городов с их шириной, долготой и названием. Соответствующая структура данных может быть такой:

struct city

{

   float latitute, longitude; /* положение города */

char*name;              /* название */

   intlarge_flag;     /* 0 = маленький, 1 = большой */

};

Список городов может храниться как массив таких структур. Допустим, мы пишем функцию, которая рисует города на карте в виде точек разного размера с подписями:

void draw_cities( int n, struct city citylist[] )

{

   int i;

   for (i=0; i < n; i++)

{

   if (citylist[i].large_flag)

         glPointSize( 4.0 );

     else

      glPointSize( 2.0 );

   glBegin( GL_POINTS );

     glVertex2f( citylist[i].longitude,

citylist[i].latitude );

   glEnd();

/* рисуем название города */

 DrawText(citylist[i].longitude, citylist[i].latitude,

citylist[i].name);

    }

}

Это реализация неудачна по следующим причинам:

  • glPointSizeвызывается для каждой итерации цикла.

  • между glBeginиglEndрисуется только одна точка.

  • вершины определяются в неоптимальном формате.

Ниже приведено более рациональное решение:

  void draw_cities( int n, struct city citylist[] )

  {

      inti;

      /* сначала рисуем маленькие точки */

      glPointSize( 2.0 );

      glBegin( GL_POINTS );

      for (i=0; i < n ;i++)

{

         if (citylist[i].large_flag==0) {

            glVertex2f( citylist[i].longitude,

citylist[i].latitude );

        }

      }

      glEnd();

      /* большие точки рисуем во вторую очередь */

      glPointSize( 4.0 );

      glBegin( GL_POINTS );

      for (i=0; i < n ;i++)

{

        if (citylist[i].large_flag==1)

{

          glVertex2f( citylist[i].longitude,

citylist[i].latitude );

        }

      }

     glEnd();

/* затем рисуем названия городов */

   for (i=0; i < n ;i++)

{

     DrawText(citylist[i].longitude, citylist[i].latitude,

citylist[i].name);

   }

}

В такой реализации мы вызываем glPointSizeдважды и увеличиваем число вершин междуglBeginиglEnd.

Однако остаются еще пути для оптимизации. Если мы поменяем наши структуры данных, то можем еще повысить эффективность рисования точек. Например:

struct city_list

{

intnum_cities; /* число городов в списке */

float*position;/* координаты города */

char**name;   /* указатель на названия городов */

  floatsize;    /* размер точки, обозначающей город */

};

Теперь города разных размеров хранятся в разных списках. Положения точек хранятся отдельно в динамическом массиве. После реорганизации мы исключаем необходимость в условном операторе внутри glBegin/glEndи получаем возможность использовать массивы вершин для оптимизации. В результате наша функция выглядит следующим образом:

void draw_cities( struct city_list *list )

{

  inti;

  /* рисуем точки */

  glPointSize( list->size );

  glVertexPointer( 2, GL_FLOAT, 0,

list->num_cities,

list->position );

  glDrawArrays( GL_POINTS, 0, list->num_cities );

  /* рисуем название города */

  for (i=0; i < list->num_cities ;i++)

{

     DrawText(citylist[i].longitude, citylist[i].latitude

citylist[i].name);

}

}

Соседние файлы в папке Программирование графических приложений