Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Новости ИТ Программы Книги Games   Обои   Экспорт RSS E-Books
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full
 
Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
 

ИЗУЧИТЕ КОМПЬЮТЕР
ОТ А ДО Я!

(Всего 230 видео урока)

Вы эффективно освоите: компьютер, Интернет, программы, удаление вирусов, установку windows xp, windows 7, видеомонтаж и многое другое...

УЗНАЙТЬ ПОДРОБНОСТИ О КУРСЕ! >>>

 
Поиск по сайту

 
 

   Программирование -> C++ Builder -> Основы программирования OpenGL

На кого рассчитана статья

Я рассчитываю на то, что вы знакомы с азами создания приложений в С++Builder или Delphi и совсем не знаете OpenGL.

Введение

OpenGL (Open Graphics Library) - популярная библиотека для работы с 3D графикой. Стандарт OpenGL появился в 1992 году благодаря компании Silicon Graphics и сейчас переживает годы своего самого бурного развития.

Чуть-чуть побольше узнать об OpenGL и о том, как с ним работать в VC, можно, почитав wat'а: http://www.gamedev.ru/coding/11203.shtml

Я хочу показать, как работать с этой библиотекой в таких популярных и, на мой взгляд, очень удобных средах разработки, как Delphi и С++Builder.

Эта - первая - статья посвящена в основном инициализации OpenGL.

Инициализация

Первым делом нужно подключить заголовочные файлы:

С++

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>

Delphi

uses OpenGL;

Если вы используете Delphi, то всё необходимое для работы с OpenGL находится в модуле OpenGL.dcu. А если вы используете С++Builder, то подключать придётся несколько файлов:

  • gl.h и glu.h содержат прототипы основных функций OpenGL определённых в opengl32.dll и glu32.dll.
  • glaux.h содержит вспомогательные (auxiliary) функции (glaux.dll). В этой статье я не буду использовать glaux.h, т.к. его функции не доступны в Delphi, да и не люблю я эту библиотеку. Кроме того основные задачи glaux (как, в прочем, и аналогичной, но более качественной, библиотеки GLUT) - это создание окон, таймеров, обработка клавиатуры и мыши, всё это есть в ИСР (Интегральная Среда Разработки) Delphi или С++Builder.

После подключения заголовочных файлов нужно установить формат пикселей. Я для этой цели использую следующую функцию:

С++

      BOOL bSetupPixelFormat(HDC hdc)
      {
          PIXELFORMATDESCRIPTOR pfd, *ppfd;
          int pixelformat;
          ppfd = &pfd;
          ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
          ppfd->nVersion = 1;
          ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
          ppfd->dwLayerMask = PFD_MAIN_PLANE;
          ppfd->iPixelType = PFD_TYPE_RGBA;
          ppfd->cColorBits = 16;
          ppfd->cDepthBits = 16;
          ppfd->cAccumBits = 0;
          ppfd->cStencilBits = 0;
          if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0)
          {
              MessageBox(NULL, "ChoosePixelFormat failed", "Error", 
        MB_OK);
              return FALSE;
          }
          if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
          {
              MessageBox(NULL, "SetPixelFormat failed", "Error", 
        MB_OK);
              return FALSE;
          }
          return TRUE;
      }

Delphi

      function bSetupPixelFormat(DC:HDC):boolean;
      var
          pfd:PIXELFORMATDESCRIPTOR;
          ppfd:PPIXELFORMATDESCRIPTOR;
          pixelformat:integer;
      begin
          ppfd := @pfd;
          ppfd.nSize := sizeof(PIXELFORMATDESCRIPTOR);
          ppfd.nVersion := 1;
          ppfd.dwFlags :=  PFD_DRAW_TO_WINDOW xor
                           PFD_SUPPORT_OPENGL xor
                           PFD_DOUBLEBUFFER;
          ppfd.dwLayerMask := PFD_MAIN_PLANE;
          ppfd.iPixelType := PFD_TYPE_RGBA;
          ppfd.cColorBits := 16;           
          ppfd.cDepthBits := 16;
          ppfd.cAccumBits := 0;
          ppfd.cStencilBits := 0;
          pixelformat := ChoosePixelFormat(dc, ppfd);
          if pixelformat=0 then
          begin
              MessageBox(0, 'ChoosePixelFormat failed', 'Error', MB_OK);
              bSetupPixelFormat:=FALSE;
              exit;
          end;
          if SetPixelFormat(dc, pixelformat, ppfd)=false then
          begin
              MessageBox(0, 'SetPixelFormat failed', 'Error', MB_OK);
              bSetupPixelFormat:=FALSE;
              exit;
          end;
          bSetupPixelFormat:=TRUE;
      end;

Вряд ли вам придётся менять что-нибудь в этой функции, но кое-что о структуре PIXELFORMATDESCRIPTOR сказать надо.

cColorBits - глубина цвета

cDepthBits - размер буфера глубины (Z-Buffer)

cStencilBits - размер буфера трафарета (мы его пока не используем)

iPixelType - формат указания цвета. Может принимать значения PFD_TYPE_RGBA (цвет указывается четырьмя параметрами RGBA - красный, зленный, синий и альфа) и PFD_TYPE_COLORINDEX (цвет указывается индексом в палитре). Как вы видите, я использую RGBA, и вам придётся поступить также, т.к. если вы захотите использовать COLORINDEX, то вам придётся изменить мою функцию: добавить пару флагов и дать начальные значения ещё нескольким переменным.

Более подробную информацию смотрите в справочнике или в MSDN.

Функция ChoosePixelFormat подбирает формат пикселей, максимально удовлетворяющий нашим требованиям, и возвращает его дескриптор, а SetPixelFormat устанавливает его в контексте устройства (dc).

После того как в контексте устройства установлен формат пикселей, нужно создать контекст воспроизведения (Rendering Context) для этого в OpenGL определены следующие функции:

С++

  HGLRC wglCreateContext(HDC hdc);
  BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc);

Delphi

  function wglCreateContext(dc: HDC): HGLRC;
  function wglMakeCurrent(dc: HDC; glrc: HGLRC):Boolean;

Наверное, объяснять их значение не стоит

Теперь перейдём к форме. В объявлении класса формы в области private добавьте следующее:

С++

  HGLRC ghRC;
  HDC   ghDC;
  void Draw();

Delphi

  ghRC:HGLRC;
  ghDC:HDC;
  procedure Draw;

ghRC - указатель на контекст воспроизведения (Rendering Context)

ghDC - дескриптор устройства (для нас - просто указатель на окно)

Процедура Draw будет отвечать за рисование.

Далее заполняем FormCreate:

С++

      void __fastcall TForm1::FormCreate(TObject *Sender)
      {
         ghDC = GetDC(Handle);
         if (!bSetupPixelFormat(ghDC))
            Close();
         ghRC = wglCreateContext(ghDC);
         wglMakeCurrent(ghDC, ghRC);
         glClearColor(0.0, 0.0, 0.0, 0.0);
         FormResize(Sender);
         glEnable(GL_COLOR_MATERIAL);
         glEnable(GL_DEPTH_TEST);
         glEnable(GL_LIGHTING);
         glEnable(GL_LIGHT0);
           float p[4]={3,3,3,1},
                 d[3]={-1,-1,-3};
         glLightfv(GL_LIGHT0,GL_POSITION,p);
         glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,d);
      }

Delphi

      procedure TForm1.FormCreate(Sender: TObject);
      var
         p: TGLArrayf4;
         d: TGLArrayf3;
      begin
         ghDC := GetDC(Handle);
         if bSetupPixelFormat(ghDC)=false then
           Close();
         ghRC := wglCreateContext(ghDC);
         wglMakeCurrent(ghDC, ghRC);
         glClearColor(0.0, 0.0, 0.0, 0.0);
         FormResize(Sender);
         glEnable(GL_COLOR_MATERIAL);
         glEnable(GL_DEPTH_TEST);
         glEnable(GL_LIGHTING);
         glEnable(GL_LIGHT0);
           p[0]:=3;
           p[1]:=3;
           p[2]:=3;
           p[3]:=1;
           d[0]:=-1;
           d[1]:=-1;
           d[2]:=-3;
         glLightfv(GL_LIGHT0,GL_POSITION,@p);
         glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,@d);
      end;

Вы видите, что тут вызывается FromResize, который мы ещё не описали. Надо это исправить. Поместите туда следующий код:

С++, Delphi

  glViewport( 0, 0, Width, Height );
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho(-5,5, -5,5, 2,12);
  gluLookAt(0,0,5, 0,0,0, 0,1,0);
  glMatrixMode( GL_MODELVIEW );

Теперь, наверное, надо кое-что объяснить.

glClearColor устанавливает цвет (в нашем случае чёрный), которым будет заполняться экран при очищении. У этой процедуры - 4 параметра, что соответствует RGBA. Вместо нее можно написать glClearIndex(0.0). Эта процедура устанавливает индекс цвета в палитре.

glViewport устанавливает область вывода - область, в которую OpenGL будет выводить изображение. В нашем случае - вся форма.

glMatrixMode устанавливает режим матрицы видового преобразования. Не забивайте ей себе голову, просто запомните, что, если вы меняете тип проецирования, положение или направление камеры, то параметр должен быть GL_PROJECTION. После того, как вы завершили свои изменения, вызовите эту процедуру с параметром GL_MODELVIEW.

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

glOrtho устанавливает режим ортогонального (прямоугольного) проецирования. Это значит, что изображение будет рисоваться как в изометрии. 6 параметров типа GLdouble (или просто double): left, right, bottom, top, near, far определяют координаты соответственно левой, правой, нижней, верхней, ближней и дальней плоскостей отсечения, т.е. всё, что окажется за этими пределами, рисоваться не будет. На самом деле эта процедура просто устанавливает масштабы координатных осей. Для того чтобы установить перспективное проецирование, используются процедуры glFrustum и gluPerspective, но о них - потом.

gluLookAt устанавливает параметры камеры: первая тройка - её координаты, вторая - вектор направления, третья - направление оси Y.

В OpenGL всё включается и выключается (разрешается и запрещается) процедурами glEnable и glDisable. Таким образом, мы разрешили тест глубины (GL_DEPTH_TEST), чтобы изображение было объёмным, разрешили давать нашим объектам какой-то цвет (GL_COLOR_MATERIAL), разрешили освещение (GL_LIGHTING) и включили <лампочку №0> (GL_LIGHT0).

glLightfv устанавливает свойства <лампочек>: позицию и направление света.

После того, как вы завершили работу с OpenGL, нужно освободить занятые ресурсы: освободить контекст, вызвав wglMakeCurrent с параметром ноль для идентификатора контекста OpenGL и разрушить этот контекст функцией wglDeleteContext. Кроме того нужно удалить дескриптор ghDC. Так как обычно работу с OpenGL завершается при завершении работы приложения, то соответствующий код нужно поместить в FormClose:

С++

      void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction 
        &Action)
      {
        if(ghRC)
        {
          wglMakeCurrent(ghDC,0);
          wglDeleteContext(ghRC);
        }
        if(ghDC)
          ReleaseDC(Handle, ghDC);
      }

Delphi

      procedure TForm1.FormClose(Sender: TObject; var Action: 
        TCloseAction);
      begin
        if ghRC<>0 then
        begin
          wglMakeCurrent(ghDC,0);
          wglDeleteContext(ghRC);
        end;
        if ghDC<>0 then
          ReleaseDC(Handle, ghDC);
      end;

А теперь, давайте уже что-нибудь нарисуем!

Пример

Давайте нарисуем сферу, а потом заставим её крутиться. Итак, всё, что нам понадобится - это форма и таймер.

Установите интервал таймера на 10 миллисекунд (нам этого будет вполне достаточно). Теперь скопируйте все представленные выше фрагменты кода в соответствующие места. В процедуре Timer1Timer напишите одну сточку: Draw(); (в Delphi без скобок).

Теперь нам осталось только что-нибудь нарисовать, т.е. отредактировать функцию Draw.

С++

      void TForm1.Draw()
      {
        glClear(GL_DEPTH_BUFFER_BIT xor GL_COLOR_BUFFER_BIT);
        GLUquadricObj *quadObj;
        quadObj:=gluNewQuadric();
        gluQuadricDrawStyle(quadObj, GLU_FILL);
        glColor3f(1,0,0);
        gluSphere(quadObj, 2,10,10);
          glRotatef(3, 0,1,0);
        gluDeleteQuadric(quadObj);
        SwapBuffers(ghDC);
      }

Delphi

      procedure TForm1.Draw;
      var
        quadObj :GLUquadricObj;
      begin
        glClear(GL_DEPTH_BUFFER_BIT xor GL_COLOR_BUFFER_BIT);
        quadObj:=gluNewQuadric;
        gluQuadricDrawStyle(quadObj, GLU_FILL);
        glColor3f(1,0,0);
        gluSphere(quadObj, 2,10,10);
          glRotatef(3, 0,1,0);
        gluDeleteQuadric(quadObj);
        SwapBuffers(ghDC);
      end;

Всё, можно нажимать F9!!!

А теперь кое-что поясню (в процедуре Draw не встретилось ни одной знакомой строчки).

glClear сбрасывает значения всего перечисленного в качестве параметров (в нашем случае очищает буфер цвета и буфер глубины). Этой процедуре передавать много всяких буферов для очистки, но лично я использую только 3: GL_DEPTH_BUFFER_BIT, GL_COLOR_BUFFER_BIT, иногда GL_STENCIL_BUFFER_BIT (буфер трафарета).

glColor устанавливает цвет фигуры. Существует следующий синтаксис как для glColor, так и для других функций OpenGL:

gl<name>[n][type]

Поясняю, каждая функция OpenGL начинается с префикса . Далее следует название функции. После названия - количество параметров (если функция определена для разного кол-ва параметров). И, наконец, переменными какого типа являются параметры:

  • b - GLbyte байт
  • s - GLshort короткое целое
  • i - GLint целое
  • f - GLfloat дробное
  • d - GLdouble дробное с двойной точностью
  • ub - GLubyte беззнаковый байт
  • us - GLushort беззнаковое короткое целое
  • ui - GLuint беззнаковое целое
  • v - вектор - массив из n элементов указанного типа

Итак, glColor3f означает, что цвет задаётся тремя компонентами типа GLfloat.

Для рисования сферы мы используем механизм из glu32.dll. Создаём объект типа GLUquadricObj и инициализируем его функцией gluNewQuadric. Далее устанавливаем стиль фигуры функцией gluQuadricDrawStyle (quadObj, GLU_FILL). Стиль может быть GLU_FILL, GLU_LINE   или GLU_POINT. Что каждый из них значит, проверьте сами.

gluSphere - делает из quadObj сферу. Три последних параметра - это радиус и количество разбиений поперёк и вдоль оси Z соответственно. Я взял маленькое число разбиений, чтобы было видно, что сфера крутится.

И не забудем освободить память, занимаемую под quadObj - gluDeleteQuadric(quadObj).

glRotatef - заставляет нашу сферу крутиться. О том, как это делается - в следующей статье.

И, наконец, SwapBuffers (ghDC) выводит всё на экран.

Архив с проектом примера на Delphi

Пока всё.

Луковкин Сергей,
gluk-02@yandex.ru

Советую почитать:

  1. Тарасов И.А. <Основы программирования OpenGL: учебный курс>.
    Скачать её можно здесь: http://itsoft.miem.edu.ru/
  2. Тихомиров Ю. <Программирование трёхмерной графики>.
    Пишет мудрёно, но очень много полезной информации. Кстати, у него вышла вторая книга, может она ещё толковее и понятней?
  3. wat OpenGL: Основы http://www.gamedev.ru/coding/11203.shtml Просто, доступно, но для другой ИСР.
 
 


 

загрузка...

Новости ИТ
04.02.2012  LG начала продажи в Европе внешнего Blu-ray привода модели BP40NS20
04.02.2012  Pioneer в ближайшее время выпустит пишущий Blu-ray XL привод
04.02.2012  Acer начал продажи своего новейшего неттопа модели Revo RL70
04.02.2012  Четырехканальные наборы модулей памяти DDR3 Super Talent Quadra объемом по 4 ГБ рассчитаны на частоту 1866 МГц
04.02.2012  AMD рассказала о планах на 2012-2013 годы по части графических решений
04.02.2012  Габариты алюминиевого корпуса для ПК Xigmatek Gigas Micro-ATX Cube равны 278 x 396 x 322 мм
04.02.2012  На будущей неделе Tokina анонсирует стабилизированный объектив AT-X 70-200mm f/4 PRO IF FX
04.02.2012  СП Corning и Samsung Mobile Display будет выпускать стеклянные подложки для дисплеев OLED
03.02.2012  В Интернет попали неофициальное изображение и технические подробности предстоящего смартфона Samsung Galaxy S II Plus
03.02.2012  AMD сделала доступными попредзаказу три процессора линейки FX-Series
03.02.2012  ViewSonic начала продажи LED-монитора VX2336s-LED
03.02.2012  Orico X-Gear: дисковод для SATA-накопителей
03.02.2012  Оптический привод Pioneer BDR-S07J позволяет записывать диски BDXL
03.02.2012  Блок питания Super Flower мощностью 430 Вт имеет сертификат 80Plus Gold
03.02.2012  Начался прием заказов на процессоры AMD FX-4170 и FX-6200
03.02.2012  Монитор ViewSonic VX2336s-LED оснащён панелью SuperClear IPS со светодиодной подсветкой
03.02.2012  В накопителях Transcend SSD720 используются контроллеры SandForce последнего поколения
03.02.2012  Анонсирован зеркальный объектив Kenko 400mm f/8 для камер систем Micro Four Thirds и Sony NEX
03.02.2012  ASUS анонсировала пишущий DVD-привод DRW-24B5ST с поддержкой функции Disc Encryption II
03.02.2012  Zalman планирует уже в этом месяце начать продажи двух новейших геймерских Mid Tower-корпусов
03.02.2012  Packard Bell обновила свой 10,1-дюймовый нетбук модели Packard Bell dot s
03.02.2012  MSI показала 10-дюймовый нетбук Wind U180 на базе платформы Intel Cedar Trail
03.02.2012  Titan начала продажи оригинального CPU-кулера Siberia TTC-NC55TZ(RB)
03.02.2012  RunCore представила новейшие SSD-диски линейки Pro-V MAX
03.02.2012  Появились первые тесты инженерного образца 10-ядерного процессора Ivy Bridge-EP
03.02.2012  Внешние накопители Apricorn Aegis Padlock DT шифруют данные по алгоритму AES-XTS
03.02.2012  Системные платы подорожают еще до конца текущего квартала
03.02.2012  Камера COOLPIX S3300 доступна в восьми вариантах цветового оформления
03.02.2012  Verizon представит Droid 4
03.02.2012  Опубликован результат APU AMD Trinity A6 для ультратонких ноутбуков в тесте 3DMark

 
Advertisment

видеостудия

 
Интересное в сети

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.
 
Rambler's Top100