ПрограммированиеСтатьиГрафика

OpenGL: Основы.

Автор:

OpenGL является одним из ведущих и популярных графических API, разработанный SGI. OpenGL разрабатывался как многоплатформенный, открытый и быстрый графический API. Многие графические пакеты используют OpenGL для вывода трёхмерной графики. Многие известные игры, такие как Quake, Serious Sam и наш отечественный ИЛ-2 Штурмовик, также написаны под OpenGL.

Введение
Инициализация
Типы в OpenGL
Функции OpenGL
Дополнительные сведения об OpenGL
Дополнительные библиотеки
  OpenGL Utility Library (glu)
  OpenGL Auxiliary Library (glaux)
  OpenGL Utility Toolkit (GLUT)
Вывод кадра
  Графические примитивы
  Вершины
  Вывод примитивов последовательностью вершинных функций
  Вывод примитивов, используя массивы
  Индексные примитивы

Введение

Почти все современные графические акселераторы могут аппаратно поддерживать OpenGL, что позволяет выводить графику в реальном времени.

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

OpenGL представляет собой набор функций, при помощи которых можно выводить 2-х и 3-х мерные графические примитивы, управлять ими, их свойствами, способами вывода и пр.

Заголовочные файлы, которые могут понадобиться для работы с OpenGL, обычно находятся в папке GL, расположенной в стандартной папке Include.

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

#include <GL/gl.h>

Кроме того, линковщику нужно указать статические библиотеки, с внешними функциями. Например, для функций, объявленных в gl.h, необходимо добавить в проект opengl32.lib.

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

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

Существует несколько функций по работе с OpenGL, которые представляет Windows API.

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

Обычно в трёхмерных играх каждый видимый кадр строится заново. То есть, в каждом кадре полностью перерисовывается вся видимая графика. Построение кадра может происходить следующим образом. Сначала весь кадр очищается, а потом последовательно выводятся трёхмерные графические объекты. Такое действие происходит несколько раз в секунду. Количество этих перерисовок в секунду называют FPS (frames per second).

Понятно, что если мы будем стирать и рисовать в видимой части экрана, то мы будем видеть мигание и мерцание наших рисующихся и стирающихся объектов.

Чтобы не было этого неприятного эффекта, пользуются следующим способом. Весь кадр полностью строят в невидимой части видеопамяти адаптера. Эту часть называют Back Buffer. После того, как все графические объекты выведены, вся эта невидимая часть копируется в видимую область видеопамяти, называемую Front Buffer. Если ваше приложение выводит графику на весь экран, а не в окно, то можно избежать копирования буфера, переключая указатель на видимую часть в видео памяти. Такой эффект называют Flip. Видно, что он работает быстрее, чем копирование буфера.

Мы будем строить пример оконного приложения.

Окно, в котором будет выводиться графика под OpenGL должно иметь два дополнительных стиля WS_CLIPSIBLINGS и WS_CLIPCHILDREN. Эти стили можно установить либо во время создания окна в функции CreateWindow(), либо функцией из Windows API - SetWindowLong(), если окно уже создано.

Согласно нашему примеру, для того чтобы установить эти стили, нами созданную функцию CreateMainWindow() необходимо вызвать с true в параметре bIsOpenGL.

Для устройства контекста окна необходимо выставить описатель пиксельного формата.

Это можно сделать при помощи объекта структуры PIXELFORMATDESCRIPTOR. Тут вы указываете, например, сколько бит необходимо выделить под каждое значение цвета, под буфер глубины и т.д.

Рассмотрим функции, работающие с PIXELFORMATDESCRIPTOR.

На самом деле, вы не всегда можете установить точно все параметры PIXELFORMATDESCRIPTOR для текущего режима по вашему желанию. Другими словами, вы можете рекомендовать те или иные параметры, система, выберет наиболее подходящий формат по вашим пожеланиям.

Итак, сначала создадим объект типа PIXELFORMATDESCRIPTOR, полностью заполненный нулевыми значениями.

PIXELFORMATDESCRIPTOR pfd = {0};

Для работы с этим объектов всегда нужно выставлять поля nSize значением равным размеру всей структуры и nVersion (версия) - со значением равным 1.

Также необходимо выставить требуемые флаги в dwFlags. Поскольку мы собираемся выводить графические объекты в окно, то нужно выставить флаг PFD_DRAW_TO_WINDOW. Далее, говорим, что буфер кадра поддерживает вывод через OpenGL - PFD_SUPPORT_OPENGL, и, так как мы используем два буфера (Back и Front), устанавливаем флаг PFD_DOUBLEBUFFER. Итак:

pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;

В поле iPixelType выставим PFD_TYPE_RGBA. Это означает, что цвет для пикселя представляется в виде RGBA (цветовые компоненты: R - красный, G - зелёный, B - голубой и A - альфа). Кроме этого бывает ещё индексное представление, которое мы не будем рассматривать вообще.

Дальше выставляем желаемые параметры. Например: глубину цвета (cColorBits) - 32 бит.

Заполнив все необходимы поля, мы делаем запрос на выбор самого подходящего формата. Это делается функцией ChoosePixelFormat(). Эта функция либо возвращает подобранный для указанного контекста устройства индекс формата, либо возвращает ноль.

Если формат был успешно подобран, нужно его выставить функцией SetPixelFormat().

Чтобы узнать, какие именно значения устанавливаются для формата, то есть получить описание полей структуры PIXELFORMATDESCRIPTOR, пользуются функцией DescribePixelFormat()

Итак, построим функцию, инициализирующую пиксельный формат для устройства контекста:

int InitPixelFormat(HDC hdc)
{
  int pixelformat;
  PIXELFORMATDESCRIPTOR pfd = {0};

  pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 32;

  if (!(pixelformat = ChoosePixelFormat(hdc, &pfd)))
  {
    //Error: ChoosePixelFormat failed
    return 0;
  }

  if(!SetPixelFormat(hdc, pixelformat, &pfd))
  {
    //Error: SetPixelFormat failed"
    return 0;
  }

  return 1;
}

Если удалось установить пиксельный формат, то теперь нужно создать просчитывающий контекст (rendering context) OpenGL. Это делается вызовом функции wglCreateContext(). Далее, созданный контекст выставляется текущим функцией wglMakeCurrent().

Теперь вы можете пользоваться функциями OpenGL.

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

Итак, мы теперь можем построить код, позволяющий работать нам с OpenGL:

Файл OpenGL.h

// OpenGL.h
// Объявление внешних функций

#ifndef _OpenGL_h_
#define _OpenGL_h_

int InitOpenGL(HWND hWnd);
void ReleaseOpenGL();

#endif //_OpenGL_h_

Файл OpenGL.cpp

// OpenGL.cpp
// http://www.gamedev.ru

// Урок: http://www.gamedev.ru/code/articles/?id=4268
// Автор: Sergey Watkin

#include <windows.h>
#include <GL/gl.h>

#include "OpenGL.h"

int InitPixelFormat(HDC hdc);
void InitSettings();

namespace{
  HWND hWnd;
  HDC   hDC;
  HGLRC hRC;
}

int InitOpenGL(HWND _hWnd)
{
  hWnd = _hWnd;
  hDC = GetDC(hWnd);
  if(!InitPixelFormat(hDC))
    return 0;

  hRC = wglCreateContext(hDC);
  wglMakeCurrent(hDC, hRC);

  InitSettings();
  return 1;
}

void InitSettings()
{
}

void ReleaseOpenGL()
{
  if(hRC)
  {
    wglMakeCurrent(hDC, 0);
    wglDeleteContext(hRC);
    hRC = 0;
  }
  if(hDC)
  {
    ReleaseDC(hWnd, hDC);
    hDC = 0;
  }
}

int InitPixelFormat(HDC hdc)
{
  int pixelformat;
  PIXELFORMATDESCRIPTOR pfd = {0};

  pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 32;

  if (!(pixelformat = ChoosePixelFormat(hdc, &pfd)))
  {
    //Error: ChoosePixelFormat failed
    return 0;
  }

  if(!SetPixelFormat(hdc, pixelformat, &pfd))
  {
    //Error: SetPixelFormat failed"
    return 0;
  }

  return 1;
}

Кроме того, если вы пользуетесь кодом для своего приложения, описанным здесь, то не забудьте добавить в него:

В начале:

#include "OpenGL.h"

Функцию CreateMainWindow() вызвать с true для параметра bIsOpenGL.

В функции Init() вызвать:

InitOpenGL(hWndMain);

А в функции ReleaseAll() вызвать:

ReleaseOpenGL();

Страницы: 1 2 3 Следующая »

#OpenGL, #основы

16 февраля 2002 (Обновление: 14 июня 2011)

Комментарии [92]