![]() |
Модераторы: Rickert |
![]() ![]() ![]() |
|
$tatic |
|
||||||||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 651 Регистрация: 28.1.2005 Репутация: 7 Всего: 22 |
Cтандартные классы JRE не поддерживают работу с OpenGL. Однако для Java уже можно насчитать множество библиотек для работы с трехмерной графикой. Среди них можно выделить такие как Java 3D, JOGL, LWJGL и sdljava. После некоторого исследования автору удалось выбрать среди них одну, которой и будет уделено внимание в статье. Но полезно было бы вкратце познакомиться и с остальными библиотеками.
Итак, Java 3D – старейшая библиотека для создания трехмерных приложений в Java. Она берет свое начало в далеком 1996 (!) году, когда такие монстры как Intel, Silicon Graphics, Apple и Sun в рамках проекта Fahrenheit (не путать с названием одноименной компьютерной игры) разработали API для описания сцен при помощи графов (scene graph-based API). В дальнейшем API было перенесено на платформу Java, а позже стало открытым. Java 3D – по сути платформонезависимый и высокоуровневый (рендеринг производится через OpenGL или DirectX), обладающий огромными возможностями мультимедийный интерфейс (многие вещи в DirectX даже не снились), – однако, и он не лишен многих недостатков. Во-первых, это его тяжеловесность, т.к. интерфейс библиотеки полностью абстрагирован от платформы. Отсюда вполне закономерная медленность. Кстати именно по этой причине Sun не рекомендует эту библиотеку для разработки игр. Во-вторых, вытекающая из первого недостатка трудность освоения – работа с библиотекой напоминает работу со вполне оформленным движком. И наконец, в-третьих, текущая версия (1.5), поскольку создана с отклонением от стандарта JSR-926, находится под лицензией JRL (Java Research License), что однозначно запрещает любую разработку программ на нем, как бесплатных, так и коммерческих. И если насчет первого типа программ еще можно «отмазаться» их созданием «для самообразования», то продать программу, использующую такую библиотеку, на законных основаниях нельзя. Конечно, как только Sun завершит стандартизацию версии 1.5, она перестанет быть ограниченной в использовании. Кстати надо упомянуть об аналогичной разработке Xith3D, позиционируемой как библиотека для создания игр, поскольку скорость ее работы значительно выше. JOGL (Java bindings for OpenGL), как и Java 3D, была создана корпорацией Sun. Однако она не граф-ориентирована и гораздо более низкоуровнева. По сути, это java-обертка вокруг интерфейса OpenGL 2.0, а следовательно для изучения можно использовать все книги и справочники по OpenGL, а также многочисленные примеры, в т.ч. из NVIDIA и ATI SDK, тем более что портирование кода из C++ будет довольно полезно в плане изучения. Но JOGL также предоставляет удобные классы для работы с текстурами и шейдерами, а кроме того, позволяет использовать и функционал графической (Java2D) и интерфейсной (AWT/Swing) части платформы, что может облегчить создание утилит с графическим интерфейсом (прикладных программ с визуализацией, редакторов для игр и т.п.). Лицензия библиотеки (BSD) никаким образом не запрещает ее использование как в бесплатных, так и в коммерческих программах. А кроме того, примеры по реализации алгоритмов на C/C++ для OpenGL практически аналогичны реализации для JOGL, что значительно облегчает ее дальнейшее использование в проектах. Кроме того, ходят слухи, что JOGL будет внедрен в состав Java 7 SE, а потому был еще более прост в использовании, т.к. не приходилось бы прилагать к приложению все версии нативных компонентов. LWJGL (LightWeight Java Game Library) – основной конкурент JOGL. В реальных приложениях LWJGL показывает даже несколько большую производительность, чем JOGL. Но у него есть очень неприятный минус – функции и константы OpenGL в нем искусственно разнесены на классы, поименованные согласно появлению функций в стандартах OpenGL (GL11, GL12, GL13 и т.д.) или его расширениях (ARBMultitexture, ARBFragmentProgram, EXTFramebufferMultisample и т.п.). В результате все функции и константы при их применении нуждаются в лишних и запутывающих префиксах, совершенно необоснованно перегружая код (например команда NVFramebufferMultisampleCoverage.glRenderbufferStorageMultsampleCoverageNV(...), а ведь здесь еще опущены параметры). В итоге вместо написания команд, программисту придется вспоминать, в каком стандарте была введена данная функция. Очевидно, что и чтение такого кода заметно усложняется. И второй недостаток библиотеки – для работы с текстурами (а конкретно, для загрузки файлов в буфер и из него в видеокарту) предполагается использовать стороннюю библиотеку DevIL (несмотря на то, что в поставку она входит). Однако на ее изучение тоже потребуется время. И наконец, sdljava – решение, основанное на известной в мире Linux кроссплатформенной библиотеке SDL. Последняя в базовом варианте очень похожа на сочетание DirectDraw + DirectInput и очень широко используется при написании игр (кстати, автор библиотеки является не последним человеком в знаменитой фирме Blizzard). Однако sdljava довольно слаба в плане поддержки OpenGL – реализована только базовая часть версии 1.1 без всяких расширений. Это довольно весомый аргумент не в пользу sdljava, ведь самых новомодных графических «вкусностей» мы напрочь лишены. Таким образом, складывая удобство, простоту, скорость и качество, можно прийти к выводу, что самой оптимальной библиотекой является JOGL, об использовании которой и будет идти речь далее. На момент написания данной статьи на официальном сайте JOGL (https://jogl.dev.java.net) можно найти сборки текущего релиза 1.0.0 (JSR-231) и сборки версии 1.1.0. Кроме того доступны «ночные» сборки 1.1.1. Т.к. в версию 1.1.0 был внесен ряд дополнений, то разумнее всего было бы использовать именно ее. Скачать ее можно, перейдя по ссылке Archived release and pre-release builds в секции Downloads. Далее следует последовательно перейти в папки Release Builds 2007 (естественно в будущем появятся новые версии) и JSR-231 1.1.0 – April 22. Следует выбрать архив для подходящей платформы (в любом архиве находятся платформонезависимые jogl.jar и gluegen-rt.jar, а также нативные JNI-библиотеки для данной платформы). Кроме того, желательно скачать также архив jogl-1.1.0-docs.zip с javadoc-документацией. Исходные коды и примеры необязательны. Все примеры по работе с библиотеками будут показаны для JDK-1.6.0 в среде разработки NetBeans IDE 5.5. Архив с библиотеками следует распаковать в любую папку на диске. Затем в NetBeans, для удобства дальнейшей работы, создаем новую библиотеку классов. Для этого заходим в меню Tools -> Library Manager. В окне менедежера нажимаем на кнопку New Library... Для нашей библиотеки даем название JOGL (можно задать любое, это не принципиально) и тип Class Libraries. Для новой библиотеки на закладке Classpath надо добавить архивы jogl.jar и gluegen-rt.jar, также желательно (при наличии) добавить документацию на закладке Javadoc. Теперь создадим новый проект типа Java Application. Дадим ему, для определенности, название jogl-example1; главный класс с точкой входа будет example.jogl1.GLFrame. В дереве созданного проекта (окно Projects) в узел библиотек Libraries добавляем используемую нами библиотеку JOGL (пункт Add Library... в контекстном меню). Поскольку JOGL использует JNI для вызова функций OpenGL, то виртуальной машине, в общем случае, необходимо будет указать путь к нативным библиотекам. Для этого при запуске приложения необходимо установить параметр java.library.path с помощью ключа -D виртуальной машины. Так, если нативные библиотеки для Windows находятся в папке C:\jogl\win, то ключ будет -Djava.library.path=C:\jogl\win\. Аналогично путь указывается и на других платформах. При этом, что самое важное, при использовании командных файлов для запуска приложения, путь может быть относителен. В NetBeans, для удобства запуска и отладки проекта встроенными средствами, данный ключ задается в свойствах проекта (Project Properties) в категории Run (поле VM Options). После проведения данных манипуляций можно приступать непосредственно к написанию программы. В JOGL рендеринг на экран реализуется через компоненты GLCanvas и GLJPanel. Первый является подклассом java.awt.Canvas и рассчитан на аппаратную акселерацию, полноэкранный эксклюзивный режим и прочие оптимизации для более быстрого рендеринга. GLJPanel, в свою очередь, наследует javax.swing.JPanel и рассчитан на тесную интеграцию с пользовательским интерфейсом Swing, но в ущерб производительности. Переопределим класс GLFrame как расширяющий java.awt.Frame и добавим в него код, создающий компонент контекста GL:
Здесь идет код обычного AWT-приложения. Все довольно просто и понятно, поэтому не будем останавливаться. Отметим только, что отключение автоматической перерисовки компонента сделано для ускорения работы приложения. Для управления рендерингом в JOGL использована событийная концепция. Интерфейс GLAutoDrawable, который реализуют GLCanvas и GLJPanel, позволяет подключить слушателя GLEventListener. Это довольно удобная концепция, позволяющая создать блочную модель рендеринга, а также легко применить при необходимости паттерн Model-View-Controller. Однако, для первого приложения ограничимся простым примером. Создадим класс Renderer, который будет реализовывать интерфейс GLEventListener. Среда NetBeans в данном случае может автоматически сделать реализацию необходимых методов, но это можно сделать и вручную. В результате получим следующий код:
Сразу же добавим экземпляр этого слушателя для объекта canvas в конструктор фрейма: canvas.addGLEventListener(new Renderer()); Методы полученного класса очень напоминают соответствующие функции при использовании GLUT в C/C++, разберем их подробнее. init – метод, вызываемый сразу же после инициализации контекста GL. Таким образом, в нем можно выполнить начальную настройку контекста GL, например установку источников света, переключение параметров вывода и т.п. Однако, данный метод может быть вызван несколько раз в течение работы приложения, если произошло повторное создание контекста, например при удалении и повторном вводе в иерархию компонентов объекта GLCanvas. display – основной метод, в котором, собственно, и проходит процесс рендеринга сцены (или ее части). Именно в нем размещаются все вызовы команд GL, отвечающие за отрисовку кадра. При этом методы display всех слушателей, добавленных в обработку событий, вызываются последовательно во время отрисовки каждого кадра, а после последнего метода автоматически вызывается смена буфера (если данное действие включено) для реализации двойной буферизации. Метод reshape вызывается при первой отрисовке компонента, изменившего размер. Он может использоваться для настройки viewport'ов, при этом для удобства по умолчанию viewport устанавливается на весь экран (вызовом glViewport(x, y, width, height)), что упрощает работу разработчика. Последний метод – displayChanged – вызывается при смене графических параметров (графического режима или устройства вывода). Следует, однако, отметить что его реализация необязательна согласно JSR-231; в данной реализации метод также не реализован. В JOGL нет автоматического цикла рендеринга, а потому необходимо либо писать реализацию графического цикла вручную, либо использовать функционал стандартных утилитных классов Animator и FPSAnimator. Первый из них позволяет создать цикл рендеринга в отдельном потоке, причем между вызовами метода display интерфейса GLAutoDrawable (который в дальнейшем вызывает метод display слушателей GLEventListener) либо делается небольшая задержка, либо нет. Этим режимом управляет метод setRunAsFastAsPossible. Класс FPSAnimator отличается лишь тем, что позволяет задать частоту кадров при отрисовке, однако точное соблюдение этого значения не гарантируется. Добавим переменную для объекта аниматора в класс фрейма:
И создадим его экземпляр в конструкторе фрейма:
И здесь же запустим его:
Теперь перед написанием собственно графической части кода добавим в конструктор слушателя для события закрытия окна:
Остановка аниматора обязательна, т.к. в противном случае поток с циклом рендеринга не будет завершен и приложение зависнет в памяти, несмотря на то, что окно будет закрыто. Вот что должно получиться в результате (GLFrame.java):
Теперь можно попробовать запустить проект из среды командой Run Main Project (F6). Если все было сделано правильно, должно появиться пустое черное окно, которое должно корректно закрываться. Теперь попробуем нарисовать в нашем окне чайник. Перейдем к файлу Renderer.java и добавим в метод init настройку параметров GL, а в display отрисовку чайника. Получим в результате следующий код:
Видно, что использование функций OpenGL абсолютно прозрачно при знании классической реализации на C/C++. Необходимо лишь учитывать следующие моменты:
![]() Это сообщение отредактировал(а) $tatic - 2.7.2007, 18:10 |
||||||||||||||||
|
|||||||||||||||||
$tatic |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 651 Регистрация: 28.1.2005 Репутация: 7 Всего: 22 |
Данную статью просьба обсуждать здесь.
|
|||
|
||||
$tatic |
|
||||||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 651 Регистрация: 28.1.2005 Репутация: 7 Всего: 22 |
Очень полезной вещью при написании графической программы является счетчик кадров в секунду (FPS). Сейчас мы посмотрим, как можно сделать такой счетчик в идеологии «компонентной» модели JOGL. Надо сказать, что нам понадобится пример из первой части данной статьи.
Создадим новый класс FPSMeter, реализующий уже знакомый нам интерфейс GLEventListener. Мы разместим его в пакете example.jogl2, чтобы показать независимость от первого примера. Расчет FPS будем производить по следующему алгоритму: считаем кадры до тех пор, пока их суммарная продолжительность не составит секунду, запоминаем полученное число кадров в секунду, обнуляем число кадров и начинаем счет заново. Добавим для реализации данного алгоритма в класс FPSMeter 4 поля:
t0 и t1 – соответственно начальное и конечное время измеряемого отрезка в миллисекундах, frames – счетчик кадров, fps – полученное число кадров в секунду. В метод display, который будет вызываться каждый кадр, добавим код нашего алгоритма:
Теперь нам нужно показать измеренное число кадров в секунду на экране. Для этого воспользуемся замечательным классом TextRenderer из пакета com.sun.opengl.util.j2d. Он позволяет выводить заданный текст как в двухмерном, так и в трехмерном пространстве любыми шрифтами, поддерживаемыми Java. Для повышения скорости вывода в данном классе используется технология кэширования отрендеренных строк и упаковывания разных строк в единую текстуру. При этом пользоваться данным классом очень легко. Добавим в класс поле private TextRenderer textRenderer и добавим создание экземпляра данного класса в метод init:
В данном случае текст будет выводиться шрифтом по умолчанию, 20 точек в высоту. Теперь добавим в метод display код отрисовки текста в двухмерной системе координат:
Весь код отрисовки должен находиться в «скобках» beginRendering и endRendering. При этом необходимо определить систему координат текста. Левый нижний угол окна (а точнее, графического компонента GLCanvas) определяется как (0, 0), а правый верхний определяется параметрами beginRendering. В нашем случае единица измерения по осям абсцисс и ординат будет 1 пиксель. Следует отметить, что в методе draw необходимо указать координаты левого нижнего угла выводимого текста. Поэтому для вывода строки в левом верхнем углу мы вычитаем из высоты окна 20 (высоту шрифта). Отрисовка ведется желтым цветом, при этом фон текста прозрачный (включается режим GL_MODULATE). Вот что мы должны получить в результате:
На этом собственно создание компонента можно считать законченным. Теперь попробуем его отобразить. Для этого в конструктор класса example.jogl1.GLFrame после строки
добавим
и не забудем проверить импорт example.jogl2.FPSMeter (NetBeans предложит сделать его автоматически). Запускаем приложение и проверяем работу счетчика. Следует отметить, что поскольку код счетчика кадров практически не зависит от основного кода отрисовки (у автора наблюдалась ошибочная работа отрисовки текста при включенном режиме GL_TEXTURE_RECTANGLE), то его можно легко применять без изменений в другом проекте. Получается своего рода графический компонент. Отключается он, как и любой слушатель, соответствующим методом removeGLEventListener. С помощью нескольких классов, реализующих GLEventListener, можно разграничить код рендеринга (в случае игры это может быть основной рендер мира, рендеринг HUD и т.п.), что позволит полнее использовать объектно-ориентированный подход и паттерны проектирования. |
||||||||||||||
|
|||||||||||||||
![]() ![]() ![]() |
Правила форума "Программирование игр, графики и искуственного интеллекта" | |
|
НА ЗЛОБУ ДНЯ: Дорогие посетители, прошу обратить внимание что новые темы касающиеся новых вопросов создаются кнопкой "Новая тема" а не "Ответить"! Любые оффтопиковые вопросы, заданные в текущих тематических темах будут удалены а их авторы, при рецедиве, забанены.
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rickert. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Программирование игр, графики и искусственного интеллекта | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |