Opengl примеры интересных программ


OpenGL: Основы.

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

Введение

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

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

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

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

Объявление стандартных функций OpenGL находится в файле gl.h, поэтому ваш файл исходного кода, содержащий функции OpenGL, должен включать 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, полностью заполненный нулевыми значениями.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Приложение

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

Стандартные геометрические примитивы

Рассмотрим стандартные команды построения примитивов, которые реализованы в библиотеках GLU и GLUT.

Как уже было сказано, чтобы построить примитив из библиотеки GLU, надо сначала создать указатель на quadric- объект с помощью команды gluNewQuadric(), а затем вызвать одну из команд gluSphere(), gluCylinder(), gluDisk(), gluPartialDisk(). Рассмотрим эти команды отдельно:

void gluSphere(GLUquadricObj*qobj, GLdouble radius, GLint slices, GLint stacks)

Строит сферу с центром в начале координат и радиусом radius. При этом число разбиений сферы вокруг оси z задается параметром slices, а вдоль оси z параметром stacks.

void gluCylinder(GLUquadricObj*qobj, GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks)

Строит цилиндр без оснований (то есть кольцо), продольная ось параллельна оси z, заднее основание имеет радиус baseRadius, и расположено в плоскости z=0, переднее основание имеет радиус topRadius и расположено в плоскости z=height. Если задать один из радиусов равным нулю, то будет построен конус.

Параметры slices и stacks имеют тот же смысл, что и в предыдущей команде.

void gluDisk(GLUquadricObj*qobj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops)

Строит плоский диск (то есть круг) с центром в начале координат и радиусом outerRadius. При этом если значение innerRadius ненулевое, то в центре диска будет находиться отверстие радиусом innerRadius. Параметр slices задает число разбиений диска вокруг оси z, а параметр loops -число концентрических колец, перпендикулярных оси z.

void gluPartialDisk(GLUquadricObj *qobj, GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops, GLdouble startAngle, GLdouble sweepAngle);

Отличие этой команды от предыдущей заключается в том, что она строит сектор круга, начальный и конечный углы которого отсчитываются против часовой стрелки от положительного направления оси y и задаются параметрами startAngle и sweepAngle. Углы измеряются в градусах.

Команды, проводящие построение примитивов из библиотеки GLUT, реализованы через стандартные примитивы OpenGL и GLU. Для построения нужного примитива достаточно произвести вызов соответствующей команды.

void glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)

void glutWireSphere(GLdouble radius, GLint slices, GLint stacks)


Команда glutSolidSphere() строит сферу, а glutWireSphere() — каркас сферы радиусом radius. Остальные параметры имеют тот же смысл, что и в предыдущих командах.

Эти команды строят куб или каркас куба с центром в начале координат и длиной ребра size.

void glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks)

void glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks)

Эти команды строят конус или его каркас высотой height и радиусом основания base, расположенный вдоль оси z. Основание находится в плоскости z=0. Остальные параметры имеют тот же смысл, что и в предыдущих командах.

void glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings)

void glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint nsides, GLint rings)

Эти команды строят тор или его каркас в плоскости z=0. Внутренний и внешний радиусы задаются параметрами innerRadius, outerRadius. Параметр nsides задает число сторон в кольцах, составляющих ортогональное сечение тора, а rings- число радиальных разбиений тора.

Эти команды строят тетраэдр (правильную треугольную пирамиду) или его каркас, при этом радиус описанной сферы вокруг него равен 1.

Эти команды строят октаэдр или его каркас, радиус описанной вокруг него сферы равен 1.

Эти команды строят додекаэдр или его каркас, радиус описанной вокруг него сферы равен квадратному корню из трех.

Эти команды строят икосаэдр или его каркас, радиус описанной вокруг него сферы равен 1.

Создание приложения в среде MS Visual C++ 5.0

Перед началом работы необходимо скопировать файлы glut.h, glut32.lib glut32.dll в каталоги…\MSVC\Include\Gl,…\MSVC\Lib,…\Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, opengl32.lib, glu32.lib, opengl32.dll, glu32.dll, которые обычно входят в состав Visual C++ и Windows. При использовании команд из библиотеки GLAUX к перечисленным файлам надо добавить glaux.h, glaux.lib.

Для создания приложения надо выполнить следующие действия:

• Создание проекта: для этого надо выбрать File→New→Projects→Win32 Console Application, набрать имя проекта, OK.

• В появившемся окне выбрать ‘An empty project’, Finish, OK.

• Текст программы можно либо разместить в созданном текстовом файле (выбрав File→New→Files→Text File), либо добавив файл с расширением *.c или *.cpp в проект (выбрав Project→Add To Project→Files).

• Подключить к проекту библиотеки OpenGL. Для этого надо выбрать Project-›Settings-›Link и в поле Object/library modules набрать названия нужных библиотек: opengl32.lib, glu32.lib, glut32.lib и, если надо, glaux.lib.

• Для компиляции выбрать Build→Build program.exe, для выполнения — Build→Execute program.exe.

• Чтобы при запуске не появлялось текстовое окно, надо выбрать Project→Settings→Link и в поле Project Options вместо ‘subsystem:console’ набрать ‘subsystem:windows’,и набрать там же строку ‘/entry:mainCRTStartup’

Когда программа готова, рекомендуется перекомпилировать ее в режиме ‘Release’ для оптимизации по быстродействию и объему. Для этого сначала надо выбрать Build→Set Active Configuration… и отметить -Win32 Release, а затем заново подключить необходимые библиотеки.

Создание приложения в среде Borland C++ 5.02

Как и для Visual C++, сначала надо обеспечить наличие файлов glut.h, glut32.lib, glut32.dll в каталогах…\BorlandC\Include\Gl,…\BorlandC\Lib,…\Windows\System соответственно. Также в этих каталогах надо проверить наличие файлов gl.h, glu.h, opengl32.lib, glu32.lib, opengl32.dll, glu32.dll, которые обычно входят в состав BorlandC++ и Windows. При этом надо учитывать, что версии Microsoft файлов opengl32.lib, glu32.lib, glut32.lib для Borland C++ не подходят и следует использовать только совместимые версии. Чтобы создать такие версии, надо использовать стандартную программу ‘implib, которая находится в каталоге…\BorlandC\Bin. Для этого надо выполнить команды вида implib…\BorlandC\Lib\filename.lib…\filename.dll для перечисленных файлов, которые создают нужный *.lib файл из соответствующего *.dll файла. Кроме того, надо отметить, что компилятор BorlandC не может по неизвестным причинам использовать файл glaux.lib, входящий в состав BorlandC++5.02, при компиляции приложения, использующего библиотеку GLAUX, поэтому возможно от этой библиотеки придется отказаться. Для создания приложения надо выполнить следующие действия:

• Создание проекта: для этого надо выбрать Project→New Project и заполнить поля в окне Target Expert следующим образом: в поле Platform выбрать Win32,в поле Taget Model выбрать Сonsole, нажать Advanced и отменить выбор пунктов *.rc и *.def.

• Подключить к проекту библиотеки OpenGL. Для этого надо выбрать в окне проекта название исполняемого файла проекта (*.exe) и нажав правую кнопку мыши выбрать в контекстном меню пункт Add node. Затем надо определить положение файлов opengl32.lib, glu32.lib, glut32.lib.

• Для компиляции выбрать Project→Build All, для выполнения Debug-›Run.

Пример программы

Результатом выполнения этой программы является построение тетраэдра с вращающимися вокруг него кольцами, на которые нанесена текстура. В среде MS Visual C++ программа может компилироваться без изменений, а при компиляции в Borland C++ придется закомментировать вызов и описание функции TextureInit(), после чего не будет проводиться наложение текстур. Как было сказано выше, попытка использовать функции из библиотеки GLAUX приводит к сообщению об ошибке при компиляции программы.

Компиляция примера приложения opengl с использованием c ++ на терминале Linux

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

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

Позвольте мне поделиться тем, что ls показывает в каталоге этого проекта:

Папка external включает в себя некоторые заголовки, которые были включены в main.cpp файл. Вот почему я также называю эту папку.

Вот первые десять строк main.cpp , «glm/*.hpp» файлы находятся в external папка.

И в конце концов, вот сообщение об ошибке, которое я получаю. Он просто жалуется на декларации. Я прочитал много документации и вопросов вокруг, реализуя много решений, которые столкнулись с очень похожей проблемой. Тем не менее, в моем случае проблема остается.

Решение

Не объявлено в области означает, что вы не включили заголовок или не включили его должным образом.

Должен дать вам все.
Если это не сработает, попробуйте просто gl.h.

Другие решения

Эти «glXXX не был объявлен» означает, что вы не включаете glew.

Попробуйте что-то вроде #include «GLEW/include/GL/glew.h Идея в том, что glew.h должны быть включены в первую очередь.

Glew используется для поиска функций glXXX для OpenGL> 1.3

Работа с OpenGL — Минимальная программа

Delphi , Графика и Игры , OpenGL

Работа с OpenGL — Минимальная программа

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

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

То есть схема здесь такая — приложение отдает команды машине OpenGL, получая результат на поверхности своего окна. Такая архитектура называется «клиент — серверной», в роли клиента выступает наше приложение, в роли сервера — система OpenGL. Задача сервера — отрабатывать команды клиента. В принципе, сервер может располагаться и не на нашем компьютере, а удаленно, возможно и за тысячи километров от нас. Наше приложение должно передать серверу требуемые для работы данные — контексты и команды на языке сервера. Также важно понимать, что основную работу выполняет не наше приложение, а сервер. Наше приложение лишь создает окно — платформу для работы сервера, и передает команды серверу. При грамотном подходе нет разницы, какими средствами мы спроектировали приложение — С или Delphi, скорость воспроизведения целиком зависит от производительности сервера — машины OpenGL. Мы выбрали в качестве средства разработки приложений именно Delphi за выдающуюся скорость компиляции и обаятельность концепций.

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

Мы знаем, что ссылка на контекст устройства — величина типа HDC, для получения которой вызываем функцию GetDC. Ссылке на контекст устройства в Delphi соответствует свойство Canvas.Handle формы, принтера и некоторых компонентов. Теоретически всюду в наших примерах в строках, использующих величину DC типа HDC, вместо DC можно использовать Canvas.Handle. В первых примерах для начинающих это так и сделано. Каков же все-таки смысл контекста устройства, если он и так связан с однозначно определенным объектом — окном, областью памяти или принтером, и зачем передавать дополнительно какую-то информацию об однозначно определенном объекте?

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

рисуют один и тот же эллипс на поверхности формы и на распечатываемом документе соответственно, то есть на различных устройствах. Причем, если мы будем выводить разноцветную картинку на монохромный принтер, он справится с этой задачей, передавая цвета оттенками серого. Даже если мы рисуем только на канве формы, мы имеем дело с различными устройствами — нам неизвестно, какова графическая плата пользователя и каковы характеристики текущей установки настроек экрана. Например, имея в своем распоряжении более 16 миллионов цветов, приложение не заботится об отображении такой богатой палитры на экране, располагающем всего 256 цветами. Эти вопросы приложение перекладывает на плечи операционной системы, решающей их посредством драйверов устройств. Приложению для того, чтобы воспользоваться функциями воспроизведения Windows, необходимо только указать ссылку на контекст устройства, содержащую средства и характеристики устройства вывода.

Илон Маск рекомендует:  Список определений

Win32 Programmer’s Reference фирмы MicroSoft о контексте устройства сообщает следующее:

«Контекст устройства является структурой, которая определяет комплект графических объектов и связанных с ними атрибутов, и графические режимы, влияющие на вывод. Графический объект включает карандаш для изображения линии, щетку для краски и заполнения, растр для копирования или прокрутки частей экрана, палитру для определения комплекта доступных цветов, области для отсечения и других операций, и маршрута для операций рисования».


Термин «структура», встретившийся здесь, соответствует записи в терминологии Delphi. Контекст устройства Windows содержит информацию, относящуюся к графическим компонентам GDI, контекст воспроизведения содержит информацию, относящуюся к OpenGL, то есть играет такую же роль, что и контекст устройства для GDI. В частности, эти контексты являются хранилищами состояния системы, например, хранят информацию о текущем цвете карандаша.

Итак, ссылка на контекст устройства содержит характеристики устройства и средства отображения. Именно он знает, как выводить на конкретно это устройство. Упрощенно говоря, получив ссылку на контекст устройства, мы берем в руки простой либо цветной карандаш, или кисточку с палитрой в миллионы оттенков. Сервер OpenGL, прежде чем приступать к работе, также должен определиться, на каком оборудовании ему придется работать. Это может быть скромная персоналка, а может быть и мощная графическая станция. Прежде чем получить контекст воспроизведения, сервер OpenGL должен получить детальные характеристики используемого оборудования. Эти характеристики хранятся в специальной структуре, тип которой — TPixelFormatDescriptor (описание формата пикселя). Формат пикселя определяет конфигурацию буфера цвета и вспомогательных буферов.

Самый частый вопрос, который я получаю в связи с моими уроками, заключается в просьбе указать источники подробной информации об OpenGL на русском. К сожалению, если такие и есть, то мне они неизвестны. Главным нашим подручным станет поставляемый в составе Delphi файл помощи по OpenGL. Систему помощи Delphi для получения хороших результатов необходимо настраивать, если в помощи Delphi найти раздел по OpenGL, он не порадует обилием информации. В разных версиях Delphi настройка помощи выполняется по-разному, потребуются некоторые несложные манипуляции, но мы не будем тратить на это время. Будем использовать самый простой способ — контекстную помощь. Наберите в тексте модуля фразу «PixelFormatDescriptor», нажмите клавишу F1 и Вы получите подробную помощь об этом типе. Точно также мы будем получать помощь обо всех терминах, функциях и командах OpenGL.

Итак, мы получили обширное описание структуры PixelFormatDescriptor. Обращаю внимание, что мы видим раздел помощи MicroSoft, рассчитанной на программистов С и С++, поэтому описание использует термины и стилистику именно этих языков. Так, по традиции Delphi имена типов начинаются с префикса T, но нам не удастся найти помощь по термину TPixelFormatDescriptor. К сожалению, это не единственное неудобство, которое нам придется испытывать. Например, если сейчас мы заглянем в файл windows.pas и найдем описание записи TPixelFormatDescriptor, мы обнаружим, что в файле помощи не указаны некоторые константы, а именно: PFD_SWAP_LAYER_BUFFERS, PFD_GENERIC_ACCELERATED и PFD_DEPTH_DONTCARE. А константа, названная PFD_DOUBLE_BUFFER_DONTCARE, по-видимому, соответствует константе, описанной в модуле windows.pas как PFD_DOUBLEBUFFER_DONTCARE. Наверное, более поздние версии помощи и заголовочного файла исправят этот и другие неточности.

Итак, смысл структуры PixelFormatDescriptor — детальное описание графической системы, на которой происходит работа. Вас может озадачить дотошность этого описания, но, уверяю, особое внимание от нас из всего этого описания требует совсем немногое.

В каталоге Beginner/1 Вы найдете проект OpenGL_min.dpr, в котором я привел описание всех полей структуры TPixelFormatDescriptor на русском, в момент их первоначального заполнения. Делается это в процедуре SetDCPixelFormat, вызываемой между получением ссылки на контекст устройства и созданием контекста воспроизведения OpenGL. Посмотрим подробнее, что там делается. Полям структуры присваиваются желаемые значения, затем вызовом функции ChoosePixelFormat осуществляется запрос системе, поддерживается ли на данном рабочем месте выбранный формат пикселя, и вызовом функции SetPixelFormat устанавливаем формат пикселя в контексте устройства. Функция ChoosePixelFormat возвращает индекс формата пикселя, который нам нужен в качестве аргумента функции SetPixelFormat.

Заполнив поля структуры TPixelFormatDescriptor, мы определяемся со своими пожеланиями к графической системе, на которой будет происходить работа приложения, машина OpenGL подбирает наиболее подходящий к нашим пожеланиям формат, и устанавливает уже его в качестве формата пикселя для последующей работы. Наши пожелания корректируются применительно к реальным характеристикам системы. То, что машина OpenGL не позволит нам установить нереальный для конкретной машины формат пикселя, значительно облегчает нашу работу. Предполагая, что разработанное приложение будет работать на машинах разного класса, можно запросить «всего побольше», а уж OpenGL разберется на конкретной машине, каковы параметры и возможности оборудования, на котором сейчас будет происходить работа. На этом можно было бы и закончить разговор о формате пикселя, если бы мы могли полностью довериться выбору OpenGL.

Обратим внимание на поле структуры «битовые флаги» — dwFlags. То, как мы зададим значение флагов, существенно может сказаться на работе нашего приложения, и наобум задавать эти значения не стоит. Тем более, что некоторые флаги совместно ужиться не могут, а некоторые могут присутствовать только в паре с другими. В этом примере флагам я присвоил значение PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL, то есть сообщаю системе, что я собираюсь осуществлять вывод в окно, и что моя система в принципе поддерживает OpenGL. Я ограничился всего двумя константами из обширного списка, приведенного в модуле windows.pas, по каждой из которых в файле помощи приведено детальное описание.

Так, константа PFD_DOUBLEBUFFER включает режим двойной буферизации, когда вывод осуществляется не на экран, а в память, затем содержимое буфера выводится на экран. Это очень полезный режим, если в любом примере на анимацию убрать режим двойной буферизации и все команды, связанные с этим режимом, хорошо будет видно мерцание при выводе кадра. Константу PFD_GENERIC_ACCELERATED имеет смысл устанавливать в случае, если компьютер оснащен графическим акселератором. Флаги, заканчивающиеся на «DONTCARE» , сообщают системе, что соответствующий режим может иметь оба значения, то есть PFD_DOUBLE_BUFFER_DONTCARE — запрашиваемый формат пикселя может иметь оба режима — одинарной и двойной буферизации. Со всеми остальными полями и константами я предоставляю Вам возможность разобраться самостоятельно, только замечу, что поле iLayerType, описанное в windows.pas типа Byte, может, согласно помощи, иметь три значения: PFD_MAIN_PLANE, PFD_OVERLAY_PLANE и PFD_UNDERLAY_PLANE, однако константа PFD_UNDERLAY_PLANE имеет значение -1, так что установить такое значение не удастся.

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

В примере битовым флагам задаем все возможные значения одновременно, числовым полям задаем заведомо нереальное значение 64, и смотрим на выбор формата пикселя, сделанным OpenGL. Результат, который Вы получите — выбранный формат пикселя, я предсказать не смогу — он индивидуален для каждой конкретной конфигурации машины и текущих настроек. Возможно, Вы получите в результате, что режим двойной буферизации не будет установлен — напоминаю, многие флаги устанавливаются только в комбинации с другими определенными. Наше приложение позволяет менять параметры формата пикселя и устанавливать его заново. Чтобы видеть, что происходит воспроизведение, небольшая площадка на экране при каждом тестировании окрашивается случайным цветом, используя функции OpenGL. Поэкспериментируйте с этим приложением, например, определите комбинацию флагов для установления режима двойной буферизации. Посмотрите значение числовых полей формата при различной палитре экрана — 16, 24, 32 бита, но не 256 цветов. О выводе при палитре экрана в 256 цветов — отдельный разговор. Это приложение, в частности, дает ответ на вопрос — как определить, оснащен ли компьютер графическим акселератором. Повозившись с этим приложением, Вы найдете ответ на вопрос, на который я Вам ответить не смогу — как надо заполнить структуру TPixelFormatDescriptor для Вашего компьютера. Обратите внимание, что в коде я установил несколько проверок на отсутствие контекста воспроизведения, который может быть потерян по ходу работы любого приложения, использующего OpenGL — редкая, но возможная ситуация в штатном режиме работы системы и очень вероятная ситуация если, например, по ходу работы приложения менять настройки экрана.

Минимальная программа OpenGL

Теперь мы знаем все, что необходимо для построения минимальной программы, использующей OpenGL. Я привел два варианта этой программы — одна построена исключительно на функциях Windows API, другая использует библиотеку классов Delphi (проекты каталогов Beginner/1 и Beginner/2 соответственно).

Взглянем на головной модуль второго проекта. При создании формы задаем формат пикселя, в качестве ссылки на контекст устройства используем значение Canvas.Handle формы. Создаем контекст воспроизведения OpenGL и храним в переменной типа HGLRC. При обработке события OnPaint устанавливаем контекст воспроизведения, вызываем функции OpenGL и освобождаем контекст. При завершении работы приложения удаляем контекст воспроизведения. Для полной академичности можно включить строки, проверяющие, получен ли контекст воспроизведения, и не теряется ли он по ходу работы. Признаком таких ситуаций является нулевое значение переменной hrc. В минимальной программе я просто окрашиваю окно в желтоватый оттенок. Получив помощь по команде glClearColor, Вы можете узнать, что аргументы ее — тройка вещественных чисел в интервале [0;1], задающих долю красного, зеленого и синего составляющих в цвете и еще один, четвертый аргумент, о котором мы поговорим чуть позднее. Этому аргументу я в примере задал значение 1.0. Вообще то, аргументы glClearColor, согласно помощи, имеют неведомый тип GLclampf. Для того, чтобы разобраться с этим типом, отсылаю к строке

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

Строку нашей программы

будем понимать как очистку экрана, фон при этом покрывается заданным цветом.

Проект, построенный только на функциях API, надеюсь, сейчас стал более понятным. Вместо Canvas.Handle используем собственную переменную dc, в обработчике события WM_PAINT реализуем действия, которые Delphi при обычном подходе выполняет за нас. Напоминаю, что для лучшей устойчивости работы обработчик WM_PAINT следовало бы написать так:

А в обработчике WM_DESTROY следует перед PostQuitMessage добавить строку:

То есть все используемые ссылки необходимо освобождать, а после того, как они стали не нужны — удалять.

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

Во всех своих примерах я приписал рекомендацию не запускать проекты, использующие OpenGL под управлением среды Delphi. Дело в том, что часто в таких ситуациях программа аварийно прерывается, выдавая сообщение «access violation -«. Это происходит и в случае самой аккуратной работы с контекстами, и не связано с небрежностью работы программы. Некоторые программисты вину за это возлагают на софтверные драйверы и рекомендуют обновить их. Некоторые утверждают, что дело в Windows 9X, и под NT этого не происходит. Возможно, Вы тоже ничего такого не замечали и не можете взять в толк, о чем я сейчас веду речь. У меня такие окошки вылетают через раз на одном и том же проекте, хотя откомпилированный модуль работает превосходно. Я полагаю, что если драйверы не «глюкуют», когда приложение работает без среды Delphi, дело не только в драйверах.

Вывод на поверхность компонентов

Теоретически функциями OpenGL возможно осуществлять вывод не только на поверхность формы, а и на поверхность любого компонента, если у него имеется свойство Canvas.Handle, для чего при получении контекста воспроизведения необходимо указывать именно его ссылку на контекст устройства, например, Image1.Canvas.Handle. Однако чаще всего это приводит к неустойчивой работе, вывод «то есть, то нет», хотя контекст воспроизведения присутствует и не теряется. Я советую Вам всегда пользоваться выводом исключительно на поверхность окна. OpenGL прекрасно уживается с визуальными компонентами, как видно из примера TestPFD, если же необходимо ограничить размер области вывода, для этого есть стандартные методы, о которых мы обязательно будем беседовать в будущем.

Просто ради интереса приведу пример, когда вывод OpenGL осуществляется на поверхность панели, то есть компонента, не имеющего свойства Canvas. Для этого мы пользуемся тем, что панель имеет отдельное окно, вызываем функцию GetDC с аргументом Panel1.Handle.

Точно также Вы можете выводить на поверхность любого компонента, имеющего свойство Handle, например, на поверхность обычной кнопки. Обязательно попробуйте сделать это.

Для вывода на компонент класса TImage можете записать:

и удалить строки BeginPaint и EndPaint, поскольку TImage не имеет свойства Handle, то есть не создает отдельного окна. Однако вывод на такие компоненты как раз отличается полной неустойчивостью, так что я не гарантирую Вам надежного положительного результата.

Вообще, вместо использования Canvas.Handle лучше использовать самостоятельно полученную аналогичную величину, вместо обработки событий лучше использовать свои ловушки сообщений. Такой подход приводит к максимальной скорости и надежности работы приложения.

В конце сегодняшнего разговора я хочу привести еще несколько проектов, появившихся за это время из под моего пера и дополняющих «ЖиЛистую Delphi».

Статья Работа с OpenGL — Минимальная программа раздела Графика и Игры OpenGL может быть полезна для разработчиков на Delphi и FreePascal.

Комментарии и вопросы

Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.

Opengl примеры интересных программ

200?’200px’:»+(this.scrollHeight+5)+’px’);»> #include
using namespace std;

void display()
<
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(0.4, 0.4);
glVertex2f(0.4, 0.8);
//
glVertex2f(0.4, 0.8);
glVertex2f(0.8, 0.8);
//
glVertex2f(0.8, 0.8);
glVertex2f(0.8, 0.4);
//
glVertex2f(0.4, 0.4);
glVertex2f(0.8, 0.4);
glEnd();
glFlush();

int main(int argc, char **argv)
<
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(240, 240);
glutInitWindowPosition(100, 740);
glutCreateWindow(«First window!»);
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
glutDisplayFunc(display);
glutMainLoop();
>

Простая программа на OpenGL

Упражнение 1. Создание простого графического окна (Simple)

  • Заполните файл реализации Simple. cpp следующим кодом
  • Запустите приложение на выполнение

Оболочка выдаст предупреждение, что данная форма проекта является устаревшей.

  • Установите флажок Do not show this dialog again и щелкните на кнопке 19_16

Должен получиться такой результат

Разбор кода Simple

Наша простая программа содержит вызовы четырех функций библиотеки GLUT (с префиксом glut ) и три вызова «чистых» функций OpenGL (с префиксом gl ). Вспомогательная библиотека GLUT ( OpenGL Utility Toolkit — набор инструментов OpenGL ) написана Марком Килгардом ( Mark Kilgard) и предназначена для межплатформенных примеров программирования и демонстраций. В нее входят графические элементы пользовательского интерфейса, включая использование меню , управление другими окнами, обеспечение поддержки джойстика и др. Ее использование как расширение OpenGL содействует обучению и такому написанию программ OpenGL , чтобы программист не занимался деталями конкретной среды, а сосредоточился на написании основного кода графического приложения. Библиотеку GLUT можно бесплатно найти в Internete .

Сама наша программа делает немного. Она создает стандартное окно графического интерфейса пользователя ( GUI ) с надписью Simple и синим фоном. В файл stdafx.h помещены подключения заголовков прототипов функций , используемых в программе.

устанавливает режим отображения графического окна при его создании. Соединение макросов в параметрах вызова функции задает окно с одиночной буферизацией ( GLUT_SINGLE ) и режим цвета RGB с альфа-каналом ( GLUT_RGBA или GLUT_RGB ). Альтернативным режимом задания цветов является режим использования индексированных цветов ( GLUT_INDEX ). Одиночная буферизация означает, что все команды рисования выполняются прямо в отображаемом окне (на контексте, холсте). Существует еще двойная буферизация (задается параметром GLUT_DOUBLE ), когда команды рисования выполняются в буфере вне экрана, а затем быстро отображаются в окне.


создает графическое окно с надписью в строке заголовка из параметра вызова.

устанавливает нашу функцию RenderScene как функцию обратного вызова ( call back ), в которой можно размещать вызовы функций визуализации OpenGL .

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

вводит приложение в цикл сообщений. Она должна быть вызвана только один раз и работает до завершения приложения. Она обрабатывает обрабатывает все сообщения, связанные с операционной системой ( управление курсором , нажатие клавиш и т.д.).

устанавливает цвет модели RGB , используемый для очистки окна. Получая код цвета, Windows и OpenGL преобразуют его в ближайшую точную величину, поддерживаемую конкретной видеоаппаратурой. Последний аргумент в вызове этой функции определяет величину альфа-канала — уровень прозрачности (1 — нeпрозрачный, 0 — абсолютно прозрачный).

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

Обычно решение о подвижке очереди команд принимает сама операционная система. Но строка

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

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

Илон Маск рекомендует:  Цвет фона и текста документа

Записки программиста

Простой кроссплатформенный OpenGL-проект на C++

24 августа 2015

В свободное время я потихоньку раскуриваю OpenGL. Это у меня что-то вроде нового хобби. Как кто-то из вас может помнить, когда-то я уже пробовал играться с OpenGL на Haskell. Однако использовать тамошний ни на что не похожий и практически не документированный DSL оказалось слишком сложной задачей для меня, и от затеи пришлось отказаться.

Надо отметить, что в этот раз я чуть было не совершил ту же ошибку, выбрав поначалу язык Scala и библиотеку LWJGL. С документацией у LWJGL все отлично, никакого своего DSL не накручено, и примеров в сети очень много. Но проблема заключается в том, что в большинстве туториалов и книг по OpenGL все же используется язык C++. И если ты столкнешься с какой-то проблемой, никто ни в каком IRC или на StackOverflow не станет разбираться в твоем коде на Scala. Плюс неизвестно еще, ты просто неправильно используешь OpenGL, или может это какая-то ошибка в LWJGL, или может это какой-то хитрый баг, вызванный взаимодействием кода на Scala с LWJGL. Сообщество вокруг LWJGL достаточно велико само по себе, но чтобы кто-то из этого сообщества тебе помог, код должен быть на Java, а с Java связываться ну очень не хотелось. Кроме того, у LWJGL на данный момент есть стабильная, но постепенно теряющая свою актуальность версия 2.9, а также совершенно новая, ни с чем не совместимая, и все еще находящаяся в альфе версия 3.0.

В силу всех этих причин на время изучения OpenGL я решил использовать C++. Когда у меня будет больше опыта в самом OpenGL, можно будет попробовать использовать и альтернативные языки, например, Scala или Go. В качестве системы сборки был выбран CMake. Дело в том, что в Linux, активным пользователем которого я являюсь, по всей видимости, пока что наиболее приличной IDE для C++ является CLion. Я реально проводил серьезный ресерч на эту тему. А CLion ничего кроме CMake пока не поддерживает. Кроме того, у меня есть очень приятный опыт использования продукции JetBrains в прошлом, да и в настоящем.

Интересно, как культура и традиции могут определять выбор технологий, не правда ли?

Теперь, когда инструментарий выбран, можно создать новый Git-репозиторий, открыть CLion и создать в этом репозитории новый проект. В проекте нам понадобятся кое-какие зависимости. И тут начинается интересное, так как общепринятого способа управления зависимостями в C++ вроде как нет. Довольно перспективно выглядит Biicode, но, насколько я могу судить, пока что он не получил широкого распространения. Не то, чтобы я много работал с C++ в последнее время, но похоже, что неплохое решение заключается в следующем. Зависимости, которые можно поставить через менеджер пакетов ОС, например, apt-get, ставятся через него. Прочие же зависимости подтягиваются в виде исходных кодов через механизм сабмодулей в Git.

Например, нам в нашем проекте понадобятся библиотеки GLM и GLFW. Первая предназначена для работы с матрицами и векторами. Вторая — для рисования окошек, реагирования на движения мыши, нажатия клавиш клавиатуры и так далее. Еще для решения той же задачи есть GLUT. В одних туториалах используется GLFW, в других GLUT, и в чем принципиальное различие между ними на данный момент мне не до конца понятно. Так что, по сути, тут я выбирал наугад. Итак, используя сабмодули Git, подключаем эти библиотеки к проекту:

Если вы склонируете репозиторий на другую машину, подтянуть зависимости можно так:

Интересный факт о сабмодулях — они смотрят на конкретный коммит. Изменить его можно, перейдя в каталог сабмодуля и сделав checkout интересующей ветки или тэга. После этого git diff вашего собственного репозитория покажет, что в нем есть изменения, который можно закоммитить. Также в какой-то момент вы можете обнаружить, что удаляются сабмодули Git очень непросто. Делается это так (почти рабочий рецепт был найден на gist, приведенная ниже инструкция тестировалась на Git 1.9.1):

  1. Скажите git rm —cached имя_сабмодуля ;
  2. Удалите соответствующие строчки из файла .gitmodules;
  3. Также грохните соответствующую секцию в .git/config;
  4. Сделайте коммит;
  5. Удалите файлы сабмодуля;
  6. Удалите каталог .git/modules/имя_сабмодуля;

Теперь правим файл CMakeList.txt нашего проекта:

cmake_minimum_required ( VERSION 2.8 )
project ( red_triangle )

find_package ( OpenGL REQUIRED )

include_directories ( glfw/include )
include_directories ( glm )

set ( CMAKE_CXX_FLAGS » $ -O2 -Wall -Wextra -std=c++11″ )

set ( SOURCE_FILES main.cpp )
add_executable ( red_triangle $ )

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

В main.cpp пишем следующий код:

#include
#include
#include
#include
#include

int main ( ) <
if ( ! glfwInit ( ) ) <
std :: cerr «Failed to initialize GLFW» std :: endl ;
return — 1 ;
>

GLFWwindow * window = glfwCreateWindow ( 300 , 300 , «Red Triangle» ,
nullptr, nullptr ) ;
if ( window == nullptr ) <
std :: cerr «Failed to open GLFW window» std :: endl ;
glfwTerminate ( ) ;
return — 1 ;
>

glfwMakeContextCurrent ( window ) ;
glfwSwapInterval ( 1 ) ;
glfwShowWindow ( window ) ;

// Важно! Не эквивалентно glEnable(GL_DEPTH_TEST | GL_DOUBLEBUFFER)
glEnable ( GL_DEPTH_TEST ) ;
glEnable ( GL_DOUBLEBUFFER ) ;
glDepthFunc ( GL_LESS ) ;

glClearColor ( 0 , 0 , 0 , 1 ) ;

glm :: mat4 m = glm :: perspective ( 45.0f , 4.0f / 3.0f , 1.0f , 100.0f ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadMatrixf ( glm :: value_ptr ( m ) ) ;

while ( glfwWindowShouldClose ( window ) == GL_FALSE ) <
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) ;
glColor4f ( 1 , 0 , 0 , 1 ) ;
glBegin ( GL_TRIANGLES ) ;
glVertex3f ( 0 , 0.5 , — 5 ) ;
glVertex3f ( 0.5 , — 0.5 , — 5 ) ;
glVertex3f ( — 0.5 , — 0.5 , — 5 ) ;
glEnd ( ) ;

glfwSwapBuffers ( window ) ;
glfwPollEvents ( ) ;
>

glfwDestroyWindow ( window ) ;
glfwTerminate ( ) ;
return 0 ;
>

Важно! Имейте в виду, что все эти glBegin, glEnd и glVertex3f — это устаревший OpenGL. В новых проектах вы не должны их использовать. Здесь эти функции используются только для того, чтобы не уводить повествование в сторону VAO, VBO и шейдеров. Заинтересованные читатели могут ознакомиться с почти таким же проектом на новом OpenGL.

Код предположительно очень прост и на данном этапе не нуждается в особых пояснениях. Здесь вы видите пример создания окна при помощи GLFW, простой пример использования GLM, а также рисование красного треугольника на черном фоне при помощи устаревших функций OpenGL. Заинтересованные читатели могут найти больше теории в предыдущих постах этого блога, посвященных OpenGL, или дождаться будущих. Результат же будет выглядеть как-то так:

А сборка проекта «вручную», без использования CLion, осуществляется так:

Примечательно, что это же проект успешно компилируется и под Windows. Там есть свои сложности, связанные с необходимостью устанавливать MinGW и Git для Windows, но в целом все работает точно так же. Еще может потребоваться немного подправить идущий с MinGW файл math.h, так как в нем есть баг. Кроме того, код успешно собирается и под MacOS.

Итак, теперь у нас есть полноценная среда для изучения OpenGL. Полную версию исходного кода к заметке вы найдете в этом репозитории. Также я буду благодарен, если вы расскажете мне, как на самом деле принято работать с зависимостями в С++ ну и прочее в таком духе, так как, повторюсь, C++ в последнее время я трогал очень мало.

Урок 1: Открываем окно

Добро пожаловать на первый урок!

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

Чтобы работать с данными уроками вам не потребуется дополнительных навыков. Опыт в любом языке программирования (C, Java, Lisp, JavaScript и других) поможет вам лучше понимать суть, но вовсе не обязателен.

Все уроки написаны на “легком” C++ и мы потратили много усилий, чтобы сделать код настолько простым, насколько это вообще возможно. Здесь не будет шаблонов, классов и указателей, что позволит вам понять все, даже если вы знаете только Java.

Забудьте все

Забудьте все, что вы знали об OpenGL ранее, если ваши знания касаются glBegin() и подобных функций. Здесь вы будете изучать новые стандарты OpenGL (OpenGL 3 и 4), в отличие от многих онлайн-уроков, в которых до сих пор рассматривается “старый” OpenGL (OpenGL 1 и 2).

Компиляция исходного кода уроков


Весь исходный код к урокам может быть скомпилирован на таких платформах, как Windows, Linux, Mac. Общая процедура для всех этих платформ будет приблизительно одинакова:

  • Обновите драйверы! Обязательно сделайте это, если что мы вас предупреждали :)
  • Скачайте компилятор, если у вас его до сих пор нет.
  • Установите CMake
  • Скачайте исходный код урока
  • Создайте проект используя CMake
  • Скомпилируйте проект
  • Изменяйте его :)

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

##Компиляция в Windows

  • Обновление драйверов должно быть для вас легкой задачей. Все что вам нужно — это просто сходить на сайт NVidia или AMD, скачать оттуда драйверы и установить их. Если вдруг вы не знаете точно модель вашей видеокарты, то вы можете посмотреть ее в свойствах адаптера, для этого перейдите в Панель управления -> Система -> Диспетчер устройств -> Видео адаптер. Если у вас встроенный Intel GPU, то драйверы всегда поставляются в комплекте.
  • Мы предлагаем вам использовать Visual Studio 2015 Express for Desktop в качестве среды, которую вы можете бесплатно скачать здесь. Если же вы захотите использовать MinGW, то мы рекомендуем вам Qt Creator. В любом случае, устанавливайте то, что вам необходимо и хотя шаги в уроках рассматриваются в Visual Studio, скорее всего различия в других IDE будут минимальны.
  • Скачайте CMake и установите его.
  • Скачайте исходный код, распакуйте его к примеру в C:/Users/XYZ/Projects/OpenGLTutorials
  • Запустите CMake. В первом поле укажите путь к распакованной папке. Если сомневаетесь, то это та папка, где находится файл CMakeLists.txt. Во втором поле укажите папку, в которую будут записываться исполняемые файлы, например вы можете указать здесь C:/Users/XYZ/Projects/OpenGLTutorials-build-Visual2010-32bits или что-то подобное. К слову, эта папка может находиться где угодно.
  • Нажмите кнопку Configure. Так как вы впервые настраиваете проект CMake спросит вас, какой именно компилятор вы хотите использовать. Здесь все упирается в ваш инструментарий, который вы выбрали в шаге 2. Кстати, если у вас Windows 64-bit, то вы можете выбрать 64 разрядные компиляторы, но если вы не уверены, то используйте 32.
  • Нажимайте Configure до тех пор, пока не исчезнут все красные строки. Далее нажмите Generate. Теперь ваш Visual Studio проект создан и вы можете забыть про CMake. Можете даже удалить его, если хотите :)
  • Откройте в Visual Studio файл Tutorials.sln в папке, которую вы указывали во втором поле главного окна CMake (C:/Users/XYZ/Projects/OpenGLTutorials-build-Visual2010-32bits). В меню Build нажмите Build All. Исходный код каждого урока и зависимостей будет откомпилирован. Также, каждый исполняемый файл будет скопирован обратно в C:/Users/XYZ/Projects/OpenGLTutorials . Надеемся у вас не возникнет ошибок.
  • Откройте C:/Users/XYZ/Projects/OpenGLTutorials/playground и запустите playground.exe. Если все прошло гладко, то у вас должно появиться черное окно.

Вы также можете запустить любой урок из Visual Studio. Для этого нажмите правой кнопкой мыши на Playground и выберете “Choose as startup project”. Для отладки используйте клавишу F5.

##Компиляция в Linux

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

    Установите последние драйверы. Мы настоятельно рекомендуем вам использовать закрытые драйверу. Это не GNU, но они работают. Если ваш дистрибутив не предоставляет автоматической установки, можете попробовать посмотреть в документации к Ubuntu

Установите все необходимые компиляторы, утилиты и библиотеки. Полный список выглядит так:

Используйте sudo apt-get install *** или su && yum install ****.

/Projects/OpenGLTutorials/ и введите следующие команды:

  • makefile будет создан в директории build
  • Выполните команду make all . Весь исходный код к урокам будет скомпилирован, а каждый исполняемый файл будет также скопирован в

    /Projects/OpenGLTutorials/. Надеемся у вас не возникнет ошибок :)
    Откройте

    /Projects/OpenGLTutorials/playground и выполните ./playground. Если все прошло гладко, то у вас должно появиться черное окно.

    Обратите внимание, что лучшим решением будет использовать IDE, такую как Qt Creator. Она имеет поддержку CMake и предоставляет удобные инструменты для отладки. Инструкция для QtCreator:

    • В QtCreator перейдите в меню File -> Tools -> Options -> Compile&Execute -> CMake
    • Установите путь к CMake. Чаще всего это /usr/bin/cmake
    • File -> Open Project и выберите tutorials/CMakeLists.txt
    • Выберите директорию, в которую необходимо помещать скомпилированные файлы. Лучше всего выбрать директорию вне tutorials
    • Опционально установите -DCMAKE_BUILD_TYPE=Debug в Parameters и используйте Validate.
    • Нажмите на иконку молота внизу. Теперь уроки могут быть запущены из директории tutorials/
    • Чтобы запускать уроки непосредственно из QtCreator, перейдите в Projects -> Execution parameters -> Working Directory и выберете директорию, в которой находятся шейдеры, текстуры и модели. К примеру для Урока 2 это будет:

    ##Компиляция в Mac

    Mac OS не поддерживает OpenGL 3.3. Последние Маки с MacOS 10.7 Lion и совместимыми GPU могут работать с OpenGL 3.2, но не с 3.3. Поэтому используйте исходный код уроков для 2.1. В остальном процедура компиляции очень похожа на процедуру в Windows (Makefile также поддерживаются, но не будут рассматриваться):

    • Установите XCode из Mac App Store
    • Скачайте CMake и установите .dmg . Нет необходимости устанавливать утилиты командной строки.
    • Скачайте исходный код (обязательно версия 2.1) и распакуйте его к примеру в

    /Projects/OpenGLTutorials/ .
    Запустите CMake (Applications -> CMake). В первом поле ввода укажите путь к папке с распакованным исходным кодом уроков. Если сомневаетесь, то это папка, содержащая файл CMakeLists.txt. Во втором поле укажите где вы хотите сохранить исполняемые файлы. К примеру это может быть

    /Projects/OpenGLTutorials_bin_XCode/. Обратите внимание, эта папка может находиться где угодно.

  • Нажмите на кнопку Configure. Так как вы используете конфигурацию впервые, то CMake спросит у вас какой компилятор вы хотите использовать. Выберете XCode.
  • Нажимайте Configure до тех пор, пока не исчезнут все красные строки. Нажмите Generate. Теперь проектный файл для XCode создан и вы можете забыть о CMake, и даже можете удалить его, если захотите.
  • Откройте

    /Projects/OpenGLTutorials_bin_XCode/ . Найдите и откройте файл Tutorials.xcodeproj

  • Выберете урок, который хотите запустить в XCode Scheme Panel и нажмите кнопку Run для компиляции и запуска
  • ##Внимание для пользователей Code::Blocks

    Из-за 2 багов (один в C::B, один в CMake), вам необходимо изменить командную строку Project -> Build Options -> Make commands, как указано на скриншоте:

    Вам также необходимо установить рабочую директорию: Project -> Properties -> Build targets -> tutorial N -> рабочая директория исполняемых файлов (это src_dir/tutorial_N)

    Запуск уроков

    Чтобы запустить исполняемый файл урока просто выполните двойной щелчок мышью на файле в нужной директории. Если вы предпочитаете командную строку, то не забудьте использовать команду cd, чтобы перейти в нужную директорию.

    Если вы хотите запустить урок из IDE, То не забудьте прочитать инструкции, данные выше, чтобы установить корректную рабочую директорию.

    Как работать с уроками

    К каждому уроку прилагается исходный код и все необходимые файлы данных, которые могут быть найдены в tutorialXX/. Тем не менее вы вряд ли будете изменять эти проекты, так как они даются для справки. Лучшим решением будет открыть playground/playground.cpp и изменять его так, как вам захочется. Если по каким-то причинам у вас его нет, то просто скопируйте код любого урока туда и все.

    Мы предоставляем фрагменты кода в каждом уроке. Не стесняйтесь копировать эти фрагменты в playground, пока читаете и экспериментировать с ними — это хорошая практика, гораздо лучшая, чем просто читать готовый код или просто копировать его.

    Открываем окно

    Наконец! Настало время кода OpenGL!

    Хотя… Все уроки будут показывать вам низко-уровневый путь для тех или иных задач, таким образом вы будете видеть, что здесь нет никакой магии, однако открытие окна — задача скучная, поэтому мы будем использовать внешнюю библиотеку GLFW для этой работы. Если вы хотите сделать это сами, то вам необходимо использовать Win32 API в ОС Windows, X11 API в Linux, Cocoa API в Mac. Также вы можете использовать другие библиотеки, такие как: SFML, FreeGLUT, SDL и подобные (см. страницу Ссылки).

    Итак, поехали! Первое что мы делаем — это разбираемся с зависимостями. Нам необходимо базовый функционал для вывода в консоль:

    Далее нам необходим GLEW. Здесь есть немного магии, но перейдем к пояснениям позднее.

    Мы будем использовать GLFW для обработки окна и клавиатуры, так что включаем его тоже.

    Следующий заголовок не является необходимым в данный момент, так как является библиотекой трехмерной математики, но позже будет очень полезен. В нем нет никакой магии и если вы знаете математику, то вполне можете написать свой аналог. Что касается “using namespace glm”, то эта строка переводит пространство имен в glm, чтобы можно было писать “vec3”, вместо “glm::vec3”.


    Если вы скопировали код представленный выше в playground.cpp, то компилятор предупредит вас, что нет функции main(), поэтому добавим ее:

    В теле функции первым делом инициализируем GLFW:

    Теперь мы можем создать наше первое OpenGL окно! :)

    Скомпилируйте и запустите этот исходный код. Если все сделано правильно, то у вас откроется и тут же закроется окно с контекстом OpenGL и это правильно, так как мы не указали, что хотим ждать до тех пор, пока пользователь не нажмет клавишу Escape. Самое время сделать это:

    И это завершает наш первый урок! Во втором уроке мы узнаем как выводить простейший треугольник. Увидимся :)

    Opengl примеры интересных программ

    OpenGL в C++ для Ch—

    . В переводе на нормальный язык этот заголовок звучит так:

    Графическая библиотека OpenGL в С++ для Дремучих Чайников.

    . У меня возникла идея попробовать:
    . не увязнув в подробностях, не запутавшись в придаточных предложениях,
    . не омрачая изложение материала отсутствием юмора,
    научить Дремучего Чайника рисовать в OpenGL линии, эллипсы, гиперболы , а также
    . раскрашивать светящиеся шары,
    . наносить на них текстуру, и всё это двигать и вращать!

    . Чтобы « провести по ней белую линию » по совету лауреата Нобелевской премии Анатоля Франса начнём изучать Графическую библиотеку OpenGL по учебнику, который привезли на осле.

    . Совершенствуем ОС Windows. C Билла Гейтса «причитается»! Рисуем белую линию, эллипс, гиперболу. Убеждаемся, что красота спасёт мир и на примере Венеры Милосской наблюдаем, что с этой красотой потом произойдет.

    . Дорогие Дремучие Чайники, давайте побеседуем с Прекрасной Дамой по имени OpenGL о светящихся шарах, не используя стеки атрибутов и индексы трафарета! На кой черт вам знать, где у дамы расположен аппендикс ?

    . Нарисуем и полюбуемся как выглядят шары в придуманных разработчиками фоновой и диффузной моделях освещения! Полюбуемся сияющими моделями зеркальных шаров, освещённых снизу и сбоку и познакомимся с «операторами-невидимками».

    . А в заключение изобразим Автопортрет Дремучего Чайника в направленном розовом и голубом свете.

    . Создаём из картинки текстуру, накладываем её на окружность и эллипс, рисуем «Царевну Лебедь». Запрещаем центуриону бросать камни в Марию Магдалину — сажаем его за решётку.

    . А чтобы не показалось мало, накрываем 3D чайник папирусом из пирамиды Хеопса, на шар наносим American Beauty художницы Кэри Фрут и американские красотки демонстрируют нам свои прелести!

    Работа с OpenGL — Минимальная программа

    Delphi , Графика и Игры , OpenGL

    Работа с OpenGL — Минимальная программа

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

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

    То есть схема здесь такая — приложение отдает команды машине OpenGL, получая результат на поверхности своего окна. Такая архитектура называется «клиент — серверной», в роли клиента выступает наше приложение, в роли сервера — система OpenGL. Задача сервера — отрабатывать команды клиента. В принципе, сервер может располагаться и не на нашем компьютере, а удаленно, возможно и за тысячи километров от нас. Наше приложение должно передать серверу требуемые для работы данные — контексты и команды на языке сервера. Также важно понимать, что основную работу выполняет не наше приложение, а сервер. Наше приложение лишь создает окно — платформу для работы сервера, и передает команды серверу. При грамотном подходе нет разницы, какими средствами мы спроектировали приложение — С или Delphi, скорость воспроизведения целиком зависит от производительности сервера — машины OpenGL. Мы выбрали в качестве средства разработки приложений именно Delphi за выдающуюся скорость компиляции и обаятельность концепций.

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

    Мы знаем, что ссылка на контекст устройства — величина типа HDC, для получения которой вызываем функцию GetDC. Ссылке на контекст устройства в Delphi соответствует свойство Canvas.Handle формы, принтера и некоторых компонентов. Теоретически всюду в наших примерах в строках, использующих величину DC типа HDC, вместо DC можно использовать Canvas.Handle. В первых примерах для начинающих это так и сделано. Каков же все-таки смысл контекста устройства, если он и так связан с однозначно определенным объектом — окном, областью памяти или принтером, и зачем передавать дополнительно какую-то информацию об однозначно определенном объекте?

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

    рисуют один и тот же эллипс на поверхности формы и на распечатываемом документе соответственно, то есть на различных устройствах. Причем, если мы будем выводить разноцветную картинку на монохромный принтер, он справится с этой задачей, передавая цвета оттенками серого. Даже если мы рисуем только на канве формы, мы имеем дело с различными устройствами — нам неизвестно, какова графическая плата пользователя и каковы характеристики текущей установки настроек экрана. Например, имея в своем распоряжении более 16 миллионов цветов, приложение не заботится об отображении такой богатой палитры на экране, располагающем всего 256 цветами. Эти вопросы приложение перекладывает на плечи операционной системы, решающей их посредством драйверов устройств. Приложению для того, чтобы воспользоваться функциями воспроизведения Windows, необходимо только указать ссылку на контекст устройства, содержащую средства и характеристики устройства вывода.

    Win32 Programmer’s Reference фирмы MicroSoft о контексте устройства сообщает следующее:

    «Контекст устройства является структурой, которая определяет комплект графических объектов и связанных с ними атрибутов, и графические режимы, влияющие на вывод. Графический объект включает карандаш для изображения линии, щетку для краски и заполнения, растр для копирования или прокрутки частей экрана, палитру для определения комплекта доступных цветов, области для отсечения и других операций, и маршрута для операций рисования».

    Термин «структура», встретившийся здесь, соответствует записи в терминологии Delphi. Контекст устройства Windows содержит информацию, относящуюся к графическим компонентам GDI, контекст воспроизведения содержит информацию, относящуюся к OpenGL, то есть играет такую же роль, что и контекст устройства для GDI. В частности, эти контексты являются хранилищами состояния системы, например, хранят информацию о текущем цвете карандаша.

    Итак, ссылка на контекст устройства содержит характеристики устройства и средства отображения. Именно он знает, как выводить на конкретно это устройство. Упрощенно говоря, получив ссылку на контекст устройства, мы берем в руки простой либо цветной карандаш, или кисточку с палитрой в миллионы оттенков. Сервер OpenGL, прежде чем приступать к работе, также должен определиться, на каком оборудовании ему придется работать. Это может быть скромная персоналка, а может быть и мощная графическая станция. Прежде чем получить контекст воспроизведения, сервер OpenGL должен получить детальные характеристики используемого оборудования. Эти характеристики хранятся в специальной структуре, тип которой — TPixelFormatDescriptor (описание формата пикселя). Формат пикселя определяет конфигурацию буфера цвета и вспомогательных буферов.

    Самый частый вопрос, который я получаю в связи с моими уроками, заключается в просьбе указать источники подробной информации об OpenGL на русском. К сожалению, если такие и есть, то мне они неизвестны. Главным нашим подручным станет поставляемый в составе Delphi файл помощи по OpenGL. Систему помощи Delphi для получения хороших результатов необходимо настраивать, если в помощи Delphi найти раздел по OpenGL, он не порадует обилием информации. В разных версиях Delphi настройка помощи выполняется по-разному, потребуются некоторые несложные манипуляции, но мы не будем тратить на это время. Будем использовать самый простой способ — контекстную помощь. Наберите в тексте модуля фразу «PixelFormatDescriptor», нажмите клавишу F1 и Вы получите подробную помощь об этом типе. Точно также мы будем получать помощь обо всех терминах, функциях и командах OpenGL.

    Итак, мы получили обширное описание структуры PixelFormatDescriptor. Обращаю внимание, что мы видим раздел помощи MicroSoft, рассчитанной на программистов С и С++, поэтому описание использует термины и стилистику именно этих языков. Так, по традиции Delphi имена типов начинаются с префикса T, но нам не удастся найти помощь по термину TPixelFormatDescriptor. К сожалению, это не единственное неудобство, которое нам придется испытывать. Например, если сейчас мы заглянем в файл windows.pas и найдем описание записи TPixelFormatDescriptor, мы обнаружим, что в файле помощи не указаны некоторые константы, а именно: PFD_SWAP_LAYER_BUFFERS, PFD_GENERIC_ACCELERATED и PFD_DEPTH_DONTCARE. А константа, названная PFD_DOUBLE_BUFFER_DONTCARE, по-видимому, соответствует константе, описанной в модуле windows.pas как PFD_DOUBLEBUFFER_DONTCARE. Наверное, более поздние версии помощи и заголовочного файла исправят этот и другие неточности.

    Итак, смысл структуры PixelFormatDescriptor — детальное описание графической системы, на которой происходит работа. Вас может озадачить дотошность этого описания, но, уверяю, особое внимание от нас из всего этого описания требует совсем немногое.

    В каталоге Beginner/1 Вы найдете проект OpenGL_min.dpr, в котором я привел описание всех полей структуры TPixelFormatDescriptor на русском, в момент их первоначального заполнения. Делается это в процедуре SetDCPixelFormat, вызываемой между получением ссылки на контекст устройства и созданием контекста воспроизведения OpenGL. Посмотрим подробнее, что там делается. Полям структуры присваиваются желаемые значения, затем вызовом функции ChoosePixelFormat осуществляется запрос системе, поддерживается ли на данном рабочем месте выбранный формат пикселя, и вызовом функции SetPixelFormat устанавливаем формат пикселя в контексте устройства. Функция ChoosePixelFormat возвращает индекс формата пикселя, который нам нужен в качестве аргумента функции SetPixelFormat.

    Заполнив поля структуры TPixelFormatDescriptor, мы определяемся со своими пожеланиями к графической системе, на которой будет происходить работа приложения, машина OpenGL подбирает наиболее подходящий к нашим пожеланиям формат, и устанавливает уже его в качестве формата пикселя для последующей работы. Наши пожелания корректируются применительно к реальным характеристикам системы. То, что машина OpenGL не позволит нам установить нереальный для конкретной машины формат пикселя, значительно облегчает нашу работу. Предполагая, что разработанное приложение будет работать на машинах разного класса, можно запросить «всего побольше», а уж OpenGL разберется на конкретной машине, каковы параметры и возможности оборудования, на котором сейчас будет происходить работа. На этом можно было бы и закончить разговор о формате пикселя, если бы мы могли полностью довериться выбору OpenGL.

    Обратим внимание на поле структуры «битовые флаги» — dwFlags. То, как мы зададим значение флагов, существенно может сказаться на работе нашего приложения, и наобум задавать эти значения не стоит. Тем более, что некоторые флаги совместно ужиться не могут, а некоторые могут присутствовать только в паре с другими. В этом примере флагам я присвоил значение PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL, то есть сообщаю системе, что я собираюсь осуществлять вывод в окно, и что моя система в принципе поддерживает OpenGL. Я ограничился всего двумя константами из обширного списка, приведенного в модуле windows.pas, по каждой из которых в файле помощи приведено детальное описание.

    Так, константа PFD_DOUBLEBUFFER включает режим двойной буферизации, когда вывод осуществляется не на экран, а в память, затем содержимое буфера выводится на экран. Это очень полезный режим, если в любом примере на анимацию убрать режим двойной буферизации и все команды, связанные с этим режимом, хорошо будет видно мерцание при выводе кадра. Константу PFD_GENERIC_ACCELERATED имеет смысл устанавливать в случае, если компьютер оснащен графическим акселератором. Флаги, заканчивающиеся на «DONTCARE» , сообщают системе, что соответствующий режим может иметь оба значения, то есть PFD_DOUBLE_BUFFER_DONTCARE — запрашиваемый формат пикселя может иметь оба режима — одинарной и двойной буферизации. Со всеми остальными полями и константами я предоставляю Вам возможность разобраться самостоятельно, только замечу, что поле iLayerType, описанное в windows.pas типа Byte, может, согласно помощи, иметь три значения: PFD_MAIN_PLANE, PFD_OVERLAY_PLANE и PFD_UNDERLAY_PLANE, однако константа PFD_UNDERLAY_PLANE имеет значение -1, так что установить такое значение не удастся.

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

    В примере битовым флагам задаем все возможные значения одновременно, числовым полям задаем заведомо нереальное значение 64, и смотрим на выбор формата пикселя, сделанным OpenGL. Результат, который Вы получите — выбранный формат пикселя, я предсказать не смогу — он индивидуален для каждой конкретной конфигурации машины и текущих настроек. Возможно, Вы получите в результате, что режим двойной буферизации не будет установлен — напоминаю, многие флаги устанавливаются только в комбинации с другими определенными. Наше приложение позволяет менять параметры формата пикселя и устанавливать его заново. Чтобы видеть, что происходит воспроизведение, небольшая площадка на экране при каждом тестировании окрашивается случайным цветом, используя функции OpenGL. Поэкспериментируйте с этим приложением, например, определите комбинацию флагов для установления режима двойной буферизации. Посмотрите значение числовых полей формата при различной палитре экрана — 16, 24, 32 бита, но не 256 цветов. О выводе при палитре экрана в 256 цветов — отдельный разговор. Это приложение, в частности, дает ответ на вопрос — как определить, оснащен ли компьютер графическим акселератором. Повозившись с этим приложением, Вы найдете ответ на вопрос, на который я Вам ответить не смогу — как надо заполнить структуру TPixelFormatDescriptor для Вашего компьютера. Обратите внимание, что в коде я установил несколько проверок на отсутствие контекста воспроизведения, который может быть потерян по ходу работы любого приложения, использующего OpenGL — редкая, но возможная ситуация в штатном режиме работы системы и очень вероятная ситуация если, например, по ходу работы приложения менять настройки экрана.

    Минимальная программа OpenGL

    Теперь мы знаем все, что необходимо для построения минимальной программы, использующей OpenGL. Я привел два варианта этой программы — одна построена исключительно на функциях Windows API, другая использует библиотеку классов Delphi (проекты каталогов Beginner/1 и Beginner/2 соответственно).

    Взглянем на головной модуль второго проекта. При создании формы задаем формат пикселя, в качестве ссылки на контекст устройства используем значение Canvas.Handle формы. Создаем контекст воспроизведения OpenGL и храним в переменной типа HGLRC. При обработке события OnPaint устанавливаем контекст воспроизведения, вызываем функции OpenGL и освобождаем контекст. При завершении работы приложения удаляем контекст воспроизведения. Для полной академичности можно включить строки, проверяющие, получен ли контекст воспроизведения, и не теряется ли он по ходу работы. Признаком таких ситуаций является нулевое значение переменной hrc. В минимальной программе я просто окрашиваю окно в желтоватый оттенок. Получив помощь по команде glClearColor, Вы можете узнать, что аргументы ее — тройка вещественных чисел в интервале [0;1], задающих долю красного, зеленого и синего составляющих в цвете и еще один, четвертый аргумент, о котором мы поговорим чуть позднее. Этому аргументу я в примере задал значение 1.0. Вообще то, аргументы glClearColor, согласно помощи, имеют неведомый тип GLclampf. Для того, чтобы разобраться с этим типом, отсылаю к строке

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

    Строку нашей программы

    будем понимать как очистку экрана, фон при этом покрывается заданным цветом.

    Проект, построенный только на функциях API, надеюсь, сейчас стал более понятным. Вместо Canvas.Handle используем собственную переменную dc, в обработчике события WM_PAINT реализуем действия, которые Delphi при обычном подходе выполняет за нас. Напоминаю, что для лучшей устойчивости работы обработчик WM_PAINT следовало бы написать так:

    А в обработчике WM_DESTROY следует перед PostQuitMessage добавить строку:

    То есть все используемые ссылки необходимо освобождать, а после того, как они стали не нужны — удалять.

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

    Во всех своих примерах я приписал рекомендацию не запускать проекты, использующие OpenGL под управлением среды Delphi. Дело в том, что часто в таких ситуациях программа аварийно прерывается, выдавая сообщение «access violation -«. Это происходит и в случае самой аккуратной работы с контекстами, и не связано с небрежностью работы программы. Некоторые программисты вину за это возлагают на софтверные драйверы и рекомендуют обновить их. Некоторые утверждают, что дело в Windows 9X, и под NT этого не происходит. Возможно, Вы тоже ничего такого не замечали и не можете взять в толк, о чем я сейчас веду речь. У меня такие окошки вылетают через раз на одном и том же проекте, хотя откомпилированный модуль работает превосходно. Я полагаю, что если драйверы не «глюкуют», когда приложение работает без среды Delphi, дело не только в драйверах.

    Вывод на поверхность компонентов

    Теоретически функциями OpenGL возможно осуществлять вывод не только на поверхность формы, а и на поверхность любого компонента, если у него имеется свойство Canvas.Handle, для чего при получении контекста воспроизведения необходимо указывать именно его ссылку на контекст устройства, например, Image1.Canvas.Handle. Однако чаще всего это приводит к неустойчивой работе, вывод «то есть, то нет», хотя контекст воспроизведения присутствует и не теряется. Я советую Вам всегда пользоваться выводом исключительно на поверхность окна. OpenGL прекрасно уживается с визуальными компонентами, как видно из примера TestPFD, если же необходимо ограничить размер области вывода, для этого есть стандартные методы, о которых мы обязательно будем беседовать в будущем.

    Просто ради интереса приведу пример, когда вывод OpenGL осуществляется на поверхность панели, то есть компонента, не имеющего свойства Canvas. Для этого мы пользуемся тем, что панель имеет отдельное окно, вызываем функцию GetDC с аргументом Panel1.Handle.

    Точно также Вы можете выводить на поверхность любого компонента, имеющего свойство Handle, например, на поверхность обычной кнопки. Обязательно попробуйте сделать это.

    Для вывода на компонент класса TImage можете записать:

    и удалить строки BeginPaint и EndPaint, поскольку TImage не имеет свойства Handle, то есть не создает отдельного окна. Однако вывод на такие компоненты как раз отличается полной неустойчивостью, так что я не гарантирую Вам надежного положительного результата.

    Вообще, вместо использования Canvas.Handle лучше использовать самостоятельно полученную аналогичную величину, вместо обработки событий лучше использовать свои ловушки сообщений. Такой подход приводит к максимальной скорости и надежности работы приложения.

    В конце сегодняшнего разговора я хочу привести еще несколько проектов, появившихся за это время из под моего пера и дополняющих «ЖиЛистую Delphi».

    Статья Работа с OpenGL — Минимальная программа раздела Графика и Игры OpenGL может быть полезна для разработчиков на Delphi и FreePascal.

    Комментарии и вопросы

    Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.

    Илон Маск рекомендует:  Что такое код dbplus_savepos
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL