opengl widget qt что это
Описание Класса QGLWidget
[модуль QtOpenGL]
Класс QGLWidget виджета для вывода графики, реализующий функции библиотеки OpenGL. Далее.
Открытые Функции
Открытые Слоты
Статические Открыте Члены
Защищенные Функции
Дополнительные Унаследованные Члены
Подробное Описание
Класс QGLWidget виджета для вывода графики, реализующий функции библиотеки OpenGL.
QGLWidget обеспечивает вывод OpenGL графики, интегрированной в Qt приложения. Это довольно просто в использовании. Вы наследуете свой класс и используете его как любой другой QWidget, но для рисования используется не QPainter или другие классы, а стандартные комманды OpenGL.
QGLWidget предоставляет три виртуальные функции, польза которых состоит в том, что переопределяя их в своем классе можно легко добиться решения типичных задач:
Класс, наследник QGLWidget, может выглядеть так:
Виджет выводит в текущий контекст, когда вызываются paintGL(), resizeGL(), или initializeGL(). Если вам нужно вызвать стандартные OpenGL API функции из других мест, (таких как, конструктор класса виджета или в вашей собственной функции порисовки) то надо сперва вызвать makeCurrent() first.
QGLWidget содержит финкции для запроса нового формата вывода и вы можете создать виджет с контекстом вывода, отличным от созданного контекта «по умолчанию».
Вы также можете распределить дисплейные списки между QGLWidget виджетами (см. документацию по конструкторам QGLWidget).
Оверлеи
QGLWidget создает GL оверлейный контекст, как дполнение к нормальному, если оверлеи поддерживаются системой.
Если вы хотите использовать оверлеи, то это необходимо указать в формате. (Замечание: Оверлей должен быть запрошен форматом контекста в конструкторе QGLWidget). В наследнике класса должны быть переопределены следующие виртуальные функции (не обязательно все):
Эти методы работают также как и нормальные, paintGL() и др. функции, за исключением того, что они могут быть вызваны только тогда, когда уставлен оверлейный контекст текущим. Вы можете сделать оверлейный контекст текущим, используя makeOverlayCurrent(), и получить непосредственный доступ к контексту вызовом overlayContext().
На X сервере по умолчанию присутствует оверлей, в не-GL Qt окнах также могут использоваться оверлеи.
Описание Функций
QGLWidget::QGLWidget ( QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WFlags f = 0 )
Конструктор OpenGL виджета с указателем на родительский parent виджет.
Используется формат «по умолчанию». При создании виджета возвратится ошибка, если в системе нет поддержки OpenGL.
Родитель класса parent и переменная флагов, f, аргументы конструктора QWidget.
Если параметр shareWidget имеет тип QGLWidget, то этот виджет будет разделять дисплейные списки OpenGL с shareWidget. Если этот виджет и shareWidget различных форматов, списки могут быть не разделены. Но вы можете проверить успешность подключения разделяемых дисплейных списков вызовом isSharing().
Инициализация OpenGL режима прорисовки, и др. установки должны быть переопределены в initializeGL() функции, не рекомендуется делать установки в конструкторе QGLWidget вашего класса.
QGLWidget::QGLWidget ( QGLContext * context, QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WFlags f = 0 )
Конструктор OpenGL виджета с указателем на родительский parent виджет.
Переменная context указатель на QGLContext контекст для вышего OpenGL виджета. Вы можете указать собственный (пользовательский) QGLContext класс.
При создании виджета возвратится ошибка, если в системе нет поддержки OpenGL.
Родитель класса parent и переменная флагов, f, аргументы конструктора QWidget.
Если параметр shareWidget имеет тип QGLWidget, то этот виджет будет разделять дисплейные списки OpenGL с shareWidget. Если этот виджет и shareWidget различных форматов, списки могут быть не разделены. Но вы можете проверить успешность подключения разделяемых дисплейных списков вызовом isSharing().
Инициализация OpenGL режима прорисовки, и др. установки должны быть переопределены в initializeGL() функции, не рекомендуется делать установки в конструкторе QGLWidget вашего класса.
QGLWidget::QGLWidget ( const QGLFormat & format, QWidget * parent = 0, const QGLWidget * shareWidget = 0, Qt::WFlags f = 0 )
Конструктор OpenGL виджета с указателем на родительский parent виджет.
При создании виджета возвратится ошибка, если в системе нет поддержки OpenGL.
Родитель класса parent и переменная флагов, f, аргументы конструктора QWidget.
Если параметр shareWidget имеет тип QGLWidget, то этот виджет будет разделять дисплейные списки OpenGL с shareWidget. Если этот виджет и shareWidget различных форматов, списки могут быть не разделены. Но вы можете проверить успешность подключения разделяемых дисплейных списков вызовом isSharing().
Инициализация OpenGL режима прорисовки, и др. установки должны быть переопределены в initializeGL() функции, не рекомендуется делать установки в конструкторе QGLWidget вашего класса.
QGLWidget::
bool QGLWidget::autoBufferSwap () const [protected]
Возвращает true если виджет автоматически производит свопинг GL буфера; иначе возвращает false.
GLuint QGLWidget::bindTexture ( const QImage & image, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA8 )
Вызывается QGLContext. bindTexture(image, target, format) для текущего контекста.
GLuint QGLWidget::bindTexture ( const QPixmap & pixmap, GLenum target = GL_TEXTURE_2D, GLint format = GL_RGBA8 )
Эта перегруженная функция введена для удобства. Используется наравне с вышеприведенной функцией.
Вызывается QGLContext. bindTexture(pixmap, target, format) для текущего контекста.
GLuint QGLWidget::bindTexture ( const QString & fileName )
Эта перегруженная функция введена для удобства. Используется наравне с вышеприведенной функцией.
Вызывается QGLContext::bindTexture(fileName) для текущего контекста.
const QGLColormap & QGLWidget::colormap () const
Возвращает палитру для данного виджета.
Обычно это виджеты верхнего уровня, которые могут использовать различные палитры. Для потомков, функция возвратит палитру виджета верхнего уровня данного потомка.
Если палитра для виждета не установлена,QColormap то функция ничего не возвращает.
const QGLContext * QGLWidget::context () const
Вощает контекст данного виджета.
Возможны ситуации, когда контекст неверен (см. isValid()), например, система не поддерживает атрибуты формата, что сообщается при сождании контекста.
QImage QGLWidget::convertToGLFormat ( const QImage & img ) [static]
Переводит изобажениеimg в unnamed-формат необходимый для OpenGL фунуций таких как glTexImage2D(). Возвращаетe изображение не испоьзуемое какQImage, но QImage::width(), QImage::height() и QImage::bits() могут применяться для работы с OpenGL.
void QGLWidget::deleteTexture ( GLuint id )
Вызыватеся QGLContext::deleteTexture(id) для текущего контекста.
void QGLWidget::doneCurrent ()
Делает GL контекст текущеим. Обычно вам нет необходимости вызываит эту функцию; QGLContext вызывает при неоходимости. Однако, это может понадобиться в многопотоковых средах.
bool QGLWidget::doubleBuffer () const
Возвращает true, если вывод производится с использованием двойной буферизации; иначе возвращается false.
int QGLWidget::fontDisplayListBase ( const QFont & fnt, int listBase = 2000 ) [protected]
Возвращает индекс первого дисплейного списка, сгенерированного для шрифтаr fnt. listBase задает базовое значение для дисплейных списков шрифтов. Значение по умолчанию 2000.
QGLFormat QGLWidget::format () const
Возвращает формат контекста вывода GL.
void QGLWidget::glDraw () [virtual protected]
Производит вывод виртуальной функции paintGL().
Контекст вывода виджета становится текущим и initializeGL() будет вызвана в том случае, если до этого еще не была вызвана.
void QGLWidget::glInit () [virtual protected]
Иниуиализация OpenGL контекста для данного выдижета. Вызывается виртуальная функция initializeGL().
QImage QGLWidget::grabFrameBuffer ( bool withAlpha = false )
Возвращает изображение, снятое с переднего буфера. Если withAlpha true, то alpha канал включен.
В звисимости от вашего аппаратного обеспечения, вы можете выбрать цветовой буфер для снятия изображения с помощью glReadBuffer(), эту функцию надо вызвать заранее.
void QGLWidget::initializeGL () [virtual protected]
Эта виртуальная функция вызывается до первого вызова paintGL() или resizeGL(), и вызывется всякий раз, когда у виджета меняется контекст вывода QGLContext. Переопределяется в подклассе.
Она должна устанавливать флаги OpenGL контекста вывода, определять дисплейные списки, и т.д.
There is no need to call makeCurrent() because this has already been done when this function is called.
void QGLWidget::initializeOverlayGL () [virtual protected]
Виртуальная функция, аналог initializeGL() для операций с оверлейными контекстами. Вызывается initializeOverlayGL() один раз, перед первым вызывом paintOverlayGL() или resizeOverlayGL(). Переопределяется в подклассе.
Она должна устанавливать флаги OpenGL контекста вывода, определять дисплейные списки, и т.д. для оверлейного контекста.
bool QGLWidget::isSharing () const
Возвращает true, если контекст GL виджета используется наравне с другими контекстами данного виджета, иначе возвращает false. GL ситема может возвратить ошибку, если, например, два подключаемых контекста QGLWidgets имеют различные форматы.
bool QGLWidget::isValid () const
Возвращает true, если у виджета верный контекст вывода; иначе возвращает false. Функция возвращает false, когда например, формат виджета неверен, что может произойти при отсутствии в системе поддержки OpenGL.
void QGLWidget::makeCurrent ()
Делает этот виджет текущим для OpenGL операций, то есть контекст вывода виджета становится текущим OpenGL контекстом вывода.
void QGLWidget::makeOverlayCurrent ()
Делает оверлейный контекст данного виджета текущим. Используется, если вам необходимо подавать OpenGL команды в оверлейный контекст не из функций initializeOverlayGL(), resizeOverlayGL(), и paintOverlayGL().
Ничего не изменяет, если виджет не оверлейный.
const QGLContext * QGLWidget::overlayContext () const
Возвращает оверлейный контекст данного виджета, или 0 если виджет не имеет оверлеев.
void QGLWidget::paintEvent ( QPaintEvent * event ) [virtual protected]
Указатель на событие находтся в event параметре. Причиной может явиться вызов виртуальной функции paintGL().
Контекст вывода виджета становится текущим контекстом и initializeGL() будет вызвана, если до этого она еще не была вызвана.
void QGLWidget::paintGL () [virtual protected]
Эта виртуальная функция вызывается, когда виджет нуждается в перерисовке. Переопределяется в подклассе.
Не нужно вызывать функцию makeCurrent(), потому что она вызывается автоматически.
void QGLWidget::paintOverlayGL () [virtual protected]
Виртуальная функция, аналог paintGL() для операций с оверлейными контекстами. Функция paintOverlayGL() будет вызвана, когда виджету необходима перерисовка. Переопределяется в подклассе.
Не нужно вызывать функцию makeOverlayCurrent(), потому что она вызывается автоматически.
void QGLWidget::qglClearColor ( const QColor & c ) const
Устанавливает цвет заполнения в режиме OpenGL. Вызывается glClearColor (в RGBA режиме) или glClearIndex (в режиме цветовых индексов) с аргументом цвета c. Применяется для текущего контекста GL.
void QGLWidget::qglColor ( const QColor & c ) const
Устанавливает цвет рисования в режиме OpenGL. Вызывается glColor4 (в RGBA режиме) или glIndex (в режиме цветовых индексов) с аргументом цвета c. Применяется для текущего контекста GL.
QPixmap QGLWidget::renderPixmap ( int w = 0, int h = 0, bool useContext = false )
Выводит текущую сцену на изображение и возвращает его.
Вы можете использовать в обоих режимах: видимом и невидимом QGLWidgets.
Данная функция создает изображене и временный QGLContext для вывода. Также вызываются initializeGL(), resizeGL(), и paintGL() для контекста. И в конце предыдущий контекст вывода восстанавливается.
Размер изображения w пикселей ширины и h пикселей высоты, если один из этих параметров не установлен, то используется размер виджета.
Есди useContext установлен в true, то функция пытается использовать существующий контекст вывода для создания изображения. По умолчанию параметр равен false. Вы можете использовать значение true, если осознаете сопряженный c этим риск.
Оверлеи не могут быть выведены в изображение.
Если контекст вывода GL и изобрадения имеют различную глубину, то результат может явиться для вас сюриризом.
Замечание: создание дисплейных спсков, модификация проекции ит.д. должны быть осуществлены внутри initializeGL(). Если этого не сделать, то полученный контекст QGLContext будет не иницализоанным должным образом, и в результате изображение модет быть незаконченным/поврежденным.
void QGLWidget::renderText ( int x, int y, const QString & str, const QFont & fnt = QFont(), int listBase = 2000 )
Вывод строки str в GL контекст данного виджета.
x и y определяют координаты окна, относительно левого верхнего угла окна. Если fnt не задан, то будет использован текущий шрифт приложения. Для изменения цвета текстя можно воспользоваться glColor() (или the qglColor() функцией-аналогом ), до вывода текста renderText(). Замечание; при использовании режима освещения (константа GL_LIGHTING), строка будет цветом отличаться от заданного выми. Для избежания этого, необходимо выключить освещение перед вызовом renderText().
listBase определяет индекс первого дисплейного списка, генерируемого функцией. Значение по умолчанию 2000. 256 может быть создано, один для каждого из 256 символов вывводимой строки. Если некоторые из шрифтов использовались другим виджетом, то ранее созданный список будет продолжен. You would normally not have to change this value unless you are using lists in the same range. Списки уничтожаются вместе с виджетом.
void QGLWidget::renderText ( double x, double y, double z, const QString & str, const QFont & fnt = QFont(), int listBase = 2000 )
Эта перегруженная функция введена для удобства. Используется наравне с вышеприведенной функцией.
x, y и z определяют координаты в сцене или объекте, в соответствии с текущими проекцией и модельными матрицами. Можно использовать для сопровождения модели текстовой меткой, которая будет подвержена трансформациям и ротациям вместе с моделью.
void QGLWidget::resizeEvent ( QResizeEvent * event ) [virtual protected]
Указатель на событие находтся в event параметре. Вызывает виртуальную функцию resizeGL().
void QGLWidget::resizeGL ( int width, int height ) [virtual protected]
Виртуальная функция, вызываемая когда виджету требуется изменить размер. Новый размер указан в width и height. Переопределяется в подклассе.
Не нуждается в вызове makeCurrent().
void QGLWidget::resizeOverlayGL ( int width, int height ) [virtual protected]
Виртуальная функция, аналог resizeGL() для операций с оверлейными контекстами.
Вызывается когда виджету требуется изменить размер. Новый размер указан в width и height. Переопределяется в подклассе.
void QGLWidget::setAutoBufferSwap ( bool on ) [protected]
Если on установлен в true, то автоматический свопинг GL буфера включен; иначе выключен.
Если on установлен в true и виджет использует двойную буферизацию, то с задним и передним буферами происходит автоматический свопинг после каждого вызова paintGL().
Авто-свопинг включен по умолчанию.
void QGLWidget::setColormap ( const QGLColormap & cmap )
Установка палитры cmap для данного виджета. Обычно, это виджеты верхнего уровня.
void QGLWidget::setMouseTracking ( bool enable )
Если enable установлен в true, то включено отслеживание мыши; иначе отслеживание мыши выключено.
void QGLWidget::swapBuffers ()
Производит свопинг во внеэкранный буфер. Работает в случае установки в формате режима двойной буферизации.
Обычно, функция не нуждается в явном вызове, так как она вызывается автоматически после каждого обновления виджета, то есть каждый раз после вызова paintGL().
void QGLWidget::updateGL () [virtual slot]
Обновляет виджет, вызывая функцию glDraw().
void QGLWidget::updateOverlayGL () [virtual slot]
Обновляет оверлеи виджета. Причиной может явиться вызов виртуальной функции paintOverlayGL().
Контекст вывода виджета становится текущим контекстом и initializeGL() будет вызвана, если до этого она еще не была вызвана.
OpenGL на Qt 4. Это просто! (часть 1) (2 стр)
Библиотека Qt 4 имеет специальный модуль для работы с OpenGL — QtOpenGL. Модуль QtOpenGL реализован как платформонезависимая Qt/C++ надстройка (стандартизация внешних обращений) над платформозависимыми GLX (OpenGL в Linux), WGL (OpenGL в Windows) или AGL (OpenGL в MacOS) API. Функциональность модуля QtOpenGL очень схожа с библиотекой GLUT, но при этом вам предоставляются все возможности Qt, которые несвязаны с OpenGL. В модуле QtOpenGL в версии Qt 4.7.1 определены следующие классы: QGLBuffer, QGLColormap, QGLContext, QGLFormat, QGLFramebufferObject, QGLFramebufferObjectFormat, QGLPixelBuffer, QGLShader, QGLShaderProgram, QGLWidget, QWSGLWindowSurface.
Классы подключаются стандартным образом:
Класс QGLWidget
Рассмотрим класс QGLWidget вместе с наиболее важными функциями-членами и слотами-членами этого класса.
Функции-члены класса (protected):
Слот-член класса (public):
Выполнение функций происходит автоматически по следующей схеме:
Знак вопроса (?) на схеме условно означает, что в этих местах проверяется, нужно ли сейчас вызвать эти функции или нет. Более полную и подробную информацию о классе QGLWidget можно найти в справке Qt Assistant, который всегда поставляется с Qt, а ещё более подробно смотрите в исходных текстах Qt.
Аргументом конструктора класса является указатель на объект класса QWidget. Класс QWidget обеспечивает работу с виджетами (интерфейсными элементами окна), а класс QGLWidget унаследован от QWidget и осуществляет связь виджетов и OpenGL. Запись QWidget *parent=0 означает, что виджет parent по умолчанию будет как бы «главным» окном (или точнее, окном-объектом верхнего уровня в иерархии объектов). Пример:
Класс виджета, который будет работать с OpenGL, должен наследоваться от класса QGLWidget. Мы назвали этот класс Scene3D. Объектом класса Scene3D будет виджет, в котором будет рисоваться трёхмерная сцена. Конструктор класса Scene3D сначала вызовит конструктор класса QGLWidget, который в свою очередь вызовит конструктор класса QWidget.
В Qt имеет место так называемая иерархия объектов (класса QObject или его классов-наследников), когда связь между объектами образует древовидную структуру (условно сверху вниз). Эту структуру называют деревом объектов. На вершине иерархии находится объект, от которого идёт вниз связь с другими объектами. Объект на вершине иерархии объектов называется объектом верхнего уровня. Он, являясь (как бы) объектом-родителем, связан с нижележащими объектами, которые являются для него (как бы) объектами-потомками. Эти объекты-потомки могут быть объектами-родителями для следующих нижележащих объектов и т.д. В Qt при уничтожении объекта-родителя все его объекты-потомки уничтожаются автоматически. Такая связь эффективна для управления памятью, когда достаточно удалить только верхний в иерархии объект и все связанные с ним нижележащие объекты удалятся автоматически. Здесь важно заметить, что объекты-потомки должны создаваться динамически (через new), иначе может произойти ошибка, связанная с вызовами деструктров. Тогда как использование динамических объектов-потомков исключает эту возможную ошибку. Как правило, объект верхнего уровня создаётся нединамически (в стеке): обычно это виджет окна или виджет главного окна. Остальные GUI-объекты создаются динамически как объекты-потомки этого главного виджета (объекта верхнего уровня). Когда объект верхнего уровня выйдет за область видимости, то всё дерево объектов удалится из памяти. В этом и заключается вся прелесть работы с деревом объектов — не нужно держать в голове динамические объекты GUI и удалять их через delete в деструкторе. В этой части статьи мы не будем создавать дерево объектов и отложим это до второй части. Здесь в обобщающей программе наш объект класса Scene3D будет объектом верхнего уровня. В конечном итоге в конструктор класса QWidget передастся значение 0, что и будет означать, что наш объект класса Scene3D является объектом верхнего уровня в иерархии объектов.
В конструкторе Scene3D() нужно задать начальные значения, не являющиеся как таковыми командами OpenGL, например, углы поворотов при наблюдении сцены. Определять деструктор в данном случае необязательно; деструктор по умолчанию сам создастся компилятором. Функции initializeGL(), resizeGL(), paintGL() являются виртуальными функциями (динамический полиморфизм в C++). Следовательно, в классе-наследнике Scene3D обозначать функции как virtual не нужно. Эти три функции изначально имеют полностью пустое тело, которое нужно заполнить командами OpenGL. Здесь нужно отметить, что функции glDraw() и glInit() принадлежат классу QGLWidget, а не к OpenGL (как можно было бы подумать из префикса gl). Функции glDraw() и glInit() не нужны для пользовательской работы; они просто вызывают initializeGL(), resizeGL(), paintGL(), о которых и пойдёт речь далее. Как раз только эти три функци и используются для пользовательской работы с OpenGL: при инициализации настроек рендеринга, при изменении размера окна виджета и при рисовании.
Инициализация контекста рендеринга
Функция initializeGL() вызывается только один раз после создания виджета. Судя по названию, в теле этой функции вы можете провести какую-либо инициализацию, т.е. установить некоторые начальные значения — речь идёт о контексте рендеринга OpenGL. Разумеется, инициализацию настроек рендеринга можно провести где-то в другом месте, но разумнее задать контекст рендеринга именно в этой функции — для этого эта функция и была создана. И, конечно же, можно изменять настройки (рендеринга) в теле трёх названных выше функций. Пример:
Вы можете так же дополнительно вызывать initializeGL() в случае необходимости с помощью glInit() класса QGLWidget (префикс gl добавлен для удобства, но это не функция OpenGL). Обратим внимание на первую команду qglClearColor(Qt::white), которая принадлежит классу QGLWidget. В OpenGL она эквивалентна glClearColor(1.0f, 1.0f, 1.0f, 1.0f), которая устанавливает цвет RGBA для очистки окна. Конечно же, вместо qglClearColor(Qt::white) можно использовать glClearColor(1.0f, 1.0f, 1.0f, 1.0f), и выбор определяется удобством и остаётся за вами. Аргументом функции qglClearColor() является значение типа QColor. Это также встроенный класс Qt, как можно догадаться из приставки Q. Особенность его в том, что он соответствует цветам в OS Windows от 0 до 255. Пример:
В соответствии с правилами обозначения в OpenGL значение 1.0f обрабатывается как тип GLfloat (собственный тип OpenGL). Зачем нужны собственные типы? Дело в том, что различные компиляторы и платформы по-разному распределяют память под стандартные типы и программист должен всегда это держать в уме. Собственные типы OpenGL обрабатываются везде одинаково и освобождают нас от этого обременительного занятия.
Следующая функция glEnable(GL_DEPTH_TEST) является уже функцией OpenGL, что можно понять из приставки gl в отличие от qgl для первой функции. Функция glEnable(GL_DEPTH_TEST) устанавливает режим проверки глубины пикселей объектов (например, для двух последовательно рисующихся треугольников). Зачем это нужно? Дело в том, что одни объекты могут быть ближе к нам (наблюдателям), а другие дальше, а значит, ближние объекты могут закрывать собой дальние. OpenGL никак не проверяет, какой объект ближе, а какой дальше, он просто последовательно рисует объекты. Если последовательно рисуются: объект1, объект2, то даже если объект2 дальше от наблюдателя, он все равно будет закрывать собой объект1, потому что объект2 нарисовался последним. Но как объяснить OpenGL, какой объект ближе, а какой дальше? На помощь нам приходит технология отсечения скрытых (невидимых) поверхностей (т.е. удаление «закрытых» пикселей объектов) с помощью буфера глубины, известного также как z-буфер. Суть этой технологии состоит в том, что каждому пикселю объекта (например, треугольника) на экране с координатами x и y даётся еще координата z, называемая глубиной и характеризующая расстояние до наблюдателя. Если сохранить глубину пикселей объекта1 в буфер глубины и потом сравнить с глубиной пикселей объекта2, то можно определить, какие пиксели объектов видны на экране, а какие скрыты. Например, рассмотрим такую ситуацию: последовательно рисуются два треугольника. Когда обрабатывается первый треугольник, то значения глубины его пикселей сохраняются в буфер глубины. Затем когда обрабатывается второй треугольник, то глубина уже его пикселей сравнивается со значениями в буфере глубины, и те пиксели, которые ближе к нам, замещают те, которые дальше. Команда glEnable(GL_DEPTH_TEST) включает такой режим, при котором проводится сравнение глубины пикселей объектов с глубиной, хранящейся в буфере глубины. Также нужно будет сообщить системе об использовании буфера глубины, т.е. нужно подключить сам буфер глубины. Qt автоматически в конструкторе класса QGLWidget по умолчанию задаст такой формат в контекст, т.е. использовать (подключить) буфер глубины. Поэтому буфер глубины можно явно и не подключать, он подключится сам. Использование буфера глубины и сравнение глубины являются эффективным способом удаления (отсечения) невидимых поверхностей.
Закомментированная функция glShadeModel(GL_FLAT) отключает режим сглаживания цвета, который всегда установлен по умолчанию. При включенном режиме сглаживания цвета, если вершины имеют разный цвет, то цвет между ними будет плавно переходить из одного в другой. Отключать режим сглаживания нет необходимости, поэтому функция закомментирована и не используется.
OpenGL использует следующие простые геометрические построения (их называют примитивами): точка, линия, треугольник (чаще всего), четырёхугольник, многоугольник (реже всего). Например, когда рисуется треугольник, рисуются его внешняя и внутренняя поверхности. Но часто бывает так, что внутренние поверхности рисовать ненужно, так как мы их никогда не увидим. Для этого используется команда glEnable(GL_CULL_FACE) и в результате её исполнения рисуются только внешние поверхности. Как можно догадаться, это повышает быстродействие рисования, так как теперь не нужно обрабатывать нелицевые поверхности (или наоборот, лицевые в зависимости от установленных настроек). Какая поверхность внешняя, а какая внутренняя определяется с помощью последовательности её вершин — закручивание по правилу правого винта (обход вершин по часовой стрелке — вектор нормали направлен от вас; против часовой стрелки — вектор нормали на вас).
Настройки окна виджета
Рассмотрим следующую функцию resizeGL(), определенную в Qt. Эта функция вызывается первый раз после initializeGL() и каждый раз автоматически, когда происходит изменение размера окна. Как вы догадываетесь параметры width и height типа int и есть ширина и высота окна виджета в пикселях, которые отсчитывается от самой верхней левой точки виджета. Эти параметры передаются в функцию resizeGL() автоматически при её вызове. В теле этой функции требуется задавать настройки, связанные с размером виджета, а именно определить командами OpenGL поле просмотра, мировое окно и вид проекции. Пример:
Изображение на экране зависит от матрицы проекции и матрицы моделирования (и ещё поля, или порта, просмотра). Данные преобразуются с помощью этих матриц (фактически умножаются на матрицы).
Последовательные команды glMatrixMode(GL_PROJECTION) и glLoadIdentity() загружают единичную матрицу в матрицу проекции. Параметром glMatrixMode() является матрица, над которой будут совершаться все последующие преобразования. Команда glMatrixMode(GL_PROJECTION) как раз означает, что текущей матрицей для преобразований станет матрица проекции. Для матрицы проекции таковыми преобразованиями являются установление видимого объёма и типа проекции. Необходимо знать, что любые преобразования с матрицами не сбрасываются, а аддитивно накапливаются. Поэтому необходимо каждый раз возвращать первоначальные матрицы, в которых не произведено никаких преобразований. С этой цель единичная матрица и загружается в текущую матрицу (проекции), т.к. единичная матрица соответствует матрице без преобразований. Если не отменять преобразования, то следующее преобразование будет совершаться уже относительно предыдущего.
Команда glOrtho() означает, что проекция является ортогональной (также ортографической), в отличие от перспективной проекции, задающейся командой glFrustum(). В перспективной проекции чем дальше объекты находятся от наблюдателя, тем они рисуются меньше, а в ортогональной нет эффекта удаления. Аргументами функции glOrtho() являются плоскости отсечения: левая, правая, верхняя, нижняя, передняя, задняя. Для функции glFrustum() плоскости отсечения: левая, правая, верхняя, нижняя, ближняя, дальняя; при этом наблюдатель находится в точке (0, 0, 0) и расстояния до ближней и дальней плоскостей должно быть положительным. Плоскости отсечения обрезают сцену, и всё, что находится за плоскостями отсечения, рисоваться не будет. Обратите внимание, что аргументы функции обозначены не 10.0f, а просто 10.0. По умолчанию такие значения относятся к GLdouble.
Функция glViewport(0, 0, (GLint)nWidth, (GLint)nHeight) определяет поле просмотра (порт просмотра) внутри окна в пикселях экрана и образует прямоугольник с левой нижней точкой (0, 0) и правой верхней точкой (nWidth, nHeight). В этом поле и будет всё рисоваться. Для нас важно, что прямоугольник поля просмотра совпадает с прямоугольником виджета окна. Так как nWidth и nHeight типа int, стоит произвести преобразования к типам GLint.
Часто начинающие программисты, задавшие первоначальные одинаковые значения ширины и высоты, недоумевают, почему их изображение растягивается по ширине при развертывании окна на весь экран. Ничего удивительного в этом нет — ширина становится больше по значению, чем высота. И OpenGL автоматически масштабирует всю проекцию сцены так, что она становится вытянутой по координате x экрана. Чуть позже в заключительном листинге обобщающей программы будет показано, как этого избежать и «сохранить квадрат квадратным». Также необходимо помнить, что отсчёт координаты y на экране производиться по-разному: из самой нижней точки вверх в OpenGL и из самой верхней точки вниз в экранных координатах в виджете.
Построение изображения в OpenGL происходит по следующему принципу: (мировые координаты)—>(мировое окно)—>(поле просмотра).
Вывод изображения
Следующая рассматриваемая функция Qt, paintGL(), вызывает рисование сцены и выполняется первый раз после resizeGL() и каждый раз после функции вызова updateGL(). Пример:
Первая закомментированная команда glClear(GL_COLOR_BUFFER_BIT) очищает окно цветом RGBA, который выбран командами qglClearColor(Qt::white) или glClearColor(1.0f, 1.0f, 1.0f, 1.0f) (в данном случае белый цвет). Если в инициализации initializeGL() установлена проверка глубины glEnable(GL_DEPTH_TEST), то можно очистить буфер цвета и глубины вместе glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT).
Команда glMatrixMode(GL_MODELVIEW) делает матрицу моделирования (имеются также переводы модельно-видовая матрица) текущей для последующих преобразований. Далее glLoadIdentity() загружает единичную матрицу в матрицу моделирования, аналогично как это говорилось выше о матрице проекции. Матрица моделирования отвечает за наблюдение сцены; а матрица проекции за проецирование сцены, которое может быть либо ортогональным, либо перспективным.
Далее приведены последовательные преобразования над матрицей моделирования (фактически над матрицей наблюдения): поворот, трансляция, масштабирование. Значения (GLfloat) xRot, yRot, zRot, xTra, yTra, zTra, xSca, ySca, zSca удобно определить как private данные-члены класса и задать им начальные значения в теле конструктора класса. Как вы догадались, это углы поворота вокруг трёх осей, величины трансляции и масштабирования. Особенность углов поворота в том, что они задаются в градусах, а не в радианах. Функция glRotatef() осуществляет поворот наблюдателя на заданный угол вокруг заданной оси. Соответственно, функции glTranslatef() и glScalef() производят трансляцию сцены и масштабирование. Важно напомнить ещё раз, что любое преобразование изменяет текущие матрицы. И следующее преобразование осуществляется относительно предыдущего. Поэтому операции (поворот—>трансляция) и (трансляция—>поворот) приводят к разным результатам; операции (поворот1—>поворот2) и (поворот2—>поворот1) также могут привести к разным конечным преобразованиям. Все эти преобразования в итоге изменяют матрицу моделирования от единичной. Именно поэтому необходимо при перерисовании сцены загружать единичную матрицу, после чего будут осуществляться указанные преобразования над ней. К тому же вы можете загружать матрицы, сделанные «своими руками».
По умолчанию (когда углы поворотов xRot, yRot, zRot равны нулю) ось y будет направлена вверх в плоскости экрана, ось x вправо в плоскости экрана, а ось z будет перпендикулярна экрану и направлена из него на вас. Оси образуют правую тройку векторов, как и должно быть в стандартной математике. Центр системы координат будет расположен в центре экрана. Эта система координат показывает мировые координаты, которыми задаются трёхмерные объекты в программе.
Нашу последнюю функцию example_drawAxis() можно определить как функцию-член класса. example_drawAxis() для примера создаёт оси координат из примитивов-линий с помощью команд glBegin(GL_LINES) и glEnd(). Аргументом glBegin() является тип примитива, а в теле задаются вершины с помощью glVertex3f().
Особенность библиотеки OpenGL в том, что она работает как машина с настройками (машина состояний, или конечный автомат). Если была установлена некоторая настройка, то она становится текущей и будет выполняться до тех пор, пока не будет изменена. Наглядный пример: команда glColor4f(), которая устанавливает текущий цвет RGBA. Обратите внимание, что совместно использована функция qglColor(). То же самое относится и к командам glEnable() для включения и glDisable() для выключения настроек.
Представление примитивов с помощью команд glBegin() и glEnd() является очень наглядным и простым для понимания, тем не менее, недостаточно эффективным по быстродействию. Поэтому для повышения быстродействия в случаях статической геометрии их часто помещают в дисплейные списки (display lists, имеются также переводы: списки отображения, списки изображения, таблицы отображения). Ещё большей эффективности можно добиться, используя массивы вершин, массивы индексов вершин, массивы цветов вершин и т.д. Этот метод применим также в случае динамической геометрии. Пример использования массивов будет продемонстрирован в заключительном обобщающем листинге программы.