FPS Magazine Issue 13

29

description

FPS is a free and open source Russian e-zine mainly dedicated to development of computer games.

Transcript of FPS Magazine Issue 13

Page 1: FPS Magazine Issue 13

Нас читаютgcupru

Все для начинающегои профессионального

разработчика игр

xtreme3dnarodruСайт движка Xtreme3D

make-gamesruПортал создания игр

gamer-clubucozcomВсе для создания игр без

программированияи не только

mizzysticruКрупнейший

информационныйGame Maker портал

xbobratuaСоздание игр программ

музыки

portalgamenetruИгровой портал

gamesfpscreatoratuaСайт для помещений игр

и обсуждаловок

dapfusDesign And Programming

Forum

gameshakerukozruВсе для редактирования

и создания игр

esateruМультимедиа-сообщество

dogamesruМастерская игр

wwwmobkioskcomМобильный киоск

gamecreateruСоздай свою игру

igrostroenienetruИгровые движки и

ресурсы

rusgame-makerruРусское сообщество

Game Maker

В этом выпуске

BlenderPython и интерфейс Blender операторы3

Blender Настольная книга4

История 3D-графики в играхОт Worlfenstein до Crysis7

Дополненная реальностьAR-новости10

OpenCV11

Язык DШаблоны13

Трассировщик лучей на DСуперсэмплинг16

Neko и HaXeЭра скриптовых языков18

laquoКошмарraquo программистаСегфолты утечки памяти и прочее21

Модели освещенияОрен-Найар24

Как собрать пакет DebianИз личного опыта27

copy 2008-2011 Редакция журнала FPS Все названия и логотипы являютсяинтеллектуальной собственностью их законных владельцев и не используются вкачестве рекламы продуктов или услуг Редакция не несет ответственности задостоверность информации в статьях и надежность всех упоминаемыхURL-адресов Мнение редакции может не совпадать с мнением авторовматериаловМатериалы издания распространяются согласно условиям лицензии CreativeCommons Attribution Noncommercial Share Alike (CC-BY-NC-SA)Главный редактор Тимур ГафаровДизайн и верстка Тимур ГафаровПо вопросам сотрудничества обращаться по адресу clocktower89mailru илиgecko0307gmailcomОфициальный сайт журнала httpfps-magazinenarodru

httpfps-magazinenarodru mailtogecko0307gmailcom

13 11

- 3 -

Python и интерфейс Blender

Операторы

В предыдущем номере журнала мы рассмотрели основумодифицирования интерфейса Blender mdash расширение класса панелей(bpytypesPanel) и научились выводить на панель нужную нам информациюОднако реальное расширение интерфейса Blender невозможно безиспользования операторов Все действия и команды Blender реализованыкак операторы например оператор удаления объекта mdashbpyopsobjectdelete()

Оператор mdash это класс наследуемый от bpytypesOperator и вобязательном порядке содержащий метод execute (который собственно ивыполняется при вызове оператора) Оператор также имеет имя подкоторым он доступен для вызова

Вот простейший оператор печатающий в консоль строку laquoHelloworldraquo

import bpy

class CustomOperator(bpytypesOperator)

bl_label = Print Hello world

bl_idname = hello

def execute(self context)

print(Hello world)

return FINISHED

Так как в метод execute передается контекст который дает доступ кданным текущего проекта оператор можно использовать для любыхдействий mdash включая манипуляции с объектами геометрией объектовматериалами настройками Blender и тд

Графически оператор представлен в виде кнопки которую можнорасположить на панели Мы создадим новую панель и добавим на нее нашоператор

class ObjectButtonsPanel(bpytypesPanel)

bl_space_type = PROPERTIES

bl_region_type = WINDOW

bl_context = object

bl_label = My new panel

def draw(self context)

layout = selflayout

col = layoutcolumn()

coloperator(hello icon=WORLD_DATA)

Опциональный аргумент icon при вызове оператора (coloperator)указывает имя значка который нужно отобразить на кнопке слева от текстаПолный список всех доступных значков Blender вы можете найти вИнтернете

- 4 -

Blender Настольная книга

Трехмерная графика mdash прекрасная отрасль для развития навыковхудожника дизайнера и программиста Современные условия сделали еегораздо более доступной чем когда-либо Для того чтобы попробоватьсвои силы в этой сфере уже не обязательно обладатьспециализированными рабочими станциями суперкомпьютерами сложными дорогим программным обеспечением Благодаря стремительномуразвитию свободного ПО и формированию глобального информационногосообщества любой желающий сегодня может овладеть основами3D-графики и анимации В значительной степени это заслуга разработчиковсвободного пакета трехмерного моделирования Blender который смеломожно ставить в один ряд с 3D Studio Max Maya и прочимииндустриальными гигантами

В течение минувшего года пользователи Blender во всем мирегромкими апплодисментами встречали каждое обновление новой ветки 25Кому-то понравился новый интерфейс кого-то впечатлили нововведениякто-то оценил обновленный Python API Порталы и блоги посвященныеBlender начали переделывать контент под Blender 25 Наш журнал такжене остался в стороне mdash весь год мы публиковали статьи и уроки раскрываяхитрости работы в новой версии пакета Настало время подняться наступень выше редакция laquoFPSraquo рада сообщить о начале работы надкрупным проектом mdash полноценной электронной книгой посвященнойBlender 25

Издание будет озаглавлено laquoBlender Настольная книгаraquo Целеваяаудитория mdash начинающие пользователи Blender 25 (как перешедшие состарых версий так и начинающие знакомство с программой laquoс нуляraquo) Книгабудет оформлена в виде сборника статей охватывающих различныеаспекты работы в Blender и скомпонованных по принципу laquoот простого ксложномуraquo Планируется 10 больших глав по 3-6 статей в каждой

Ниже приведено ориентировочное содержание книги

Введение О Blender Blender Foundation и свободном ПО Установка Blender

Глава 1 Основы Blender Конфигурация интерфейса по умолчанию Основные горячие клавиши Базовые примитивы Трансформация объектов Вершины ребра и грани Материалы Цвет текстура отражаемость прозрачность Рендеринг статического изображения

Глава 2 Создание реалистичной сцены Камера Источники освещения Тени Отражение преломление рельеф Процедурные текстуры Настройки мира Цвет фона освещение среды туман звезды

Глава 3 Объекты Вершинное моделирование Основные инструменты Сплайновое моделирование Кривые Безье и NURBS Сплайны Модификаторы объектов Взаимосвязь между объектами Метаобъекты

Глава 4 Изображения Редактор UVизображений Развертка текстурных координат

- 5 -

Глава 5 Материалы и спецэффекты Симуляция атмосферы Подповерхностное рассеивание Многослойные текстуры Редактор узлов Композитинг Слои Многослойный рендеринг

Глава 6 Основы анимации Временная шкала Интерполяционныекривые Скелетная анимация Арматура костиразвесовка Рендеринг видеоклипа Монтаж фильма

Глава 7 Физика Система частиц Силовые поля Мягкие тела и ткань Симуляция жидкости Симуляция дыма

Глава 8 Скриптовый язык Python Основы Python Система расширений Blender Экспорт и импорт данных Модификация интерфейса Blender

Глава 9 Игровой движок Blender Редактор логики Игровые свойства Карты освещения нормалей AO Анимация персонажей Игровая физика Шейдеры Использование Python в игровом движке

Глава 10 Советы по работе над проектом Внешние и вложенные данные ссылки связывание Обмен данными Подключаемые движки рендеринга Сетевой рендеринг

Издание будет распространятся в формате PDF по лицензии CreativeCommons BY SA На подготовку текста книги мы отводим год затемнесколько месяцев на подготовку иллюстраций корректировку и верстку

К работе над книгой приглашаются все желающие На почтовый ящикредакции (clocktower89mailru или gecko0307gmailcom) принимаютсястатьи и материалы по любой из вышеперечисленных тем а также общиесоветы и предложения

Вы разрабатываете перспективный проект Открылиинтересный сайт Хотите laquoраскрутитьraquo свою команду илистудию Мы Вам поможем

Спецпредложение от laquoFPSraquo

laquoFPSraquo предлагает уникальную возможность совершенно БЕСПЛАТНОразместить на страницах журнала рекламу Вашего проекта При этом отВас требуется минимум

Соответствие рекламируемого общей тематике журнала Этоможет быть игра программное обеспечение для разработчиков какой-либодвижок или SDK а также любой другой ресурс в рамках игростроя (включаясайты по программированию графике звуку и тд) Заявки не отвечающиеэтому требованию рассматриваться не будут

Готовый баннер или рекламный лист Для баннеров приемлемоеразрешение 800x200 для рекламных листов mdash 1000x700 Формат mdash JPGили PNG Содержание mdash произвольное но не выходящее за рамкиобщепринятого и соответствующее грамматическим нормам Совет ксозданию рекламного листа рекомендуем отнестись ответственно Если неможете сами качественно оформить рекламу найдите подходящегохудожника laquoГолыйraquo текст без графики и оформления не принимается

Краткое описание Вашего проекта и mdash обязательно mdash ссылка насоответствующий сайт (рекламу без ссылки не публикуем)

Заявки на рекламу принимаются на почтовый ящик редакцииclocktower89mailru или лично главному редактору gecko0307gmailcom(просьба в качестве темы указывать laquoсотрудничество с FPSraquo а не простоlaquoрекламаraquo так как письмо может отсеять спам-фильтр)

Прикрепленные материалы (рекламный лист информация и пр) могутбыть как прикреплены к письму так и загружены на какой-либо надежныйсервер (убедительная просьба не использовать RapidShare DepositFiles идругие подобные файлохранилища mdash загружайте файлы на свой сайт илиftp-сервер и присылайте статические ссылки) Все материалы желательноархивировать в формате zip rar 7z targz tarbz2 или tarlzma

Форум АНИМАТОРОВ и ХУДОЖНИКОВvanimatoriucozruanimatorforum2x2ruСоздан для того чтобы поделиться опытом спользователями ndash у нас много статей и разделов У насможно отдохнуть поболтать найти друзей Здесь Васполностью обучат рисованию и анимации дадутдельные советы Также можно задать вопрос на любуютему Есть форумная валюта (можно купить толькофорумные товары снять деньги к сожалению нельзя)Вы можете поместить свою работу фотографию илипросто картинку в галереюЗаходите мы всегда будем Вам рады

РЕСУРСЫ для игр программ форумов и тдzacazzbordruПринимаются заказы на спрайты рисунки баннерымузыку SAMP-сервера и многое другоеЦены на рисунки вычисляются исходя из следующеготарифаизображение 1x1 ndash 1 руб 1х2 ndash 150 рубМузыка 1 минута ndash 300 рубSAMP-сервер один сервер ndash 100 руб

- 7 -

История 3D-графики в играх

Давным-давно когда воздух был чистым деревья - высокими анебезызвестная Корпорация еще не монополизировала рынокоперационных систем появились первые компьютерные игры

Естественно тогда трехмерной графикой даже и не пахло первыеигрушки были абсолютно плоскими и создавались в основном для игровыхавтоматов Затем появилась изометрия которой кстати до сих пор находятприменение в играх Но о трехмерной графике с которой знакомы мы свами задумались где-то в 80-х годах XX века хотя говорят уже в 70-хнекоторые энтузиасты работали с wireframe-каркасами Самой первойтрехмерной игрой использующей каркасную графику была Battlezone(Atari 1980 г) В дальнейшем же появились реализации работающие сзатенением граней правда по скорости они здорово уступали спрайтам иих использование могло быть оправдано только в случае когдаполигональных моделей было совсем немного Прародителем современных3D-игр считается I Robot от той же Atari (1983 г) В середине 80-хпоявилась первая игра линейки Microsoft Flight Simulator что вполнезакономерно рисовать надо только несколько самолетиков и плоскуюземлю Зато вовсю используется третье измерение Нужно ли говорить чтоигра пользовалась большой популярностью Чисто полигональные движкитогда практически не использовались наряду с полигональными моделямишироко применялись спрайты так что полного 3D еще не существовалоНаиболее ярким примером сочетания полигональных и спрайтовыхобъектов является игра Alone in the Dark (это уже 1992 год) Этатехнология применяется и сегодня хотя уже достаточно редко

В том же 1992 году стараниями небезызвестной компании id Softwareсвет увидел первый шутер от первого лица (FPS) - Wolfenshtein 3D Хотя насамом деле Wolfenshteinу предшествовала игра Catacomb Abyss нопочему-то она оказалась забыта игроками Впервые была примененаперспектива благодаря чему объекты уменьшались отдаляясь от игрокаВпервые (в отличие от Microsoft Flight Simulator или F-19) в этих играхприменяется текстурирование - вместо однотонных граней используютсямасштабируемые растровые изображения

Сердцем тогдашних компьютеров был 386-й процессор а видеокартыотвечали только за вывод на экран монитора непосредственно кадра непроводя никаких дополнительных вычислений Через год происходиточередной прорыв появляется Doom Теперь игрок перемещается пополностью трехмерному уровню правда при этом монстры по-прежнемуостаются спрайтовыми но все-таки эффект присутствия становитсядостаточно ощутимым игра на самом деле затягивает

Настоящий переворот в области игровой трехмерной графикипроисходит в 1996 году - выходит Quake от все той же id Software Теперьполностью полигональный движок становится реальностью появляетсямножество новых технологий например Z-буфер а текстурирование ужеподразумевается как нечто само собой разумеющееся Правда впервыеZ-буфер был опробован еще в Doom но теперь он становится стандартомКстати говоря незадолго до этого (1995 г) свои первые неуверенные шагиделает Game SDK разработанный Microsoft для Windows 95 По сути GameSDK - первенец в линейке DirectX В это же время получаетраспространение среди программистов графический стандарт OpenGL(разработчик - Silicon Graphics совместно с Sun Microsystems) изначальноразработанный для CAD-систем еще в 1992 году

Тогда же (точнее немного позднее - в 1997 году) появляются первыевидеокарты с 3D-ускорением - Voodoo Graphics от 3Dfx (представительпервого поколения видеокарт) Наряду с DirectX (в 1996 г выходит ужеDirectX 2) для написания игр с аппаратным ускорением трехмерной графикииспользуется интерфейс Glide все той же 3Dfx Надо ли говорить какойпопулярностью среди игроков (и разработчиков игр) пользовался3D-ускоритель адаптер мог обрабатывать до 1 миллиона треугольников и45 миллионов пикселей в секунду полностью брал на себя вычисленияотносящиеся к 3D-сцене Достаточно интересным было подключениеVoodoo к компьютеру так как 2D-часть на акселераторе полностьюотсутствовала для работы была необходима еще и обычная видеокартакоторая подключалась к ускорителю

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 2: FPS Magazine Issue 13

- 3 -

Python и интерфейс Blender

Операторы

В предыдущем номере журнала мы рассмотрели основумодифицирования интерфейса Blender mdash расширение класса панелей(bpytypesPanel) и научились выводить на панель нужную нам информациюОднако реальное расширение интерфейса Blender невозможно безиспользования операторов Все действия и команды Blender реализованыкак операторы например оператор удаления объекта mdashbpyopsobjectdelete()

Оператор mdash это класс наследуемый от bpytypesOperator и вобязательном порядке содержащий метод execute (который собственно ивыполняется при вызове оператора) Оператор также имеет имя подкоторым он доступен для вызова

Вот простейший оператор печатающий в консоль строку laquoHelloworldraquo

import bpy

class CustomOperator(bpytypesOperator)

bl_label = Print Hello world

bl_idname = hello

def execute(self context)

print(Hello world)

return FINISHED

Так как в метод execute передается контекст который дает доступ кданным текущего проекта оператор можно использовать для любыхдействий mdash включая манипуляции с объектами геометрией объектовматериалами настройками Blender и тд

Графически оператор представлен в виде кнопки которую можнорасположить на панели Мы создадим новую панель и добавим на нее нашоператор

class ObjectButtonsPanel(bpytypesPanel)

bl_space_type = PROPERTIES

bl_region_type = WINDOW

bl_context = object

bl_label = My new panel

def draw(self context)

layout = selflayout

col = layoutcolumn()

coloperator(hello icon=WORLD_DATA)

Опциональный аргумент icon при вызове оператора (coloperator)указывает имя значка который нужно отобразить на кнопке слева от текстаПолный список всех доступных значков Blender вы можете найти вИнтернете

- 4 -

Blender Настольная книга

Трехмерная графика mdash прекрасная отрасль для развития навыковхудожника дизайнера и программиста Современные условия сделали еегораздо более доступной чем когда-либо Для того чтобы попробоватьсвои силы в этой сфере уже не обязательно обладатьспециализированными рабочими станциями суперкомпьютерами сложными дорогим программным обеспечением Благодаря стремительномуразвитию свободного ПО и формированию глобального информационногосообщества любой желающий сегодня может овладеть основами3D-графики и анимации В значительной степени это заслуга разработчиковсвободного пакета трехмерного моделирования Blender который смеломожно ставить в один ряд с 3D Studio Max Maya и прочимииндустриальными гигантами

В течение минувшего года пользователи Blender во всем мирегромкими апплодисментами встречали каждое обновление новой ветки 25Кому-то понравился новый интерфейс кого-то впечатлили нововведениякто-то оценил обновленный Python API Порталы и блоги посвященныеBlender начали переделывать контент под Blender 25 Наш журнал такжене остался в стороне mdash весь год мы публиковали статьи и уроки раскрываяхитрости работы в новой версии пакета Настало время подняться наступень выше редакция laquoFPSraquo рада сообщить о начале работы надкрупным проектом mdash полноценной электронной книгой посвященнойBlender 25

Издание будет озаглавлено laquoBlender Настольная книгаraquo Целеваяаудитория mdash начинающие пользователи Blender 25 (как перешедшие состарых версий так и начинающие знакомство с программой laquoс нуляraquo) Книгабудет оформлена в виде сборника статей охватывающих различныеаспекты работы в Blender и скомпонованных по принципу laquoот простого ксложномуraquo Планируется 10 больших глав по 3-6 статей в каждой

Ниже приведено ориентировочное содержание книги

Введение О Blender Blender Foundation и свободном ПО Установка Blender

Глава 1 Основы Blender Конфигурация интерфейса по умолчанию Основные горячие клавиши Базовые примитивы Трансформация объектов Вершины ребра и грани Материалы Цвет текстура отражаемость прозрачность Рендеринг статического изображения

Глава 2 Создание реалистичной сцены Камера Источники освещения Тени Отражение преломление рельеф Процедурные текстуры Настройки мира Цвет фона освещение среды туман звезды

Глава 3 Объекты Вершинное моделирование Основные инструменты Сплайновое моделирование Кривые Безье и NURBS Сплайны Модификаторы объектов Взаимосвязь между объектами Метаобъекты

Глава 4 Изображения Редактор UVизображений Развертка текстурных координат

- 5 -

Глава 5 Материалы и спецэффекты Симуляция атмосферы Подповерхностное рассеивание Многослойные текстуры Редактор узлов Композитинг Слои Многослойный рендеринг

Глава 6 Основы анимации Временная шкала Интерполяционныекривые Скелетная анимация Арматура костиразвесовка Рендеринг видеоклипа Монтаж фильма

Глава 7 Физика Система частиц Силовые поля Мягкие тела и ткань Симуляция жидкости Симуляция дыма

Глава 8 Скриптовый язык Python Основы Python Система расширений Blender Экспорт и импорт данных Модификация интерфейса Blender

Глава 9 Игровой движок Blender Редактор логики Игровые свойства Карты освещения нормалей AO Анимация персонажей Игровая физика Шейдеры Использование Python в игровом движке

Глава 10 Советы по работе над проектом Внешние и вложенные данные ссылки связывание Обмен данными Подключаемые движки рендеринга Сетевой рендеринг

Издание будет распространятся в формате PDF по лицензии CreativeCommons BY SA На подготовку текста книги мы отводим год затемнесколько месяцев на подготовку иллюстраций корректировку и верстку

К работе над книгой приглашаются все желающие На почтовый ящикредакции (clocktower89mailru или gecko0307gmailcom) принимаютсястатьи и материалы по любой из вышеперечисленных тем а также общиесоветы и предложения

Вы разрабатываете перспективный проект Открылиинтересный сайт Хотите laquoраскрутитьraquo свою команду илистудию Мы Вам поможем

Спецпредложение от laquoFPSraquo

laquoFPSraquo предлагает уникальную возможность совершенно БЕСПЛАТНОразместить на страницах журнала рекламу Вашего проекта При этом отВас требуется минимум

Соответствие рекламируемого общей тематике журнала Этоможет быть игра программное обеспечение для разработчиков какой-либодвижок или SDK а также любой другой ресурс в рамках игростроя (включаясайты по программированию графике звуку и тд) Заявки не отвечающиеэтому требованию рассматриваться не будут

Готовый баннер или рекламный лист Для баннеров приемлемоеразрешение 800x200 для рекламных листов mdash 1000x700 Формат mdash JPGили PNG Содержание mdash произвольное но не выходящее за рамкиобщепринятого и соответствующее грамматическим нормам Совет ксозданию рекламного листа рекомендуем отнестись ответственно Если неможете сами качественно оформить рекламу найдите подходящегохудожника laquoГолыйraquo текст без графики и оформления не принимается

Краткое описание Вашего проекта и mdash обязательно mdash ссылка насоответствующий сайт (рекламу без ссылки не публикуем)

Заявки на рекламу принимаются на почтовый ящик редакцииclocktower89mailru или лично главному редактору gecko0307gmailcom(просьба в качестве темы указывать laquoсотрудничество с FPSraquo а не простоlaquoрекламаraquo так как письмо может отсеять спам-фильтр)

Прикрепленные материалы (рекламный лист информация и пр) могутбыть как прикреплены к письму так и загружены на какой-либо надежныйсервер (убедительная просьба не использовать RapidShare DepositFiles идругие подобные файлохранилища mdash загружайте файлы на свой сайт илиftp-сервер и присылайте статические ссылки) Все материалы желательноархивировать в формате zip rar 7z targz tarbz2 или tarlzma

Форум АНИМАТОРОВ и ХУДОЖНИКОВvanimatoriucozruanimatorforum2x2ruСоздан для того чтобы поделиться опытом спользователями ndash у нас много статей и разделов У насможно отдохнуть поболтать найти друзей Здесь Васполностью обучат рисованию и анимации дадутдельные советы Также можно задать вопрос на любуютему Есть форумная валюта (можно купить толькофорумные товары снять деньги к сожалению нельзя)Вы можете поместить свою работу фотографию илипросто картинку в галереюЗаходите мы всегда будем Вам рады

РЕСУРСЫ для игр программ форумов и тдzacazzbordruПринимаются заказы на спрайты рисунки баннерымузыку SAMP-сервера и многое другоеЦены на рисунки вычисляются исходя из следующеготарифаизображение 1x1 ndash 1 руб 1х2 ndash 150 рубМузыка 1 минута ndash 300 рубSAMP-сервер один сервер ndash 100 руб

- 7 -

История 3D-графики в играх

Давным-давно когда воздух был чистым деревья - высокими анебезызвестная Корпорация еще не монополизировала рынокоперационных систем появились первые компьютерные игры

Естественно тогда трехмерной графикой даже и не пахло первыеигрушки были абсолютно плоскими и создавались в основном для игровыхавтоматов Затем появилась изометрия которой кстати до сих пор находятприменение в играх Но о трехмерной графике с которой знакомы мы свами задумались где-то в 80-х годах XX века хотя говорят уже в 70-хнекоторые энтузиасты работали с wireframe-каркасами Самой первойтрехмерной игрой использующей каркасную графику была Battlezone(Atari 1980 г) В дальнейшем же появились реализации работающие сзатенением граней правда по скорости они здорово уступали спрайтам иих использование могло быть оправдано только в случае когдаполигональных моделей было совсем немного Прародителем современных3D-игр считается I Robot от той же Atari (1983 г) В середине 80-хпоявилась первая игра линейки Microsoft Flight Simulator что вполнезакономерно рисовать надо только несколько самолетиков и плоскуюземлю Зато вовсю используется третье измерение Нужно ли говорить чтоигра пользовалась большой популярностью Чисто полигональные движкитогда практически не использовались наряду с полигональными моделямишироко применялись спрайты так что полного 3D еще не существовалоНаиболее ярким примером сочетания полигональных и спрайтовыхобъектов является игра Alone in the Dark (это уже 1992 год) Этатехнология применяется и сегодня хотя уже достаточно редко

В том же 1992 году стараниями небезызвестной компании id Softwareсвет увидел первый шутер от первого лица (FPS) - Wolfenshtein 3D Хотя насамом деле Wolfenshteinу предшествовала игра Catacomb Abyss нопочему-то она оказалась забыта игроками Впервые была примененаперспектива благодаря чему объекты уменьшались отдаляясь от игрокаВпервые (в отличие от Microsoft Flight Simulator или F-19) в этих играхприменяется текстурирование - вместо однотонных граней используютсямасштабируемые растровые изображения

Сердцем тогдашних компьютеров был 386-й процессор а видеокартыотвечали только за вывод на экран монитора непосредственно кадра непроводя никаких дополнительных вычислений Через год происходиточередной прорыв появляется Doom Теперь игрок перемещается пополностью трехмерному уровню правда при этом монстры по-прежнемуостаются спрайтовыми но все-таки эффект присутствия становитсядостаточно ощутимым игра на самом деле затягивает

Настоящий переворот в области игровой трехмерной графикипроисходит в 1996 году - выходит Quake от все той же id Software Теперьполностью полигональный движок становится реальностью появляетсямножество новых технологий например Z-буфер а текстурирование ужеподразумевается как нечто само собой разумеющееся Правда впервыеZ-буфер был опробован еще в Doom но теперь он становится стандартомКстати говоря незадолго до этого (1995 г) свои первые неуверенные шагиделает Game SDK разработанный Microsoft для Windows 95 По сути GameSDK - первенец в линейке DirectX В это же время получаетраспространение среди программистов графический стандарт OpenGL(разработчик - Silicon Graphics совместно с Sun Microsystems) изначальноразработанный для CAD-систем еще в 1992 году

Тогда же (точнее немного позднее - в 1997 году) появляются первыевидеокарты с 3D-ускорением - Voodoo Graphics от 3Dfx (представительпервого поколения видеокарт) Наряду с DirectX (в 1996 г выходит ужеDirectX 2) для написания игр с аппаратным ускорением трехмерной графикииспользуется интерфейс Glide все той же 3Dfx Надо ли говорить какойпопулярностью среди игроков (и разработчиков игр) пользовался3D-ускоритель адаптер мог обрабатывать до 1 миллиона треугольников и45 миллионов пикселей в секунду полностью брал на себя вычисленияотносящиеся к 3D-сцене Достаточно интересным было подключениеVoodoo к компьютеру так как 2D-часть на акселераторе полностьюотсутствовала для работы была необходима еще и обычная видеокартакоторая подключалась к ускорителю

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 3: FPS Magazine Issue 13

- 4 -

Blender Настольная книга

Трехмерная графика mdash прекрасная отрасль для развития навыковхудожника дизайнера и программиста Современные условия сделали еегораздо более доступной чем когда-либо Для того чтобы попробоватьсвои силы в этой сфере уже не обязательно обладатьспециализированными рабочими станциями суперкомпьютерами сложными дорогим программным обеспечением Благодаря стремительномуразвитию свободного ПО и формированию глобального информационногосообщества любой желающий сегодня может овладеть основами3D-графики и анимации В значительной степени это заслуга разработчиковсвободного пакета трехмерного моделирования Blender который смеломожно ставить в один ряд с 3D Studio Max Maya и прочимииндустриальными гигантами

В течение минувшего года пользователи Blender во всем мирегромкими апплодисментами встречали каждое обновление новой ветки 25Кому-то понравился новый интерфейс кого-то впечатлили нововведениякто-то оценил обновленный Python API Порталы и блоги посвященныеBlender начали переделывать контент под Blender 25 Наш журнал такжене остался в стороне mdash весь год мы публиковали статьи и уроки раскрываяхитрости работы в новой версии пакета Настало время подняться наступень выше редакция laquoFPSraquo рада сообщить о начале работы надкрупным проектом mdash полноценной электронной книгой посвященнойBlender 25

Издание будет озаглавлено laquoBlender Настольная книгаraquo Целеваяаудитория mdash начинающие пользователи Blender 25 (как перешедшие состарых версий так и начинающие знакомство с программой laquoс нуляraquo) Книгабудет оформлена в виде сборника статей охватывающих различныеаспекты работы в Blender и скомпонованных по принципу laquoот простого ксложномуraquo Планируется 10 больших глав по 3-6 статей в каждой

Ниже приведено ориентировочное содержание книги

Введение О Blender Blender Foundation и свободном ПО Установка Blender

Глава 1 Основы Blender Конфигурация интерфейса по умолчанию Основные горячие клавиши Базовые примитивы Трансформация объектов Вершины ребра и грани Материалы Цвет текстура отражаемость прозрачность Рендеринг статического изображения

Глава 2 Создание реалистичной сцены Камера Источники освещения Тени Отражение преломление рельеф Процедурные текстуры Настройки мира Цвет фона освещение среды туман звезды

Глава 3 Объекты Вершинное моделирование Основные инструменты Сплайновое моделирование Кривые Безье и NURBS Сплайны Модификаторы объектов Взаимосвязь между объектами Метаобъекты

Глава 4 Изображения Редактор UVизображений Развертка текстурных координат

- 5 -

Глава 5 Материалы и спецэффекты Симуляция атмосферы Подповерхностное рассеивание Многослойные текстуры Редактор узлов Композитинг Слои Многослойный рендеринг

Глава 6 Основы анимации Временная шкала Интерполяционныекривые Скелетная анимация Арматура костиразвесовка Рендеринг видеоклипа Монтаж фильма

Глава 7 Физика Система частиц Силовые поля Мягкие тела и ткань Симуляция жидкости Симуляция дыма

Глава 8 Скриптовый язык Python Основы Python Система расширений Blender Экспорт и импорт данных Модификация интерфейса Blender

Глава 9 Игровой движок Blender Редактор логики Игровые свойства Карты освещения нормалей AO Анимация персонажей Игровая физика Шейдеры Использование Python в игровом движке

Глава 10 Советы по работе над проектом Внешние и вложенные данные ссылки связывание Обмен данными Подключаемые движки рендеринга Сетевой рендеринг

Издание будет распространятся в формате PDF по лицензии CreativeCommons BY SA На подготовку текста книги мы отводим год затемнесколько месяцев на подготовку иллюстраций корректировку и верстку

К работе над книгой приглашаются все желающие На почтовый ящикредакции (clocktower89mailru или gecko0307gmailcom) принимаютсястатьи и материалы по любой из вышеперечисленных тем а также общиесоветы и предложения

Вы разрабатываете перспективный проект Открылиинтересный сайт Хотите laquoраскрутитьraquo свою команду илистудию Мы Вам поможем

Спецпредложение от laquoFPSraquo

laquoFPSraquo предлагает уникальную возможность совершенно БЕСПЛАТНОразместить на страницах журнала рекламу Вашего проекта При этом отВас требуется минимум

Соответствие рекламируемого общей тематике журнала Этоможет быть игра программное обеспечение для разработчиков какой-либодвижок или SDK а также любой другой ресурс в рамках игростроя (включаясайты по программированию графике звуку и тд) Заявки не отвечающиеэтому требованию рассматриваться не будут

Готовый баннер или рекламный лист Для баннеров приемлемоеразрешение 800x200 для рекламных листов mdash 1000x700 Формат mdash JPGили PNG Содержание mdash произвольное но не выходящее за рамкиобщепринятого и соответствующее грамматическим нормам Совет ксозданию рекламного листа рекомендуем отнестись ответственно Если неможете сами качественно оформить рекламу найдите подходящегохудожника laquoГолыйraquo текст без графики и оформления не принимается

Краткое описание Вашего проекта и mdash обязательно mdash ссылка насоответствующий сайт (рекламу без ссылки не публикуем)

Заявки на рекламу принимаются на почтовый ящик редакцииclocktower89mailru или лично главному редактору gecko0307gmailcom(просьба в качестве темы указывать laquoсотрудничество с FPSraquo а не простоlaquoрекламаraquo так как письмо может отсеять спам-фильтр)

Прикрепленные материалы (рекламный лист информация и пр) могутбыть как прикреплены к письму так и загружены на какой-либо надежныйсервер (убедительная просьба не использовать RapidShare DepositFiles идругие подобные файлохранилища mdash загружайте файлы на свой сайт илиftp-сервер и присылайте статические ссылки) Все материалы желательноархивировать в формате zip rar 7z targz tarbz2 или tarlzma

Форум АНИМАТОРОВ и ХУДОЖНИКОВvanimatoriucozruanimatorforum2x2ruСоздан для того чтобы поделиться опытом спользователями ndash у нас много статей и разделов У насможно отдохнуть поболтать найти друзей Здесь Васполностью обучат рисованию и анимации дадутдельные советы Также можно задать вопрос на любуютему Есть форумная валюта (можно купить толькофорумные товары снять деньги к сожалению нельзя)Вы можете поместить свою работу фотографию илипросто картинку в галереюЗаходите мы всегда будем Вам рады

РЕСУРСЫ для игр программ форумов и тдzacazzbordruПринимаются заказы на спрайты рисунки баннерымузыку SAMP-сервера и многое другоеЦены на рисунки вычисляются исходя из следующеготарифаизображение 1x1 ndash 1 руб 1х2 ndash 150 рубМузыка 1 минута ndash 300 рубSAMP-сервер один сервер ndash 100 руб

- 7 -

История 3D-графики в играх

Давным-давно когда воздух был чистым деревья - высокими анебезызвестная Корпорация еще не монополизировала рынокоперационных систем появились первые компьютерные игры

Естественно тогда трехмерной графикой даже и не пахло первыеигрушки были абсолютно плоскими и создавались в основном для игровыхавтоматов Затем появилась изометрия которой кстати до сих пор находятприменение в играх Но о трехмерной графике с которой знакомы мы свами задумались где-то в 80-х годах XX века хотя говорят уже в 70-хнекоторые энтузиасты работали с wireframe-каркасами Самой первойтрехмерной игрой использующей каркасную графику была Battlezone(Atari 1980 г) В дальнейшем же появились реализации работающие сзатенением граней правда по скорости они здорово уступали спрайтам иих использование могло быть оправдано только в случае когдаполигональных моделей было совсем немного Прародителем современных3D-игр считается I Robot от той же Atari (1983 г) В середине 80-хпоявилась первая игра линейки Microsoft Flight Simulator что вполнезакономерно рисовать надо только несколько самолетиков и плоскуюземлю Зато вовсю используется третье измерение Нужно ли говорить чтоигра пользовалась большой популярностью Чисто полигональные движкитогда практически не использовались наряду с полигональными моделямишироко применялись спрайты так что полного 3D еще не существовалоНаиболее ярким примером сочетания полигональных и спрайтовыхобъектов является игра Alone in the Dark (это уже 1992 год) Этатехнология применяется и сегодня хотя уже достаточно редко

В том же 1992 году стараниями небезызвестной компании id Softwareсвет увидел первый шутер от первого лица (FPS) - Wolfenshtein 3D Хотя насамом деле Wolfenshteinу предшествовала игра Catacomb Abyss нопочему-то она оказалась забыта игроками Впервые была примененаперспектива благодаря чему объекты уменьшались отдаляясь от игрокаВпервые (в отличие от Microsoft Flight Simulator или F-19) в этих играхприменяется текстурирование - вместо однотонных граней используютсямасштабируемые растровые изображения

Сердцем тогдашних компьютеров был 386-й процессор а видеокартыотвечали только за вывод на экран монитора непосредственно кадра непроводя никаких дополнительных вычислений Через год происходиточередной прорыв появляется Doom Теперь игрок перемещается пополностью трехмерному уровню правда при этом монстры по-прежнемуостаются спрайтовыми но все-таки эффект присутствия становитсядостаточно ощутимым игра на самом деле затягивает

Настоящий переворот в области игровой трехмерной графикипроисходит в 1996 году - выходит Quake от все той же id Software Теперьполностью полигональный движок становится реальностью появляетсямножество новых технологий например Z-буфер а текстурирование ужеподразумевается как нечто само собой разумеющееся Правда впервыеZ-буфер был опробован еще в Doom но теперь он становится стандартомКстати говоря незадолго до этого (1995 г) свои первые неуверенные шагиделает Game SDK разработанный Microsoft для Windows 95 По сути GameSDK - первенец в линейке DirectX В это же время получаетраспространение среди программистов графический стандарт OpenGL(разработчик - Silicon Graphics совместно с Sun Microsystems) изначальноразработанный для CAD-систем еще в 1992 году

Тогда же (точнее немного позднее - в 1997 году) появляются первыевидеокарты с 3D-ускорением - Voodoo Graphics от 3Dfx (представительпервого поколения видеокарт) Наряду с DirectX (в 1996 г выходит ужеDirectX 2) для написания игр с аппаратным ускорением трехмерной графикииспользуется интерфейс Glide все той же 3Dfx Надо ли говорить какойпопулярностью среди игроков (и разработчиков игр) пользовался3D-ускоритель адаптер мог обрабатывать до 1 миллиона треугольников и45 миллионов пикселей в секунду полностью брал на себя вычисленияотносящиеся к 3D-сцене Достаточно интересным было подключениеVoodoo к компьютеру так как 2D-часть на акселераторе полностьюотсутствовала для работы была необходима еще и обычная видеокартакоторая подключалась к ускорителю

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 4: FPS Magazine Issue 13

- 5 -

Глава 5 Материалы и спецэффекты Симуляция атмосферы Подповерхностное рассеивание Многослойные текстуры Редактор узлов Композитинг Слои Многослойный рендеринг

Глава 6 Основы анимации Временная шкала Интерполяционныекривые Скелетная анимация Арматура костиразвесовка Рендеринг видеоклипа Монтаж фильма

Глава 7 Физика Система частиц Силовые поля Мягкие тела и ткань Симуляция жидкости Симуляция дыма

Глава 8 Скриптовый язык Python Основы Python Система расширений Blender Экспорт и импорт данных Модификация интерфейса Blender

Глава 9 Игровой движок Blender Редактор логики Игровые свойства Карты освещения нормалей AO Анимация персонажей Игровая физика Шейдеры Использование Python в игровом движке

Глава 10 Советы по работе над проектом Внешние и вложенные данные ссылки связывание Обмен данными Подключаемые движки рендеринга Сетевой рендеринг

Издание будет распространятся в формате PDF по лицензии CreativeCommons BY SA На подготовку текста книги мы отводим год затемнесколько месяцев на подготовку иллюстраций корректировку и верстку

К работе над книгой приглашаются все желающие На почтовый ящикредакции (clocktower89mailru или gecko0307gmailcom) принимаютсястатьи и материалы по любой из вышеперечисленных тем а также общиесоветы и предложения

Вы разрабатываете перспективный проект Открылиинтересный сайт Хотите laquoраскрутитьraquo свою команду илистудию Мы Вам поможем

Спецпредложение от laquoFPSraquo

laquoFPSraquo предлагает уникальную возможность совершенно БЕСПЛАТНОразместить на страницах журнала рекламу Вашего проекта При этом отВас требуется минимум

Соответствие рекламируемого общей тематике журнала Этоможет быть игра программное обеспечение для разработчиков какой-либодвижок или SDK а также любой другой ресурс в рамках игростроя (включаясайты по программированию графике звуку и тд) Заявки не отвечающиеэтому требованию рассматриваться не будут

Готовый баннер или рекламный лист Для баннеров приемлемоеразрешение 800x200 для рекламных листов mdash 1000x700 Формат mdash JPGили PNG Содержание mdash произвольное но не выходящее за рамкиобщепринятого и соответствующее грамматическим нормам Совет ксозданию рекламного листа рекомендуем отнестись ответственно Если неможете сами качественно оформить рекламу найдите подходящегохудожника laquoГолыйraquo текст без графики и оформления не принимается

Краткое описание Вашего проекта и mdash обязательно mdash ссылка насоответствующий сайт (рекламу без ссылки не публикуем)

Заявки на рекламу принимаются на почтовый ящик редакцииclocktower89mailru или лично главному редактору gecko0307gmailcom(просьба в качестве темы указывать laquoсотрудничество с FPSraquo а не простоlaquoрекламаraquo так как письмо может отсеять спам-фильтр)

Прикрепленные материалы (рекламный лист информация и пр) могутбыть как прикреплены к письму так и загружены на какой-либо надежныйсервер (убедительная просьба не использовать RapidShare DepositFiles идругие подобные файлохранилища mdash загружайте файлы на свой сайт илиftp-сервер и присылайте статические ссылки) Все материалы желательноархивировать в формате zip rar 7z targz tarbz2 или tarlzma

Форум АНИМАТОРОВ и ХУДОЖНИКОВvanimatoriucozruanimatorforum2x2ruСоздан для того чтобы поделиться опытом спользователями ndash у нас много статей и разделов У насможно отдохнуть поболтать найти друзей Здесь Васполностью обучат рисованию и анимации дадутдельные советы Также можно задать вопрос на любуютему Есть форумная валюта (можно купить толькофорумные товары снять деньги к сожалению нельзя)Вы можете поместить свою работу фотографию илипросто картинку в галереюЗаходите мы всегда будем Вам рады

РЕСУРСЫ для игр программ форумов и тдzacazzbordruПринимаются заказы на спрайты рисунки баннерымузыку SAMP-сервера и многое другоеЦены на рисунки вычисляются исходя из следующеготарифаизображение 1x1 ndash 1 руб 1х2 ndash 150 рубМузыка 1 минута ndash 300 рубSAMP-сервер один сервер ndash 100 руб

- 7 -

История 3D-графики в играх

Давным-давно когда воздух был чистым деревья - высокими анебезызвестная Корпорация еще не монополизировала рынокоперационных систем появились первые компьютерные игры

Естественно тогда трехмерной графикой даже и не пахло первыеигрушки были абсолютно плоскими и создавались в основном для игровыхавтоматов Затем появилась изометрия которой кстати до сих пор находятприменение в играх Но о трехмерной графике с которой знакомы мы свами задумались где-то в 80-х годах XX века хотя говорят уже в 70-хнекоторые энтузиасты работали с wireframe-каркасами Самой первойтрехмерной игрой использующей каркасную графику была Battlezone(Atari 1980 г) В дальнейшем же появились реализации работающие сзатенением граней правда по скорости они здорово уступали спрайтам иих использование могло быть оправдано только в случае когдаполигональных моделей было совсем немного Прародителем современных3D-игр считается I Robot от той же Atari (1983 г) В середине 80-хпоявилась первая игра линейки Microsoft Flight Simulator что вполнезакономерно рисовать надо только несколько самолетиков и плоскуюземлю Зато вовсю используется третье измерение Нужно ли говорить чтоигра пользовалась большой популярностью Чисто полигональные движкитогда практически не использовались наряду с полигональными моделямишироко применялись спрайты так что полного 3D еще не существовалоНаиболее ярким примером сочетания полигональных и спрайтовыхобъектов является игра Alone in the Dark (это уже 1992 год) Этатехнология применяется и сегодня хотя уже достаточно редко

В том же 1992 году стараниями небезызвестной компании id Softwareсвет увидел первый шутер от первого лица (FPS) - Wolfenshtein 3D Хотя насамом деле Wolfenshteinу предшествовала игра Catacomb Abyss нопочему-то она оказалась забыта игроками Впервые была примененаперспектива благодаря чему объекты уменьшались отдаляясь от игрокаВпервые (в отличие от Microsoft Flight Simulator или F-19) в этих играхприменяется текстурирование - вместо однотонных граней используютсямасштабируемые растровые изображения

Сердцем тогдашних компьютеров был 386-й процессор а видеокартыотвечали только за вывод на экран монитора непосредственно кадра непроводя никаких дополнительных вычислений Через год происходиточередной прорыв появляется Doom Теперь игрок перемещается пополностью трехмерному уровню правда при этом монстры по-прежнемуостаются спрайтовыми но все-таки эффект присутствия становитсядостаточно ощутимым игра на самом деле затягивает

Настоящий переворот в области игровой трехмерной графикипроисходит в 1996 году - выходит Quake от все той же id Software Теперьполностью полигональный движок становится реальностью появляетсямножество новых технологий например Z-буфер а текстурирование ужеподразумевается как нечто само собой разумеющееся Правда впервыеZ-буфер был опробован еще в Doom но теперь он становится стандартомКстати говоря незадолго до этого (1995 г) свои первые неуверенные шагиделает Game SDK разработанный Microsoft для Windows 95 По сути GameSDK - первенец в линейке DirectX В это же время получаетраспространение среди программистов графический стандарт OpenGL(разработчик - Silicon Graphics совместно с Sun Microsystems) изначальноразработанный для CAD-систем еще в 1992 году

Тогда же (точнее немного позднее - в 1997 году) появляются первыевидеокарты с 3D-ускорением - Voodoo Graphics от 3Dfx (представительпервого поколения видеокарт) Наряду с DirectX (в 1996 г выходит ужеDirectX 2) для написания игр с аппаратным ускорением трехмерной графикииспользуется интерфейс Glide все той же 3Dfx Надо ли говорить какойпопулярностью среди игроков (и разработчиков игр) пользовался3D-ускоритель адаптер мог обрабатывать до 1 миллиона треугольников и45 миллионов пикселей в секунду полностью брал на себя вычисленияотносящиеся к 3D-сцене Достаточно интересным было подключениеVoodoo к компьютеру так как 2D-часть на акселераторе полностьюотсутствовала для работы была необходима еще и обычная видеокартакоторая подключалась к ускорителю

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 5: FPS Magazine Issue 13

Вы разрабатываете перспективный проект Открылиинтересный сайт Хотите laquoраскрутитьraquo свою команду илистудию Мы Вам поможем

Спецпредложение от laquoFPSraquo

laquoFPSraquo предлагает уникальную возможность совершенно БЕСПЛАТНОразместить на страницах журнала рекламу Вашего проекта При этом отВас требуется минимум

Соответствие рекламируемого общей тематике журнала Этоможет быть игра программное обеспечение для разработчиков какой-либодвижок или SDK а также любой другой ресурс в рамках игростроя (включаясайты по программированию графике звуку и тд) Заявки не отвечающиеэтому требованию рассматриваться не будут

Готовый баннер или рекламный лист Для баннеров приемлемоеразрешение 800x200 для рекламных листов mdash 1000x700 Формат mdash JPGили PNG Содержание mdash произвольное но не выходящее за рамкиобщепринятого и соответствующее грамматическим нормам Совет ксозданию рекламного листа рекомендуем отнестись ответственно Если неможете сами качественно оформить рекламу найдите подходящегохудожника laquoГолыйraquo текст без графики и оформления не принимается

Краткое описание Вашего проекта и mdash обязательно mdash ссылка насоответствующий сайт (рекламу без ссылки не публикуем)

Заявки на рекламу принимаются на почтовый ящик редакцииclocktower89mailru или лично главному редактору gecko0307gmailcom(просьба в качестве темы указывать laquoсотрудничество с FPSraquo а не простоlaquoрекламаraquo так как письмо может отсеять спам-фильтр)

Прикрепленные материалы (рекламный лист информация и пр) могутбыть как прикреплены к письму так и загружены на какой-либо надежныйсервер (убедительная просьба не использовать RapidShare DepositFiles идругие подобные файлохранилища mdash загружайте файлы на свой сайт илиftp-сервер и присылайте статические ссылки) Все материалы желательноархивировать в формате zip rar 7z targz tarbz2 или tarlzma

Форум АНИМАТОРОВ и ХУДОЖНИКОВvanimatoriucozruanimatorforum2x2ruСоздан для того чтобы поделиться опытом спользователями ndash у нас много статей и разделов У насможно отдохнуть поболтать найти друзей Здесь Васполностью обучат рисованию и анимации дадутдельные советы Также можно задать вопрос на любуютему Есть форумная валюта (можно купить толькофорумные товары снять деньги к сожалению нельзя)Вы можете поместить свою работу фотографию илипросто картинку в галереюЗаходите мы всегда будем Вам рады

РЕСУРСЫ для игр программ форумов и тдzacazzbordruПринимаются заказы на спрайты рисунки баннерымузыку SAMP-сервера и многое другоеЦены на рисунки вычисляются исходя из следующеготарифаизображение 1x1 ndash 1 руб 1х2 ndash 150 рубМузыка 1 минута ndash 300 рубSAMP-сервер один сервер ndash 100 руб

- 7 -

История 3D-графики в играх

Давным-давно когда воздух был чистым деревья - высокими анебезызвестная Корпорация еще не монополизировала рынокоперационных систем появились первые компьютерные игры

Естественно тогда трехмерной графикой даже и не пахло первыеигрушки были абсолютно плоскими и создавались в основном для игровыхавтоматов Затем появилась изометрия которой кстати до сих пор находятприменение в играх Но о трехмерной графике с которой знакомы мы свами задумались где-то в 80-х годах XX века хотя говорят уже в 70-хнекоторые энтузиасты работали с wireframe-каркасами Самой первойтрехмерной игрой использующей каркасную графику была Battlezone(Atari 1980 г) В дальнейшем же появились реализации работающие сзатенением граней правда по скорости они здорово уступали спрайтам иих использование могло быть оправдано только в случае когдаполигональных моделей было совсем немного Прародителем современных3D-игр считается I Robot от той же Atari (1983 г) В середине 80-хпоявилась первая игра линейки Microsoft Flight Simulator что вполнезакономерно рисовать надо только несколько самолетиков и плоскуюземлю Зато вовсю используется третье измерение Нужно ли говорить чтоигра пользовалась большой популярностью Чисто полигональные движкитогда практически не использовались наряду с полигональными моделямишироко применялись спрайты так что полного 3D еще не существовалоНаиболее ярким примером сочетания полигональных и спрайтовыхобъектов является игра Alone in the Dark (это уже 1992 год) Этатехнология применяется и сегодня хотя уже достаточно редко

В том же 1992 году стараниями небезызвестной компании id Softwareсвет увидел первый шутер от первого лица (FPS) - Wolfenshtein 3D Хотя насамом деле Wolfenshteinу предшествовала игра Catacomb Abyss нопочему-то она оказалась забыта игроками Впервые была примененаперспектива благодаря чему объекты уменьшались отдаляясь от игрокаВпервые (в отличие от Microsoft Flight Simulator или F-19) в этих играхприменяется текстурирование - вместо однотонных граней используютсямасштабируемые растровые изображения

Сердцем тогдашних компьютеров был 386-й процессор а видеокартыотвечали только за вывод на экран монитора непосредственно кадра непроводя никаких дополнительных вычислений Через год происходиточередной прорыв появляется Doom Теперь игрок перемещается пополностью трехмерному уровню правда при этом монстры по-прежнемуостаются спрайтовыми но все-таки эффект присутствия становитсядостаточно ощутимым игра на самом деле затягивает

Настоящий переворот в области игровой трехмерной графикипроисходит в 1996 году - выходит Quake от все той же id Software Теперьполностью полигональный движок становится реальностью появляетсямножество новых технологий например Z-буфер а текстурирование ужеподразумевается как нечто само собой разумеющееся Правда впервыеZ-буфер был опробован еще в Doom но теперь он становится стандартомКстати говоря незадолго до этого (1995 г) свои первые неуверенные шагиделает Game SDK разработанный Microsoft для Windows 95 По сути GameSDK - первенец в линейке DirectX В это же время получаетраспространение среди программистов графический стандарт OpenGL(разработчик - Silicon Graphics совместно с Sun Microsystems) изначальноразработанный для CAD-систем еще в 1992 году

Тогда же (точнее немного позднее - в 1997 году) появляются первыевидеокарты с 3D-ускорением - Voodoo Graphics от 3Dfx (представительпервого поколения видеокарт) Наряду с DirectX (в 1996 г выходит ужеDirectX 2) для написания игр с аппаратным ускорением трехмерной графикииспользуется интерфейс Glide все той же 3Dfx Надо ли говорить какойпопулярностью среди игроков (и разработчиков игр) пользовался3D-ускоритель адаптер мог обрабатывать до 1 миллиона треугольников и45 миллионов пикселей в секунду полностью брал на себя вычисленияотносящиеся к 3D-сцене Достаточно интересным было подключениеVoodoo к компьютеру так как 2D-часть на акселераторе полностьюотсутствовала для работы была необходима еще и обычная видеокартакоторая подключалась к ускорителю

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 6: FPS Magazine Issue 13

- 7 -

История 3D-графики в играх

Давным-давно когда воздух был чистым деревья - высокими анебезызвестная Корпорация еще не монополизировала рынокоперационных систем появились первые компьютерные игры

Естественно тогда трехмерной графикой даже и не пахло первыеигрушки были абсолютно плоскими и создавались в основном для игровыхавтоматов Затем появилась изометрия которой кстати до сих пор находятприменение в играх Но о трехмерной графике с которой знакомы мы свами задумались где-то в 80-х годах XX века хотя говорят уже в 70-хнекоторые энтузиасты работали с wireframe-каркасами Самой первойтрехмерной игрой использующей каркасную графику была Battlezone(Atari 1980 г) В дальнейшем же появились реализации работающие сзатенением граней правда по скорости они здорово уступали спрайтам иих использование могло быть оправдано только в случае когдаполигональных моделей было совсем немного Прародителем современных3D-игр считается I Robot от той же Atari (1983 г) В середине 80-хпоявилась первая игра линейки Microsoft Flight Simulator что вполнезакономерно рисовать надо только несколько самолетиков и плоскуюземлю Зато вовсю используется третье измерение Нужно ли говорить чтоигра пользовалась большой популярностью Чисто полигональные движкитогда практически не использовались наряду с полигональными моделямишироко применялись спрайты так что полного 3D еще не существовалоНаиболее ярким примером сочетания полигональных и спрайтовыхобъектов является игра Alone in the Dark (это уже 1992 год) Этатехнология применяется и сегодня хотя уже достаточно редко

В том же 1992 году стараниями небезызвестной компании id Softwareсвет увидел первый шутер от первого лица (FPS) - Wolfenshtein 3D Хотя насамом деле Wolfenshteinу предшествовала игра Catacomb Abyss нопочему-то она оказалась забыта игроками Впервые была примененаперспектива благодаря чему объекты уменьшались отдаляясь от игрокаВпервые (в отличие от Microsoft Flight Simulator или F-19) в этих играхприменяется текстурирование - вместо однотонных граней используютсямасштабируемые растровые изображения

Сердцем тогдашних компьютеров был 386-й процессор а видеокартыотвечали только за вывод на экран монитора непосредственно кадра непроводя никаких дополнительных вычислений Через год происходиточередной прорыв появляется Doom Теперь игрок перемещается пополностью трехмерному уровню правда при этом монстры по-прежнемуостаются спрайтовыми но все-таки эффект присутствия становитсядостаточно ощутимым игра на самом деле затягивает

Настоящий переворот в области игровой трехмерной графикипроисходит в 1996 году - выходит Quake от все той же id Software Теперьполностью полигональный движок становится реальностью появляетсямножество новых технологий например Z-буфер а текстурирование ужеподразумевается как нечто само собой разумеющееся Правда впервыеZ-буфер был опробован еще в Doom но теперь он становится стандартомКстати говоря незадолго до этого (1995 г) свои первые неуверенные шагиделает Game SDK разработанный Microsoft для Windows 95 По сути GameSDK - первенец в линейке DirectX В это же время получаетраспространение среди программистов графический стандарт OpenGL(разработчик - Silicon Graphics совместно с Sun Microsystems) изначальноразработанный для CAD-систем еще в 1992 году

Тогда же (точнее немного позднее - в 1997 году) появляются первыевидеокарты с 3D-ускорением - Voodoo Graphics от 3Dfx (представительпервого поколения видеокарт) Наряду с DirectX (в 1996 г выходит ужеDirectX 2) для написания игр с аппаратным ускорением трехмерной графикииспользуется интерфейс Glide все той же 3Dfx Надо ли говорить какойпопулярностью среди игроков (и разработчиков игр) пользовался3D-ускоритель адаптер мог обрабатывать до 1 миллиона треугольников и45 миллионов пикселей в секунду полностью брал на себя вычисленияотносящиеся к 3D-сцене Достаточно интересным было подключениеVoodoo к компьютеру так как 2D-часть на акселераторе полностьюотсутствовала для работы была необходима еще и обычная видеокартакоторая подключалась к ускорителю

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 7: FPS Magazine Issue 13

- 8 -

Совместное использование 3D- и 2D-карт было существеннымнедостатком поэтому сразу после Voodoo Graphics выходит Voodoo Rushсочетающая в себе оба модуля Впрочем качество этой карты оставляложелать лучшего поэтому она не смогла завоевать признание игроков

Вскоре (1998 год) выходит игра Unreal (Epic Megagames) В играхиспользуются все более и более изощренные технологии (напримермикрофактурные текстуры и прозрачность) рынок видеокарт с3D-ускорением резко расширяется на арену выходят NVIDIA Maxtor S3 ачерез некоторое время и ATI Например еще в конце 1997-го nVidiaвыпускает первый видеоадаптер сочетающий в себе 2D- и 3D-ускорители ипри этом превосходящий по производительности Voodoo - NVIDIA Riva128

В конце того же 1998 года выходит DirectX 6 позволившийразработчикам использовать новые технологии stencil W-буфермультитекстурирование и многое другое 3D-технологии развиваются сневообразимой скоростью революция следует за революцией В конце1999 года выходит DirectX 7 - очередной прорыв На этот раз появляетсяаппаратный TampL (Transforms and Lighting) - модуль отвечающий запреобразование геометрии и аппаратный рассчет освещения За ускорение3D-графики отвечают видеокарты третьего поколения Постепенно оттесняя3Dfx лидером в производстве 3D-ускорителей становится NVIDIA Споявлением RivaTNT2 в 1999 году nVidia отказывается от поддержки APIGlide

Начало нового тысячелетия оказалось очень символичным на рубежевеков были практически переломлены основные принципы построениятрехмерной графики в видеокарте На смену фиксированному конвейеруприходит программируемый широкое распространение приобретаютшейдеры В конце 2000 года исчезает легендарная 3Dfx (компания былакуплена ее главным конкурентом - NVIDIA)

Итак для чего же были разработаны шейдеры Дело в том что впредыдущих поколениях за поддержку того или иного эффекта (напримертумана) отвечало ядро видеокарты а точнее его TCL-блок (TransformsClipping Lighting - трансформация отсечение и освещение) поэтомувведение новых эффектов происходило очень медленно - было необходимождать очередного поколения видеокарт в которых этот эффектподдерживается Кроме того нужно было постоянно расширять самграфический чип и переписывать драйвера что добавляло хлопотпроизводителям железа Вполне логичным шагом была заменафиксированного TCL-блока программируемым Если точнее то TCLзаменяется вершинным шейдером а кроме него существуют такжепиксельные шейдеры которые изменяют процесс обработки текстур Этозначит что каждый разработчик может контролировать процесс обработкивидеокартой данных о 3D-сцене и изменять его чтобы добавитькакой-нибудь новый визуальный эффект

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 8: FPS Magazine Issue 13

- 9 -

Именно версия поддерживаемых шейдеров становится основнымотличием между видеокартами следующих поколений шейдерыпоявляются в 3D-ускорителях четвертого поколения например NVIDIAGeForce 4 или ATI Radeon 8500 и поддерживаются в DirectX 8 Следующеепоколение - вершинный и пиксельный шейдеры версии 20 и DirectX 9Примерами видеокарт этого поколения являются ATI Radeon 9600 илиnVidia GeForce FX 5800 Бурное развитие языка программированияшейдеров высокого уровня для Direct3D и OpenGL 20 привело кпрактически полному отказу от использования ассемблера в описаниишейдеров Были разработаны специальные языки программированияшейдеров Cg от NVIDIA HLSL от Microsoft (впоследствии ставший частьюDirectX 9) и GLSL от SGI являющийся аналогом HLSL разработанным дляOpenGL

В эпоху DirectX 9 для соответствия спецификациям требовалась лишьподдержка шейдеров 20 Сами разработчики за три года laquoдодумалиraquoстолько что DirectX 90с и 90а отличались такими laquoмелочамиraquo как HDRновые типы фильтрации использование геометрических шаблонов и тд Ивсе это кардинальным образом смогло изменить реализм трехмернойграфики Однако отсутствие жесткой стандартизации на уровне API привелок тому что многие возможности пришлось снова поддерживать на уровнеприложений а это вылилось в проблемы с совместимостью потерипроизводительности и др

Пожалуй главное новшество положенное в основу DirectX 10 ndashмаксимальное недопущение laquoвольностейraquo со стороны производителей GPUиз-за специфики структуры нового набора шейдеров 40 В результатемногочисленные надстройки придуманные производителями ушли впрошлое Предусматривается использование полностью программируемыхуниверсальных шейдеров при отсутствии разделения на вершинные ипиксельные как это было раньше Также добавлен новый тип шейдеров ndashгеометрический промежуточный между вершинным и пиксельным Он даетвозможность производить манипуляции над уже определившимся массивомтреугольников после окончания работы вершинного шейдера и самоеглавное допускает произвольное изменение их геометрии

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 9: FPS Magazine Issue 13

- 10 -

AR-новости

ARToolworks Inc и Esperient Ltd выпустили СОВМЕСТНЫЙ ПРОЕКТна базе своих технологий ARToolkit и Esperient Creator Система CreatorAR по словам разработчиков объединяет простоту использованиясреды Esperient Creator и мощь технологий дополненной реальности подкапотом библиотеки ARToolkit

Creator AR работает в качестве плагина к Esperient Creatorпозволяющий использовать конструктор для разработки интерактивныхприложений с применением дополненной реальности Для созданияпростейших приложений даже не требуется программирование - CreatorAR полностью интегрируется в визуальный интерфейс Esperient Creator

Бен Воган (Ben Vaughan) администратор ARToolworks laquoЯ оченьдоволен что мы смогли объединить наши передовые технологии чтобысоздать новый продукт который будет полезен для наших клиентов Апростой в освоении инструментарий сделает технологию дополненнойреальности доступнее и позволит разработчикам создавать весьмаинтересные приложенияraquo

Для свободного скачивания доступна демонстрационная версияCreator AR полная версия для коммерческого использования стоит $1500

Корпорация Qualcomm объявила ПОБЕДИТЕЛЕЙ КОНКУРСАAugmented Reality Developer Challenge 2010 Первый приз ($125000)получила команда разработчиков из Литвы с игрой Paparazzi -симулятором папарацци где как ясно из названия перед игроком стоитзадача скрытой съемки звезд шоу-бизнеса Второе место ($50000)заняла фирма Defiant Development Pty Ltd (Австралия) представившаяInch High Stunt Guy - игру использующую дополненную реальность дляуправления трюковым мотоциклом На третьем месте ($25000) -разработчики из США с симулятором спасательного вертолета DangerCopter

Что общего у легендарной Mike Tysons Punch-Out на NES исверхсовременного игрового контроллера Microsoft Kinect Группа хакеровkinecthacksnet объединили две казалось бы совершенно несовместимыевещи недавно программисты ПРЕДСТАВИЛИ ВИДЕОРОЛИК которыйдемонстрирует возможность использования Kinect для распознаванияударов во всеми любимом боксерском симуляторе

Напомним что Kinect - это laquoконтроллер без контроллераraquo для Xbox360 разработанный компанией Microsoft Kinect позволяет пользователювзаимодействовать с приставкой через устные команды позы тела ипоказываемые объекты или рисунки Усилиями энтузиастов Kinectподружили с ПК в результате чего стало появляться множествооригнальных проектов с дополненной реальностью

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 10: FPS Magazine Issue 13

- 11 -

OpenCV

OpenCV mdash одна из наиболее популярных библиотек для работы сдополненной реальностью Это библиотека компьютерного зрения(computer vision) mdash набор алгоритмов для эффективной обработки ираспознавания графической информации в реальном времени OpenCVразработана корпорацией Intel и активно использует специфичныевозможности интеловских процессоров (в частности IPP mdash IntegratedPerformance Primitives) для оптимизации собственной работыБиблиотека кроссплатформенна распространяется по лицензии BSD

OpenCV находит широчайшее применение в самых разных сферахинформационных технологий включая трехмерные редакторы системыраспознавания лиц и жестов HCI компьютерные игры робототехникустереоскопию и многое другое Библиотека располагает множествомсредств для работы с изображениями (включая базовую обработкупреобразование цветовых режимов и тд) и потоком видеоданных (ввод изфайла или с камеры вывод в файл) В арсенале OpenCV mdash мощныесредства структурного анализа калибровки отслеживания движений ираспознавания объектов Кроме того библиотека позволяет вывестиизображение на экран и нарисовать простые геометрические фигуры длядемонстрации результатов вычислений В OpenCV даже предусмотреныбазовые функции пользовательского интерфейса (полосы прокруткиподдержка клавиатуры и мыши)

OpenCV состоит из следующих модулейcv mdash основные функцииcvaux mdash вспомогательные и экспериментальные функцииcxcore mdash структуры данных и линейная алгебраhighgui mdash функции GUI

OpenCV написана в основном на C но имеет интерфейсы и для другихязыков (C++ C Python Ruby Java) Мы рассмотрим работу с OpenCV напримере замечательного языка D mdash биндинг библиотеки к D можно скачатьс сайта журнала (fps-magazinenarodru) в разделе laquoФайловый архивraquo

Начнем с простого примера mdash вывода изображения с веб-камеры наэкран Объявляем основной модуль и импортируем функции OpenCV

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

Объявляем основную функцию

int main()

Объявляем служебные указатели и переменные

CvCapture capture = null

IplImage frame = null

int key = 0

Инициализируем веб-камеру

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 11: FPS Magazine Issue 13

- 12 -

Создаем окно для вывода видео

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

Стартуем бесконечный цикл который завершится если пользовательнажмет клавишу Q (не лучший вариант но для демонстрационных целейсойдет) В теле цикла принимаем с камеры очередной кадр изображения

while( true )

frame = cvQueryFrame( capture )

Если по каким-то причинам это не удается вызываем аварийноезавершение цикла (и соответственно всей программы)

if (frame) break

Если кадр передан удачно отображаем его в окне

cvShowImage(result frame)

Проверяем нажатие клавиши и закрываем цикл

key = cvWaitKey( 10 )

if (key == q) break

Закрываем окно выключаем камеру и завершаем работу приложения

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

В следующем номере журнала вы узнаете как laquoподружитьraquo OpenCV сOpenGL mdash такой тандем будет неплохой основой для разработки игр идругих интерактивных приложений с дополненной реальностью

module main

import stdstdio

import stdstring

import opencvcv

import opencvcvtypes

import opencvcxcore

import opencvhighgui

int main()

CvCapture capture = null

IplImage frame = null

int key = 0

capture = cvCreateCameraCapture( 0 )

if ( capture )

writeln( Cannot initialize webcamn )

return 1

cvNamedWindow( result CV_WINDOW_AUTOSIZE )

while( true )

frame = cvQueryFrame( capture )

if( frame ) break

cvShowImage( result frame )

key = cvWaitKey( 10 )

if (key == q) break

cvDestroyWindow( result )

cvReleaseCapture( ampcapture )

return 0

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 12: FPS Magazine Issue 13

- 13 -

Язык D Шаблоны

Одно из неоспоримых преимуществ языка D mdash мощнейшая системашаблонов Шаблоны в D реализованы лучше чем в C++ В этой статье яхочу показать несколько наиболее ярких примеров обобщенногопрограммирования на D

Простой шаблон объявляется следующим образом

template Foo(T)

void print(T t)

writeln(t)

Пример использования

Foointprint(10) выводит 10

Параметром шаблона может быть не только тип но и любое значение(через псевдоним)

template Foo(alias s)

void print()

writeln(hello s )

Пример использования

Fooworldprint() выводит строку laquohello worldraquo

Благодаря псевдонимам шаблон может вычислять значение во времякомпиляции Следующий шаблон возвращает квадрат числа

template sqr(alias n)

enum sqr = n n

Пример использования

int i = sqr16 переменной i присваивается значение 256

Другая категория шаблонов D mdash шаблоны функций

void Foo(T)(T t)

writeln(t)

Пример использования

Fooint(10) выводит 10

Аргументом шаблона функции может быть так называемый кортеж(tuple) mdash особая абстракция обладающая свойствами структуры и массиваКак и структура кортеж может содержать элементы разных типов Подобномассиву кортеж индексирует элементы mdash к ним можно обращатьсяпривычным оператором квадратных скобок

В следующем примере шаблон функции принимает аргумент типа autoref В нее можно передать любое количество аргументов любого типа mdash онибудут интерпретированы как кортеж Сама функция выводит сначалаколичество элементов кортежа затем первый элемент а затем перебираетвсе циклом foreach

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 13: FPS Magazine Issue 13

- 14 -

void Foo(T)(auto ref T x)

writeln(xlength)

writeln(x[0])

foreach(v x) writeln(v)

Пример использования

Foo( hello 10 0567f )

Самое интересное mdash можно объявлять литералы кортежей

template Tuple(E)

alias E Tuple

alias Tuple(3 7 c) t

Foo(t)

Кортеж однотипных элементов можно использовать дляинициализации массива

alias Tuple(4 2 10) t

int[] a = [t] все равно что [4 2 10]

Такой кортеж называется кортежем выражений (expression tuple) Естьтакже кортеж типов (type tuple)

alias Tuple(int float) TF

Его можно использовать как тип аргументов обычной функции

void Foo(TF tf)

writeln(tf)

Пример использования

Foo(1 05) выводит 105

Наконец кортеж можно генерировать из элементов структуры припомощи свойства tupleof

void setPosition(float x float y float z)

writeln(x y z)

struct Point

float x

float y

float z

Point p = 10 00 20

setPosition(ptupleof)

Кортеж mdash это не настоящий тип данных его следует рассматриватьчасть парадигмы обобщенного программирования Проще говоря кортежкак конструкция существует только во время компиляции программы Дляработы с динамическими данными в рантайме он разумеется не годится mdashна это есть другие средства Например для нахождения суммы чиселможно использовать такой шаблон

T sum(T)(T[] array)

T result = 0

foreach(v array) result+=v

return result

Пример использования

r = sum( 10 20 90 30 )

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 14: FPS Magazine Issue 13

- 15 -

Функция также принимает массив (как статический так идинамический)

int[] a = [10 20 90 30]

r = sum(a)

Другая важная концепция обобщенного программирования в D mdashпримесь (mixin) Примеси отчасти заменяют в D препроцессор Есть двавида примесей Первый mdash это шаблон примеси при помощи которогоможно вставлять (подмешивать) заранее написанный код в текущийконтекст

mixin template Foo()

int x = 5

Теперь

struct Bar

mixin Foo

все равно что

struct Bar

int x = 5

Шаблон примеси может быть параметризован

mixin template Foo(T)

T x = 5

mixin Foo(int)

Можно также подмешивать виртуальные функции в классы

mixin template Foo()

void func() writefln(Foofunc())

class Bar

mixin Foo

Другой тип примесей mdash примеси строк mdash используются длякомпиляции строк как обычного кода D Следующий пример генерируетструктуру по заданным параметрам

template GenStruct(string Name string M1)

const char[] GenStruct =

struct ~ Name ~

int ~ M1 ~

mixin(GenStruct(Foo bar))

Генерирует

struct Foo

int bar

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 15: FPS Magazine Issue 13

- 16 -

Трассировщик лучей на D Суперсэмплинг

Мы продолжаем разговор о трассировщиках лучей начатый вдвенадцатом номере журнала Специфика цифрового изображения mdashделение на дискретные однородные точки mdash при рендеринге примитивовсказывается в виде так называемого алиасинга mdash эффектаступенчатости линий и краев объектов Cпособы решения этойпроблемы имеют общее название антиалиасинг Один из методовантиалиасинга широко используемый при оффлайн-рендеринге mdashсуперсэмплинг

Сэмплом в компьютерной графике называют цветовую единицуизображения В большинстве случаев это то же самое что пиксельвидимый на экране mdash однако например при суперсэмплинге на экранвыводятся не все вычисленные сэмплы Суть этого метода проста длякаждого пикселя вычисляется не один а несколько сэмплов а в результатзаписывается их среднее арифметическое Вы можете представить себеэто так происходит рендеринг картинки в более высоком разрешениикоторая затем уменьшается до нужных размеров (так называемыйдаунсэмплинг) mdash при этом laquoлишниеraquo пиксели используются в качестведополнительных данных для усреднения цвета

Суперсэмплинг mdash достаточно ресурсоемкая техника требующая внесколько раз больше памяти и процессорного времени чем при простомдискретном рендеринге Поэтому сейчас все чаще используетсяадаптивный суперсэмплинг дополнительные сэмплы вычисляются толькодля тех пикселей которые находятся на границах резких переходов цветаДля каждого пикселя выбирается два-три сэмпла mdash если цветовая разницамежду ними невысока результат вычисляется только по ним в противномслучае вычисляются дополнительные сэмплы

Основная проблема суперсэмплинга mdash вопрос количества и позицийдополнительных сэмплов Ведь заранее неизвестно в каком месте пикселяпроизойдет резкая смена цвета Следовательно нужен laquoумныйraquo способвыбрать сэмплы Существуют несколько подходов к решению этоговопроса

Сетка Простейший алгоритм Пиксель однородно разбивается нанесколько субпикселей и сэмпл выбирается из центра каждого Основнойнедостаток алгоритма сетки mdash для достижения полного антиалиасинганеобходимо достаточно большое количество сэмплов (сетка 3x3 или выше)

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

Диск Пуассона Сэмплы выбираются тоже случайно mdash но спроверкой расстояний между точками В результате получается полноепокрытие обширной дискообразной области при сравнительно небольшомколичестве сэмплов К сожалению данный алгоритм малопригоден дляиспользования в графике реального времени

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

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 16: FPS Magazine Issue 13

- 17 -

Повернутая сетка Используется сетка 2х2 повернутая на заданныйугол Сэмплы таким образом не привязаны к вертикальной игоризонтальной осям что позволяет покрыть большее пространство принебольшом количестве сэмплов

Сетка Случайная выборка

Диск Пуассона Джиттер

Повернутая сетка

Приведу простую реализацию суперсэмплинга с алгоритмом сетки (наязыке D)

int samples = 4

for (int x=0 xltbufferwidth x++)

for (int y=0 yltbufferheight y++)

color[] supersamples

for (float sx=00f sxlt10f sx+=10fsamples)

for (float sy=00f sylt10f sy+=10fsamples)

ray cameraRay = new ray(

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy0)

cameraPosition +

vector3f(x-bufferwidth2+sx y-bufferheight2+sy1000)

)

color ssColor = здесь вычисляется цвет сэмпла

supersamples ~= ssColor

color resultColor = average(supersamples)

buffersetPixel(xyresultColor)

Функция average находит усредненный цвет на основании заданногомассива цветов Ее реализация зависит от способа кодирования цвета нов общем случае вычисляется нахождением среднего арифметического длявсех каналов (то есть необходимо найти сумму каналов и разделить наобщее количество элементов массива) Все вычисления производятся длячисел с плавающей запятой В псевдокоде это можно представитьследующим образом (для простоты предположим что в массиве 4элемента)

color result

resultr = (col[0]r + col[1]r + col[2]r + col[3]r)4

resultg = (col[0]g + col[1]g + col[2]g + col[3]g)4

resultb = (col[0]b + col[1]b + col[2]b + col[3]b)4

resulta = (col[0]a + col[1]a + col[2]a + col[3]a)4

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 17: FPS Magazine Issue 13

- 18 -

Neko и haXe Эра скриптовых языков

Молодое поколение программистов взращенное на Java и C в нашидни трудно удивить очередным скриптовым языком (а консерваторовlaquoсишниковraquo mdash и подавно) Но факт остается фактом компилируемыеязыки постепенно переходят в категорию laquoдля профессионаловraquo и laquoдляхакеровraquo а для решения прикладных задач все чаще используют Python

На волне этой тенденции возникают качественно новые идеи К ихчислу можно отнести haXe (httphaxeorg) mdash метаязык сверхвысокогоуровня абстракции Программы на нем не выполняются напрямую атранслируются в код для других языков На момент написания статьи haXeподдерживает трансляцию в C++ Flash JavaScript (HTML5) PHP и Neko (вразработке mdash поддержка Java) Впечатляющий потенциал такого подхода кпрограммированию заключается в том что можно выбрать наиболееподходящую платформу для эффективной эксплуатации программы безнеобходимости полного портирования кода

Основной платформой haXe является необычайно быстрый и гибкийскриптовый язык Neko В отличие от haXe Neko является языком сдинамической типизацией Он спроектирован не столько для удобстванаписания кода программистом сколько для автоматической генерации втом числе ndash трансляции с других языков Поэтому как правило компиляторNeko используется не сам по себе а в качестве бэкенда и виртуальноймашины для других языков Поэтому haXe и Neko рассматриваются вместекак единый набор интрументов

Возможности Neko обеспечиваются тремя китами

стандартный язык Neko

NXML

NekoML

Стандартный язык Neko чем-то напоминает Lua Его можноиспользовать для разработки прототипов собственных модулей Nekoобеспечивает простое и быстрое тестирование новых модулей посколькуне нужно применять объектно-ориентированные структуры и методы

Два других языка ndash это XML-подобный язык разметки NXML ифункциональный язык NekoML NXML спроектирован для автоматическойгенерации компиляторами Причина такого решения в том что в то времякак людям проще читать стандартные языки структуры XML гораздо прощедля автоматического разбора и навигации NXML также обеспечивает болеепростой способ включать отладочную информацию

А вот NekoML ndash совсем другая история Он следует стилюфункциональных языков семейства ML и схож с языком Objective CamlNekoML отлично подходит для создания компиляторов Компилятор Nekoизначално написанный на Objective Caml теперь тоже написан на NekoML исобирает сам себя Этот laquoзамкнутый кругraquo называется bootstrapping

Но вернемся к haXe laquoHello Worldraquo на этом языке будет выглядетьследующим образом

MyProgramhx

class MyProgram

static function main()

trace(Hello World)

Проект компилируется одной командой

haxe -main MyProgram -neko MyProgramn

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 18: FPS Magazine Issue 13

- 19 -

Полученный код можно выполнить на виртуальной машине Neko

neko MyProgramn

или собрать исполняемый файл скомпоновав байт-код Neko свиртуальной машиной

nekotools boot MyProgramn

haXe mdash объектно-ориентированный язык В отличие от того же LuaООП в нем реализуется не в виде прототипов а в виде классов Это роднитhaXe с С++ Классы haXe элегантно связаны с концепцией модулей этогоязыка mdash каждый модуль (файл исходного кода с расширением hx)объявляет одноименный класс который можно импортировать из другихмодулей Модули объединяются в пакеты которым соответствуют каталогис файлами hx

mathVectorhx

package math

class Vector

public function new()

MyProgramhx

import mathVector

var vec Vector = new Vector()

Любопытен подход haXe к типизации можно объявить переменную ноне указывать ее тип mdash компилятор автоматически определит тип припервом присваивании значения Нечто подобное есть в языке D (тип auto mdashно он работает только при объявлении с одновременным присваиванием)

var x значение не присвоено тип переменной x mdash Unknown

x = 3 присвоено значение типа Int тип переменной x mdash Int

Как и в других современных языках в haXe есть динамическиемассивы

Массив со статической инициализацией

var a ArrayltIntgt = [510100]

trace(a[1])

Массив с динамической инициализацией

var a ArrayltIntgt = []

apush(5)

apush(10)

apush(100)

trace(a[1])

Благодаря встроенным методам push и pop динамический массивможно использовать в качестве стека

Программа выводит 5

var a ArrayltIntgt = []

apush(5)

apush(10)

apop()

trace(a[alength-1])

Итерация элементов массива осуществляется при помощи операторовfor и in

for( i in 0alength )

trace(a[i])

for( i in a )

trace(i)

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 19: FPS Magazine Issue 13

- 20 -

Кроме того haXe поддерживает таблицы (анонимные объекты)

var abonent = name Alex number 2980035

trace(abonent)

И ассоциативные массивы (хэши)

var dict HashltStringgt = new HashltStringgt()

dictset(object sphere)

dictset(color blue)

for( i in dictiterator() )

trace(i)

Стандартная библиотека haXe реализует рефлексию mdash способностьобъектов получать метаданные о собственных свойствах и методах (а такжедобавлять новые свойства и методы)

var object MyClass = new MyClass()

ReflectsetField(objectfoofunction(text String)

trace(text)

)

ReflectcallMethod(object

Reflectfield(objectfoo)

[hello world])

Чтение и запись файлов mdash также не проблема

import nekoioFile

import nekoLib

var fileContents = FilegetContent(filetxt)

Libprintln(fileContents)

Благодаря поддержке динамических библиотек C на haXeNekoтеоретически можно писать полноценные программы с графическиминтерфейсом ненамного уступающие в плане производительностискомпилированным на С или С++ Для haXe уже существует ряд врапперовк популярным библиотекам которые можно найти на libhaxeorg КонечноhaXe mdash в значительной степени экспериментальная система и говорить ополном отказе от Python в пользу NekoVM для решения прикладных задачпока рановато Однако haXe имеет все шансы стать основнойвеб-платформой будущего mdash этот язык можно использовать например длястандартизации веб-приложений и создания единого для всехинтернет-сервисов сетевого API дискуссии о котором идут уже не первыйгод Очевидны также преимущества haXe при разработке онлайн-игр в томчисле mdash с использованием новейших возможностей современныхбраузеров (HTML5 WebGL и др)

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 20: FPS Magazine Issue 13

- 21 -

laquoКошмарraquo программистаЧеловеку свойственно ошибаться Поэтому частенько даже в самом

безошибочном на первый взгляд программном коде могут встретиться такназываемые семантические ошибки В отличие от синтаксических они неотлавливаются компилятором mdash код может быть скомпилирован но во времяработы вылетать с неожиданным laquosegmentation faultraquo Еще хуже еслипрограмма вызывает утечку памяти или даже сбой операционной системы Вэтой статье рассмотрены наиболее распространенные ошибки с которымисталкиваются программисты

Ошибка сегментации (англ segmentation fault или сокращённоsegfault) mdash ошибка программного обеспечения возникающая при попыткеобращения к недоступным для записи участкам памяти либо при попыткеизменения памяти запрещённым способом

Сегментная адресация памяти является одним из подходов куправлению и защите памяти в операционной системе Для большинствацелей она была вытеснена страничной памятью однако в документациях потрадиции используют термин laquoОшибка сегментацииraquo Некоторыеоперационные системы до сих пор используют сегментацию на некоторыхлогических уровнях а страничная память используется в качестве основнойполитики управления памятью

В UNIX-подобных операционных системах процесс обращающийся кнедействительным участкам памяти получает сигнал SIGSEGV В MSWindows такой процесс создаёт исключение STATUS_ACCESS_VIOLATIONи как правило запускает программу Dr Watson которая показываетпользователю окно с предложением отправить отчёт об ошибке в Microsoft

Вот пример кода ANSI C который приводит к ошибке сегментации наплатформах с защитой памяти

char s = hello world

s = H

Когда программа содержащая этот код скомпилирована строка laquohelloworldraquo размещается в секции программы с бинарной пометкой laquoтолько длячтенияraquo При запуске операционная система помещает её с другимистроками и константами в сегмент памяти предназначенный только длячтения После запуска переменная s указывает на адрес строки а попыткаприсвоить значение символьной константы H через переменную в памятиприводит к ошибке сегментации

Компиляция и запуск таких программ на OpenBSD 40 вызываетследующую ошибку выполнения

$ gcc segfaultc -g -o segfault

$ segfault

Segmentation fault

В отличие от этого gcc 411 на Linux возвращает ошибку ещё вовремя компиляции

$ gcc segfaultc -g -o segfault

segfaultc In function lsquomainrsquo

segfaultc4 error assignment of read-only location

Этот пример кода создаёт нулевой указатель и пытается присвоитьзначение по несуществующему адресу Это вызывает ошибки сегментацииво время выполнения программы на многих системах

int ptr = (int)0

ptr = 1

Ещё один способ вызвать ошибку сегментации заключается в томчтобы вызвать функцию main рекурсивно что приведёт к переполнениюстека

int main()

main()

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 21: FPS Magazine Issue 13

- 22 -

Утечка памяти (англ memory leak) mdash процесс неконтролируемогоуменьшения объёма свободной оперативной памяти связанный с ошибкамив работающих программах вовремя не освобождающих ненужные ужеучастки памяти или с ошибками системных служб контроля памяти

Рассмотрим следующий фрагмент кода на C++

1 char pointer = 0

2 for( int i = 0 i lt 10 i++ )

3 pointer = new char[100]

4

5 delete [] pointer

В этом примере на 3-й строке создается объект в динамическойпамяти Код на 3-й строке выполняется 10 раз причём каждый следующийраз адрес нового объекта перезаписывает значение хранящееся вуказателе pointer На 5-й строке выполняется удаление объекта созданногона последней итерации цикла Однако первые 9 объектов остаются вдинамической памяти и одновременно в программе не остаётсяпеременных которые бы хранили адреса этих объектов Те в 5-й строкеневозможно ни получить доступ к первым 9 объектам ни удалить их

Динамическая память является ограниченным ресурсом Управлениединамической памятью программы обычно осуществляется библиотекойязыка программирования которая сама работает поверх динамическойпамяти предоставляемой операционной системой Утечки памяти приводятк тому что потребление памяти программой неконтролируемо возрастает врезультате рано или поздно вступают в действие архитектурныеограничения среды исполнения (операционной системы виртуальноймашины ЭВМ) и тогда новое выделение памяти становится невозможнымВ этой ситуации в программе которая запрашивает память обычнопроисходит аварийная остановка Это может по стечению обстоятельствпроизойти и совсем с другой программой после того как программаподверженная утечкам потребит всю память ЭВМ

Существуют различные способы предотвращения утечек памяти

Отказ от динамической памяти Например FORTRAN-77полностью отказывается от применения механизмов динамическогораспределения памяти что исключает подобные ошибки но существенноограничивает функциональность программ

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

Сборка мусора Некоторые языки программирования (напримерOberon Java D языки платформы NET) предоставляют средствапозволяющие автоматически освобождать неиспользуемую память (такназываемые сборщики мусора англ garbage collectors) Сборщики мусорарешают также и проблему циклических ссылок но сборка мусора являетсяресурсоемкой операцией За использование подобных средств приходитсярасплачиваться быстродействием системы

Сборка мусора была изобретена Джоном Маккарти в 1959 году приразработке языка программирования Lisp структура которого делает ручноеуправление памятью крайне затруднительным

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

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 22: FPS Magazine Issue 13

- 23 -

Переполнение буфера (buffer overflow) mdash явление возникающеекогда компьютерная программа записывает данные за пределамивыделенного в памяти буфера Переполнение буфера обычно возникаетиз-за неправильной работы с данными полученными извне и памятью приотсутствии жесткой защиты со стороны подсистемы программирования(компилятор или интерпретатор) и операционной системы В результатепереполнения могут быть испорчены данные расположенные следом забуфером или перед ним

Переполнение буфера является наиболее популярным способомвзлома компьютерных систем так как большинство языков высокого уровняиспользуют технологию стекового кадра mdash размещение данных в стекепроцесса смешивая данные программы с управляющими данными (в томчисле адреса начала стекового кадра и адреса возврата из исполняемойфункции)

Переполнение буфера может вызывать аварийное завершение илизависание программы ведущее к отказу обслуживания (denial of serviceDoS) Отдельные виды переполнений например переполнение в стековомкадре позволяют злоумышленнику загрузить и выполнить произвольныймашинный код от имени программы и с правами учетной записи от которойона выполняется

Рассмотрим следующую программу на С Ее можно использовать длягенерации ошибок переполнения буфера Первый аргумент команднойстроки программа принимает как текст которым заполняется буфер

include ltstdiohgt

include ltstringhgt

int main(int argc char argv[])

char buffer[10]

if (argc lt 2)

fprintf(stderr ИСПОЛЬЗОВАНИЕ s строкаn argv[0])

return 1

strcpy(buffer argv[1])

return 0

Программу можно опробовать с несколькими разными строкамиСтроки размером в 9 или меньше символов не будут вызыватьпереполнение буфера Строки в 10 и более символов будут вызыватьпереполнение хотя это может и не приводить к ошибке сегментации

По материалам Википедии

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 23: FPS Magazine Issue 13

- 24 -

Модели освещения

Орен-Найар

BRDF (Bidirectional reflectance distribution function mdash двунаправленнаяфункция распределения отражений) описывает как свет отражаетсяили поглощается поверхностью в зависимости от разных углов падения

Существует три вида BRDF Упрощенная (без учета трассировки лучей) Гибридная (с трассировкой лучей) Измеренная (комплексная основанная на реальных измерениях)

Измеренная и гибридная BRDF как правило обеспечивают болеереалистичный результат чем упрощенная

Наиболее распространенные BRDF для моделирования диффузногоосвещения mdash Ламберт и Орен-Найар (Oren-Nayar) BRDF по Ламбертухорошо работает только для сравнительно гладких поверхностей В отличиеот нее модель Орена-Найара (авторы mdash Майкл Орен и Шри К Найар)основана на предположении что поверхность состоит из множествамикрограней освещение каждой из которых описывается модельюЛамберта Модель учитывает взаимное перекрытие (экранирование)затенение и переотражение между микрогранями

Орен-Найар имеет параметр для контроля шероховатостиповерхности (roughness) Этот параметр определяет сколько светаотразится назад в направлении источника света что являетсяхарактеристикой шероховатой бархатистой или запыленной поверхностиЧем чем выше шероховатость тем менее отчетливым становитсядиффузное отражение

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 24: FPS Magazine Issue 13

- 25 -

Формула Орена-Найара имеет вид

I=ILkdcos(θL)(A + Bmax(0cos(θvminusθL))sin (α) tan (β) )

где I mdash интенсивность отраженного света IL

mdash интенсивность точечногоисточника света k

d ndash коэффициент диффузного отражения θ

L - угол между

направлением света и нормалью к поверхности θV

ndash угол между нормальюи направлением на наблюдателя Параметры модели определяются последующим формулам

A=1minus05 σ2

σ2 + 033B=045 σ2

σ2 + 009

α =min(θLθV ) β =max(θLθV )

cosθL=(NL) cosθV=(NV )

где N mdash нормаль L mdash вектор направления на источник света V mdash векторнаблюдателя Параметр σ (задается в диапазоне [0 1]) отвечает зашероховатость поверхности чем он больше тем более шероховатойявляется поверхность Если σ = 0 (все микрограни расположены в однойплоскости) то A = 1 B = 0 и следовательно формула Орена-Найараупрощается до модели Ламберта

I=ILkdcos(θL)

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 25: FPS Magazine Issue 13

- 26 -

Реализация на GLSL

Вершинная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

void main(void)

gl_Position = ftransform()

V_eye = gl_ModelViewMatrix gl_Vertex

L_eye = gl_LightSource[0]position - V_eye

N_eye = vec4(gl_NormalMatrix gl_Normal 10)

V_eye = -V_eye

Фрагментная программа

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

float roughness = 085

void main()

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

float rs = roughness roughness

float A = 1 - 05 rs (rs + 033)

float B = 045 rs (rs + 009)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float NL = dot ( N L )

float NV = dot ( N V )

vec3 LProj = normalize ( L - N NL )

vec3 VProj = normalize ( V - N NV )

float cx = max ( dot ( LProj VProj ) 00 )

float cosAlpha = NL gt NV NL NV

float cosBeta = NL gt NV NV NL

float dx = sqrt ( ( 10 - cosAlpha cosAlpha )

( 10 - cosBeta cosBeta ) ) cosBeta

gl_FragColor = max ( 00 NL ) Cd (A + B cx dx)

gl_FragColora = 10

- предполагается что в приложении уже включены инастроены соответствующие параметры OpenGL (позицияисточника света свойства материала и др) Приведеннаяреализация в целях упрощения не учитывает интенсивностьисточника света Исходный код предоставлен какобщественное достояние (Public Domain) и может бытьиспользован безо всяких ограничений

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 26: FPS Magazine Issue 13

- 27 -

Как собрать пакет Debian

Debian mdash один из старейших фундаментальных дистрибутивовLinux который часто берется за основу для создания другихоперационных систем Если вы используете Ubuntu или Mint то вашасистема тоже является частью большого семейства Debian Несмотряна косметические различия все дистрибутивы этого семейства имеютодно сходство mdash они совместимы с Debian В первую очередь этокасается системы управления пакетами В Ubuntu можно устанавливатьпакеты из репозитория Debian и наоборот Поэтому само собойразумеется что подход к созданию пакетов Debian будет справедлив длявсех основанных на нем дистрибутивов

Однако что делать если вы не нашли нужных deb-пакетов ни в одномрепозитории Большинство пользователей привыкло в такой ситуациисобирать программы из исходников осуществляя установку штатнымисредствами сопутствующего make-файла (sudo configure ampamp make ampamp makeinstall) Однако линуксоид со стажем прекрасно понимает mdash таким образомпроисходит laquoзасорениеraquo системы бесхозными файлами Это собственно иесть проблема Windows 2 (первая проблема как известно вирусы)которую в Linux решают менеджеры пакетов В отличие от них вы современем можете забыть что уже установили а что mdash нет А винчестервсе-таки не резиновый Поэтому я призываю не торопиться с командойmake install и попробовать оформить свежесобранную программу ваккуратный пакет

В этой статье я привожу только основные моменты создание пакетадля помещения в официальные репозитории mdash это отдельная тема там кмэйнтейнеру выдвигаются очень строгие требования необходимособлюдать множество правил А вот для сборки личного пакета дляlaquoдомашнегоraquo использования большинство из этих правил знатьнеобязательно

Простейший пакет собирается в четыре этапа

1 Создайте новый каталог и назовите его mypackage_10-1_i386 гдеlaquomyprogramraquo mdash название пакета laquo10raquo mdash версия laquo1raquo mdash номер ревизии (тоесть вашей сборки пакета) и laquoi386raquo mdash архитектура CPU под которуюскомпилированы бинарные файлы в пакете Если пакет содержит файлыдля разработчиков (заголовочные файлы статические библиотекидокументацию) к названию пакета прибавляется laquo-devraquo Конечнопридерживаться этих соглашений вас никто не заставляет но так будетудобнее и для менеджера пакетов и для вас самих Например недавно ясобрал собственные пакеты для языка haXe haxe_206-1_i386libneko_181-1_i386 libneko-dev_181-1_i386 neko_181-1_i386

2 Поместите в этот каталог файлы программы повторяя структуруфайловой системы Linux То есть если файл libsomethingso долженустановиться в каталог usrlib то необходимо создать в нашем рабочемкаталоге папку usr а в ней mdash lib и скопировать в нее libsomethingso Наэтом этапе необходимо быть очень осторожным чтобы файлы неконфликтовали с уже существующими в системе (поскольку установкапакета запускается с правами root она и глазом не моргнув заменитсуществующие файлы новыми mdash а это ясное дело чревато фатальнымипоследствиями)

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 27: FPS Magazine Issue 13

- 28 -

3 Создайте в каталоге еще одну папку и назовите ее DEBIAN В нейсоздайте файл control следующего содержания (привожу пример из своегопакета)

Package haxeVersion 206-1Priority extraSection develMaintainer Timur Gafarov lttgafaroffgmailcomgtArchitecture i386Depends nekoProvides haxeDescription haXe languageWebsite httphaxeorg

Как видите ничего сложного Эта информация используется системойдля индексирования и каталогизации пакетов Она же выводится на экранпри установке пакета графическим инсталлятором (например GDebi)

4 Теперь перейдите в каталог двумя уровнями выше (то есть вкоторой находится папка mypackage_10-1_i386) и введите следующуюкоманду

dpkg-deb --build mypackage_10-1_i386

Будет собран пакет mypackage_10-1_i386deb

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian
Page 28: FPS Magazine Issue 13

Это все

Надеемся номер вышел интересным Если так поддержитеFPS Отправляйте статьи обзоры интервью и прочее на любыетемы касающиеся игр графики звука программирования и тд наclocktower89mailru или gecko0307mailru

Сборка от 132011python 252 (r25260911 Oct 5 2008 192449) [GCC 432]reportlab 25 svglib 063 svgmath 033 pygments 131

  • Содержание
  • Python и интерфейс Blender
  • Blender Настольная книга
  • История 3D-графики в играх
  • AR-новости
  • OpenCV
  • Язык D Шаблоны
  • Суперсэмплинг
  • Neko и haXe
  • laquoКошмарraquo программиста
  • Модели освещения
  • Как собрать пакет Debian