28

FPS Magazine Issue 15

Embed Size (px)

DESCRIPTION

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

Citation preview

Нас читают

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

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

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

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

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

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

mizzysticruКрупнейший

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

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

музыки

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

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

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

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

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

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

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

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

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

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

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

Game Maker

gaconucozruCайт посвященный

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

gameoxnullnetРазработка игрна конструкторе

Game Maker

bigslava3dnruСообщество

творческих людей

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

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

Blender 25+Netrender кластерный рендеринг3

Язык DСтиль D7

Шаблоны Часть II9

Перегрузка операторов12

Шаблоны проектированияSingleton Плюсы и минусы14

Мой язык - лучшийЗаблуждения в программировании17

Вечный вопросПробелы против табуляции19

Что такое QR-кодЭти странные квадратики21

Модели освещенияCook-Torrance24

Шейдеры на все случаи жизниToon Shading на GLSL27

15 11

httpfpsmagzymichostcom mailtogecko0307gmailcom

- 3 -

BlenderNetrender

КЛАСТЕР ndash это набор вычислительных узловсамостоятельных компьютеров связанных высокоскоростнойсетью и объединенных в логическое целое специальнымпрограммным обеспечением Фактически простейший кластерможно собрать из нескольких персональных компьютеровнаходящихся в одной локальной сети просто установив на нихсоответствующее ПО Традиционно для создания кластеровиспользуется Linux (более 70 систем) и другие разновидностиUnix (оставшиеся 30)

В чем идея подобного объединения Кластеры какправило ассоциируются с суперкомпьютерами круглые суткирешающими какую-нибудь сверхбольшую задачу но напрактике существует и множество куда более laquoприземленныхraquoкластерных применений Часто встречаются кластеры вкоторых одни узлы дублируя другие готовы в любой моментперехватить управление или одни узлы проверяя получаемыес другого узла результаты радикально повышают надежностьсистемы Еще одно популярное применение кластеров ndashрешение задачи массового обслуживания когда серверуприходится отвечать на большое количество независимыхзапросов Такую систему обычно называют laquoсервернойфермойraquo

Большинство суперкомпьютеров в мире построено наоснове концепции параллельных вычислений Большаявычислительная мощность достигается путем сложениямощностей отдельных вычислителей на задачах которыеможно хорошо разделить между этими вычислителямиНапример знаменитый Deep Blue который выиграл в шахматыу Каспарова представляет собой объединение несколькихсотен процессоров RS6000 (подробнее о Deep Blue и другихшахматных компьютерах читайте в laquoFPSraquo 12 10)

Многие голливудские компании занимающиесямультипликацией например Pixar и Industrial Light and Magicиспользуют кластеры компьютеров для рендерингаПросчитанные по сети предпросмотры и кэшированиеускоряют процесс рендеринга в целом от старта к финишуКластер предназначенный для рендеринга компьютернойграфики ndash сеть распределенного рендеринга ndash получилназвание laquoрендер-фермаraquo (renderfarm)

Все крупные профессиональные пакеты для работы с3D-графикой имеют встроенную поддежку рендер-ферм (вчастности распределенный рендеринг имеется в Vray и MentalRay) Blender также не остался в стороне Сетевой рендеринг вBlender 25 реализован в качестве плагина (Add-Ons gt Render gtNetwork Renderer) ndash в версии 258 он помечен как стабильныйно находящийся на стадии активной разработки

Принцип следующий на одной машине вы запускаете такназываемый master-сервер а на всех остальных ndashslave-серверы

- 4 -

1 На главной машине запустите master-сервер активируйтеплагин переключите движок рендеринга на Network RendererВ качестве режима операции выберите Master

2 Нажмите Start Service Строка статуса рендеринга будетотображать действия сервера Остановить его работу можнонажатием клавиши Esc

3 На всех остальных машинах кластера запуститеslave-сервер активируйте плагин переключите движокрендеринга на Network Renderer В качестве режима операциивыберите Slave

- 5 -

4 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Нажмите Start ServiceСтрока статуса рендеринга будет отображать действиясервера Остановить его работу можно нажатием клавиши Esc

5 На том компьютере где находится ваш проект запуститеклиентский процесс измените настройки рендерингасохраните blend-файл активируйте плагин переключитедвижок рендеринга на Network Renderer В качестве режимаоперации выберите Client

6 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Отправьте задачу навыполнение кнопкой Send Job

Теперь вы можете использовать комбинацию Ctrl+F12чтобы отрендерить анимацию на кластере Готовые кадрыбудут появлятся автоматически Прирост скорости рендерингабудет обратно пропорционален количеству slave-серверов

Можно также запустить серверы в консольном режимеСохраните master-сервер в файл blend и запускайте командой

$ blender -b masterblend -a

Аналогично ndash для slave-сервера

$ blender -b slaveblend -a

- 6 -

OpenGL 429 АВГУСТА 2011 г организация Khronos Group

представила обновленную версию спецификации OpenGL42 и языка описания шейдеров GLSL 420 Новая версияспецификации обратно совместима с предыдущимиверсиями OpenGL и содержит улучшенияподготовленные на основе пожеланий разработчиковграфических приложений и игр

Компания NVIDIA выпустила тестовую версиюпроприетарных видеодрайверов с поддержкой OpenGL42 сразу после публикации спецификации Драйверполностью поддерживает OpenGL 42 для карт NVIDIAGeForce 400500 (Fermi) и доступен для платформWindows Solaris Linux и FreeBSD Компания AMDсообщила о намерении выпустить в ближайшие днибета-версию драйверов AMD Catalyst с поддержкойOpenGL 42

Поддержка OpenGL 42 в свободной библиотеке Mesaпока не планируется в обозримом будущем В настоящеевремя в Mesa 3D полностью обеспечена поддержкаOpenGL 21 и частично OpenGL 30 довести до концаработу над поддержкой всех возможностей OpenGL 30планируется к концу года

Из добавленных в OpenGL 42 улучшений можноотметить

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

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

- Поддержка изменения произвольной части сжатойтекстуры без повторной загрузки в GPU текстурыцеликом что позволяет добиться существенного ростапроизводительности

- Поддержка упаковки нескольких 8- и 16-разрядныхзначений в одно 32-разрядное значение для эффективнойобработки шейдеров cо значительным сокращениемиспользуемого объема памяти и повышением пропускнойспособности Например подобная упаковка особеннополезна для организации передачи данных междуразличными стадиями выполнения шейдера

- 7 -

КАК И ВО МНОГИХ других языках в D есть свой стильпрограммирования ndash ряд правил laquoхорошего тонаraquo дляграмотного читаемого кода Эти правила ни к чему непринуждают ndash вы разумеется вольны писать программыкак вам угодно Однако их рекомендуется соблюдать ndashособенно в том случае если с вашим кодом будутработать другие люди К примеру стиля Dпридерживаются библиотека Phobos и компилятор DMD

httpwwwdigitalmarscomd20dstylehtml

На каждую строку ndash не более одного утверждения

Вместо аппаратных знаков табуляции следуетиспользовать пробелы

Длина отступа ndash четыре пробела

Операторы отделяются от операндов пробелами

Тела функций отделяются двумя пустыми строками

Объявления переменных отделяются от утвержденийодной пустой строкой

Одно утверждение комментируется двумя косымичертами

statement comment

statement comment

Набор утверждений комментируется блоком

comment

comment

statement

statement

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 3 -

BlenderNetrender

КЛАСТЕР ndash это набор вычислительных узловсамостоятельных компьютеров связанных высокоскоростнойсетью и объединенных в логическое целое специальнымпрограммным обеспечением Фактически простейший кластерможно собрать из нескольких персональных компьютеровнаходящихся в одной локальной сети просто установив на нихсоответствующее ПО Традиционно для создания кластеровиспользуется Linux (более 70 систем) и другие разновидностиUnix (оставшиеся 30)

В чем идея подобного объединения Кластеры какправило ассоциируются с суперкомпьютерами круглые суткирешающими какую-нибудь сверхбольшую задачу но напрактике существует и множество куда более laquoприземленныхraquoкластерных применений Часто встречаются кластеры вкоторых одни узлы дублируя другие готовы в любой моментперехватить управление или одни узлы проверяя получаемыес другого узла результаты радикально повышают надежностьсистемы Еще одно популярное применение кластеров ndashрешение задачи массового обслуживания когда серверуприходится отвечать на большое количество независимыхзапросов Такую систему обычно называют laquoсервернойфермойraquo

Большинство суперкомпьютеров в мире построено наоснове концепции параллельных вычислений Большаявычислительная мощность достигается путем сложениямощностей отдельных вычислителей на задачах которыеможно хорошо разделить между этими вычислителямиНапример знаменитый Deep Blue который выиграл в шахматыу Каспарова представляет собой объединение несколькихсотен процессоров RS6000 (подробнее о Deep Blue и другихшахматных компьютерах читайте в laquoFPSraquo 12 10)

Многие голливудские компании занимающиесямультипликацией например Pixar и Industrial Light and Magicиспользуют кластеры компьютеров для рендерингаПросчитанные по сети предпросмотры и кэшированиеускоряют процесс рендеринга в целом от старта к финишуКластер предназначенный для рендеринга компьютернойграфики ndash сеть распределенного рендеринга ndash получилназвание laquoрендер-фермаraquo (renderfarm)

Все крупные профессиональные пакеты для работы с3D-графикой имеют встроенную поддежку рендер-ферм (вчастности распределенный рендеринг имеется в Vray и MentalRay) Blender также не остался в стороне Сетевой рендеринг вBlender 25 реализован в качестве плагина (Add-Ons gt Render gtNetwork Renderer) ndash в версии 258 он помечен как стабильныйно находящийся на стадии активной разработки

Принцип следующий на одной машине вы запускаете такназываемый master-сервер а на всех остальных ndashslave-серверы

- 4 -

1 На главной машине запустите master-сервер активируйтеплагин переключите движок рендеринга на Network RendererВ качестве режима операции выберите Master

2 Нажмите Start Service Строка статуса рендеринга будетотображать действия сервера Остановить его работу можнонажатием клавиши Esc

3 На всех остальных машинах кластера запуститеslave-сервер активируйте плагин переключите движокрендеринга на Network Renderer В качестве режима операциивыберите Slave

- 5 -

4 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Нажмите Start ServiceСтрока статуса рендеринга будет отображать действиясервера Остановить его работу можно нажатием клавиши Esc

5 На том компьютере где находится ваш проект запуститеклиентский процесс измените настройки рендерингасохраните blend-файл активируйте плагин переключитедвижок рендеринга на Network Renderer В качестве режимаоперации выберите Client

6 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Отправьте задачу навыполнение кнопкой Send Job

Теперь вы можете использовать комбинацию Ctrl+F12чтобы отрендерить анимацию на кластере Готовые кадрыбудут появлятся автоматически Прирост скорости рендерингабудет обратно пропорционален количеству slave-серверов

Можно также запустить серверы в консольном режимеСохраните master-сервер в файл blend и запускайте командой

$ blender -b masterblend -a

Аналогично ndash для slave-сервера

$ blender -b slaveblend -a

- 6 -

OpenGL 429 АВГУСТА 2011 г организация Khronos Group

представила обновленную версию спецификации OpenGL42 и языка описания шейдеров GLSL 420 Новая версияспецификации обратно совместима с предыдущимиверсиями OpenGL и содержит улучшенияподготовленные на основе пожеланий разработчиковграфических приложений и игр

Компания NVIDIA выпустила тестовую версиюпроприетарных видеодрайверов с поддержкой OpenGL42 сразу после публикации спецификации Драйверполностью поддерживает OpenGL 42 для карт NVIDIAGeForce 400500 (Fermi) и доступен для платформWindows Solaris Linux и FreeBSD Компания AMDсообщила о намерении выпустить в ближайшие днибета-версию драйверов AMD Catalyst с поддержкойOpenGL 42

Поддержка OpenGL 42 в свободной библиотеке Mesaпока не планируется в обозримом будущем В настоящеевремя в Mesa 3D полностью обеспечена поддержкаOpenGL 21 и частично OpenGL 30 довести до концаработу над поддержкой всех возможностей OpenGL 30планируется к концу года

Из добавленных в OpenGL 42 улучшений можноотметить

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

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

- Поддержка изменения произвольной части сжатойтекстуры без повторной загрузки в GPU текстурыцеликом что позволяет добиться существенного ростапроизводительности

- Поддержка упаковки нескольких 8- и 16-разрядныхзначений в одно 32-разрядное значение для эффективнойобработки шейдеров cо значительным сокращениемиспользуемого объема памяти и повышением пропускнойспособности Например подобная упаковка особеннополезна для организации передачи данных междуразличными стадиями выполнения шейдера

- 7 -

КАК И ВО МНОГИХ других языках в D есть свой стильпрограммирования ndash ряд правил laquoхорошего тонаraquo дляграмотного читаемого кода Эти правила ни к чему непринуждают ndash вы разумеется вольны писать программыкак вам угодно Однако их рекомендуется соблюдать ndashособенно в том случае если с вашим кодом будутработать другие люди К примеру стиля Dпридерживаются библиотека Phobos и компилятор DMD

httpwwwdigitalmarscomd20dstylehtml

На каждую строку ndash не более одного утверждения

Вместо аппаратных знаков табуляции следуетиспользовать пробелы

Длина отступа ndash четыре пробела

Операторы отделяются от операндов пробелами

Тела функций отделяются двумя пустыми строками

Объявления переменных отделяются от утвержденийодной пустой строкой

Одно утверждение комментируется двумя косымичертами

statement comment

statement comment

Набор утверждений комментируется блоком

comment

comment

statement

statement

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 4 -

1 На главной машине запустите master-сервер активируйтеплагин переключите движок рендеринга на Network RendererВ качестве режима операции выберите Master

2 Нажмите Start Service Строка статуса рендеринга будетотображать действия сервера Остановить его работу можнонажатием клавиши Esc

3 На всех остальных машинах кластера запуститеslave-сервер активируйте плагин переключите движокрендеринга на Network Renderer В качестве режима операциивыберите Slave

- 5 -

4 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Нажмите Start ServiceСтрока статуса рендеринга будет отображать действиясервера Остановить его работу можно нажатием клавиши Esc

5 На том компьютере где находится ваш проект запуститеклиентский процесс измените настройки рендерингасохраните blend-файл активируйте плагин переключитедвижок рендеринга на Network Renderer В качестве режимаоперации выберите Client

6 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Отправьте задачу навыполнение кнопкой Send Job

Теперь вы можете использовать комбинацию Ctrl+F12чтобы отрендерить анимацию на кластере Готовые кадрыбудут появлятся автоматически Прирост скорости рендерингабудет обратно пропорционален количеству slave-серверов

Можно также запустить серверы в консольном режимеСохраните master-сервер в файл blend и запускайте командой

$ blender -b masterblend -a

Аналогично ndash для slave-сервера

$ blender -b slaveblend -a

- 6 -

OpenGL 429 АВГУСТА 2011 г организация Khronos Group

представила обновленную версию спецификации OpenGL42 и языка описания шейдеров GLSL 420 Новая версияспецификации обратно совместима с предыдущимиверсиями OpenGL и содержит улучшенияподготовленные на основе пожеланий разработчиковграфических приложений и игр

Компания NVIDIA выпустила тестовую версиюпроприетарных видеодрайверов с поддержкой OpenGL42 сразу после публикации спецификации Драйверполностью поддерживает OpenGL 42 для карт NVIDIAGeForce 400500 (Fermi) и доступен для платформWindows Solaris Linux и FreeBSD Компания AMDсообщила о намерении выпустить в ближайшие днибета-версию драйверов AMD Catalyst с поддержкойOpenGL 42

Поддержка OpenGL 42 в свободной библиотеке Mesaпока не планируется в обозримом будущем В настоящеевремя в Mesa 3D полностью обеспечена поддержкаOpenGL 21 и частично OpenGL 30 довести до концаработу над поддержкой всех возможностей OpenGL 30планируется к концу года

Из добавленных в OpenGL 42 улучшений можноотметить

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

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

- Поддержка изменения произвольной части сжатойтекстуры без повторной загрузки в GPU текстурыцеликом что позволяет добиться существенного ростапроизводительности

- Поддержка упаковки нескольких 8- и 16-разрядныхзначений в одно 32-разрядное значение для эффективнойобработки шейдеров cо значительным сокращениемиспользуемого объема памяти и повышением пропускнойспособности Например подобная упаковка особеннополезна для организации передачи данных междуразличными стадиями выполнения шейдера

- 7 -

КАК И ВО МНОГИХ других языках в D есть свой стильпрограммирования ndash ряд правил laquoхорошего тонаraquo дляграмотного читаемого кода Эти правила ни к чему непринуждают ndash вы разумеется вольны писать программыкак вам угодно Однако их рекомендуется соблюдать ndashособенно в том случае если с вашим кодом будутработать другие люди К примеру стиля Dпридерживаются библиотека Phobos и компилятор DMD

httpwwwdigitalmarscomd20dstylehtml

На каждую строку ndash не более одного утверждения

Вместо аппаратных знаков табуляции следуетиспользовать пробелы

Длина отступа ndash четыре пробела

Операторы отделяются от операндов пробелами

Тела функций отделяются двумя пустыми строками

Объявления переменных отделяются от утвержденийодной пустой строкой

Одно утверждение комментируется двумя косымичертами

statement comment

statement comment

Набор утверждений комментируется блоком

comment

comment

statement

statement

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 5 -

4 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Нажмите Start ServiceСтрока статуса рендеринга будет отображать действиясервера Остановить его работу можно нажатием клавиши Esc

5 На том компьютере где находится ваш проект запуститеклиентский процесс измените настройки рендерингасохраните blend-файл активируйте плагин переключитедвижок рендеринга на Network Renderer В качестве режимаоперации выберите Client

6 Нажмите кнопку со стрелками чтобы автоматическиоперелить IP-адрес master-сервера Отправьте задачу навыполнение кнопкой Send Job

Теперь вы можете использовать комбинацию Ctrl+F12чтобы отрендерить анимацию на кластере Готовые кадрыбудут появлятся автоматически Прирост скорости рендерингабудет обратно пропорционален количеству slave-серверов

Можно также запустить серверы в консольном режимеСохраните master-сервер в файл blend и запускайте командой

$ blender -b masterblend -a

Аналогично ndash для slave-сервера

$ blender -b slaveblend -a

- 6 -

OpenGL 429 АВГУСТА 2011 г организация Khronos Group

представила обновленную версию спецификации OpenGL42 и языка описания шейдеров GLSL 420 Новая версияспецификации обратно совместима с предыдущимиверсиями OpenGL и содержит улучшенияподготовленные на основе пожеланий разработчиковграфических приложений и игр

Компания NVIDIA выпустила тестовую версиюпроприетарных видеодрайверов с поддержкой OpenGL42 сразу после публикации спецификации Драйверполностью поддерживает OpenGL 42 для карт NVIDIAGeForce 400500 (Fermi) и доступен для платформWindows Solaris Linux и FreeBSD Компания AMDсообщила о намерении выпустить в ближайшие днибета-версию драйверов AMD Catalyst с поддержкойOpenGL 42

Поддержка OpenGL 42 в свободной библиотеке Mesaпока не планируется в обозримом будущем В настоящеевремя в Mesa 3D полностью обеспечена поддержкаOpenGL 21 и частично OpenGL 30 довести до концаработу над поддержкой всех возможностей OpenGL 30планируется к концу года

Из добавленных в OpenGL 42 улучшений можноотметить

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

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

- Поддержка изменения произвольной части сжатойтекстуры без повторной загрузки в GPU текстурыцеликом что позволяет добиться существенного ростапроизводительности

- Поддержка упаковки нескольких 8- и 16-разрядныхзначений в одно 32-разрядное значение для эффективнойобработки шейдеров cо значительным сокращениемиспользуемого объема памяти и повышением пропускнойспособности Например подобная упаковка особеннополезна для организации передачи данных междуразличными стадиями выполнения шейдера

- 7 -

КАК И ВО МНОГИХ других языках в D есть свой стильпрограммирования ndash ряд правил laquoхорошего тонаraquo дляграмотного читаемого кода Эти правила ни к чему непринуждают ndash вы разумеется вольны писать программыкак вам угодно Однако их рекомендуется соблюдать ndashособенно в том случае если с вашим кодом будутработать другие люди К примеру стиля Dпридерживаются библиотека Phobos и компилятор DMD

httpwwwdigitalmarscomd20dstylehtml

На каждую строку ndash не более одного утверждения

Вместо аппаратных знаков табуляции следуетиспользовать пробелы

Длина отступа ndash четыре пробела

Операторы отделяются от операндов пробелами

Тела функций отделяются двумя пустыми строками

Объявления переменных отделяются от утвержденийодной пустой строкой

Одно утверждение комментируется двумя косымичертами

statement comment

statement comment

Набор утверждений комментируется блоком

comment

comment

statement

statement

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 6 -

OpenGL 429 АВГУСТА 2011 г организация Khronos Group

представила обновленную версию спецификации OpenGL42 и языка описания шейдеров GLSL 420 Новая версияспецификации обратно совместима с предыдущимиверсиями OpenGL и содержит улучшенияподготовленные на основе пожеланий разработчиковграфических приложений и игр

Компания NVIDIA выпустила тестовую версиюпроприетарных видеодрайверов с поддержкой OpenGL42 сразу после публикации спецификации Драйверполностью поддерживает OpenGL 42 для карт NVIDIAGeForce 400500 (Fermi) и доступен для платформWindows Solaris Linux и FreeBSD Компания AMDсообщила о намерении выпустить в ближайшие днибета-версию драйверов AMD Catalyst с поддержкойOpenGL 42

Поддержка OpenGL 42 в свободной библиотеке Mesaпока не планируется в обозримом будущем В настоящеевремя в Mesa 3D полностью обеспечена поддержкаOpenGL 21 и частично OpenGL 30 довести до концаработу над поддержкой всех возможностей OpenGL 30планируется к концу года

Из добавленных в OpenGL 42 улучшений можноотметить

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

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

- Поддержка изменения произвольной части сжатойтекстуры без повторной загрузки в GPU текстурыцеликом что позволяет добиться существенного ростапроизводительности

- Поддержка упаковки нескольких 8- и 16-разрядныхзначений в одно 32-разрядное значение для эффективнойобработки шейдеров cо значительным сокращениемиспользуемого объема памяти и повышением пропускнойспособности Например подобная упаковка особеннополезна для организации передачи данных междуразличными стадиями выполнения шейдера

- 7 -

КАК И ВО МНОГИХ других языках в D есть свой стильпрограммирования ndash ряд правил laquoхорошего тонаraquo дляграмотного читаемого кода Эти правила ни к чему непринуждают ndash вы разумеется вольны писать программыкак вам угодно Однако их рекомендуется соблюдать ndashособенно в том случае если с вашим кодом будутработать другие люди К примеру стиля Dпридерживаются библиотека Phobos и компилятор DMD

httpwwwdigitalmarscomd20dstylehtml

На каждую строку ndash не более одного утверждения

Вместо аппаратных знаков табуляции следуетиспользовать пробелы

Длина отступа ndash четыре пробела

Операторы отделяются от операндов пробелами

Тела функций отделяются двумя пустыми строками

Объявления переменных отделяются от утвержденийодной пустой строкой

Одно утверждение комментируется двумя косымичертами

statement comment

statement comment

Набор утверждений комментируется блоком

comment

comment

statement

statement

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 7 -

КАК И ВО МНОГИХ других языках в D есть свой стильпрограммирования ndash ряд правил laquoхорошего тонаraquo дляграмотного читаемого кода Эти правила ни к чему непринуждают ndash вы разумеется вольны писать программыкак вам угодно Однако их рекомендуется соблюдать ndashособенно в том случае если с вашим кодом будутработать другие люди К примеру стиля Dпридерживаются библиотека Phobos и компилятор DMD

httpwwwdigitalmarscomd20dstylehtml

На каждую строку ndash не более одного утверждения

Вместо аппаратных знаков табуляции следуетиспользовать пробелы

Длина отступа ndash четыре пробела

Операторы отделяются от операндов пробелами

Тела функций отделяются двумя пустыми строками

Объявления переменных отделяются от утвержденийодной пустой строкой

Одно утверждение комментируется двумя косымичертами

statement comment

statement comment

Набор утверждений комментируется блоком

comment

comment

statement

statement

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 8 -

Неправильный код следует обрамлять вложеннымблоком

+++++

comment

comment

statement

statement

+++++

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

laquoверблюдомraquo (первая буква первого слова ndash строчная уостальных слов ndash заглавная)

int mySuperFunction()

Названия классов и структур пишутся через заглавнуюбукву

class Foo

class FooAndBar

Названия не должны начинаться со знака подчеркивания(laquo_raquo) если они не принадлежат private-членам классов

Названия модулей не должны содержать заглавныебуквы ndash во избежание проблем на файловых системах

нечувствительных к регистру

По возможности следует избегать объявлениябессмысленных псевдонимов например

alias void VOID

alias int INT

alias int pint

Одинаковые объявления следует группировать

int[] x y

int p q

При перегрузке операторов не следует назначать имнелогичную и неочевидную семантику ndash например

наделять оператор laquo+raquo смыслом отличным от операцииlaquoсложениеraquo

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 9 -

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

Часть II

МЫ ПРОДОЛЖАЕМ тему о шаблонах в языке Dначатую в laquoFPSraquo 13 (11) Обобщенноепрограммирование в D ndash это не простопараметризованные шаблоны функций и классов Dразвивает эту идею позволяя напрямую laquoобщатьсяraquo скомпилятором и получать информацию о типах на этапесборки программы ndash причем средства для этого встроеныв сам язык

Начнем с простого ndash директивы pragma Она ужезнакома laquoплюсистамraquo ndash в C++ это нестандартнаяпрепроцессорная инструкция и ее частое использованиеявляется признаком дурного тона В D pragma ndash это частьстандарта языка Например

pragma(msg Hello world)

во время компиляции выведет строку laquoHello worldraquoЭто полезно для вывода на экран различныхпредупреждений отладочных сообщений для пометкиdeprecated-кода и тд

Один из способов ее применения ndash вывод типа тогоили иного значения

pragma(msg typeof([[foo[] bar[]] 5])stringof)

Эта команда выведет следующий текст

AssociativeArray(const(immutable(char)[])[string]int)

В D возможна экстренная остановка компиляции Дляэтого используется специальная конструкция ndash staticassert Напомним что assert обрабатывает исключениепроверяя заданное значение на истинность если в assertпередать 0 или false он гарантированно остановит работупрограммы К примеру если ваша программа неподдерживает Linux можно написать так

version(linux)

pragma(msg Linux is not supported)

static assert(0)

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 10 -

template factorial(uint n)

static if (n lt 2)

const uint factorial = 1

else

const uint factorial = n factorial(n-1)

Использование uint f = factorial10

Непосредственно получение информации о классах итипах (интроспекция или рефлексия) реализовано вспециальном расширении языка ndash traits Мы рассмотримчастный случай интроспекции когда необходимо узнатьскомпилируется ли тот или иной код

Возьмем к примеру шаблон функции котораясодержит операцию конкатенирования

void append (T) (ref T[] x T y)

x ~= y

Обычно конкатенирование применяется длядобавления нового элемента в массив ndash однако мы небудем связываться с массивами и вместо этогопараметризуем шаблон двумя типами Т и S чтобысохранить поддержку классов перегружающих операторlaquo ~= raquo

void append (T S) (ref T x S y)

x ~= y

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

void append (T S) (ref T x S y)

static if ( __traits (compiles x ~= y) )

x ~= y

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Директива __traits с параметром compiles принимаетлюбое выражение или утверждение возвращая истинуесли оно семантически правильно В нашем случае этоx ~= y

Итак наш шаблон append стал более laquoумнымraquoПравда не вполне удобно два раза писать искомый код ndashэто становится более ощутимым если он представляетсобой нечто большее чем одну операцию Тут на помощьприходит подмешивание (mixin)

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 11 -

void append (T S) (ref T x S y)

enum code = q

x ~= y

static if ( __traits (compiles mixin (code)) )

mixin (code)

else static assert (0

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

Мы прописываем laquoкритичныйraquo код только один раз изатем подмешиваем его везде где нужно Прописываем ввиде константной строки которая доступна под именемlaquocoderaquo А для строк содержащих D-код предусмотренспециальный синтаксис ndash q hellip Это было введено длятого чтобы текстовые редакторы подсвечивалисинтаксис таких строк как если бы это был обычный код

Однако теперь шаблон выглядит немного нелепоОтдадим дань стилю D и переоформим его с учетомконтрактной парадигмы Финальная версия append будетвыглядеть следующим образом

void append ( T S

string code = qx ~= y ) (ref T x S y)

in

static assert ( __traits (compiles mixin (code))

Operation is not supported for types ~

Tstringof ~ ~ Sstringof)

body

mixin (code)

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

int value = 6

append(int int x += y ) (value 5)

Правда при этом вызов функции стал болеезапутанным В то же время изначальное предназначениешаблона ndash добавление элемента в массив ndash остается всетаким же простым

string[] arr

append(arr hello)

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 12 -

Перегрузка операторов в D

ПЕРЕГРУЗКА операторов ndash важный элементполиморфизма в ООП-языках Будучи всего лишьlaquoсинтаксическим сахаромraquo (syntactic sugar) перегрузкаоператоров оказывается очень полезной во многихситуациях делая поведение пользовательских типовболее похожим на поведение встроенных Вы можетенапример переопределить операторы арифметическихдействий для векторов или матриц

vector3f c = a + b

будет интерпретировано как

vector3f c

cx = ax + bx

cy = ay + by

cz = az + bz

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

Наример для перегрузки оператора laquo+raquo используетсяметод opAdd

T opAdd(T b)

Но можно то же самое написать так

T opBinary (string op) (T b) if (op == +)

Для классов-контейнеров незаменима перегрузкаоператора индекса

T opIndex (int index)

return get (index)

void opIndexAssign (T val int index)

set (val index)

auto a = obj[10]

obj[4] = 100

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 13 -

и конкатенирования

void opCatAssign(T k)

obj ~= 10

void opCatAssign(T[] k)

obj ~= [5 8 10 32]

В некоторых случаях бывает нужно перегрузитьоператор in Например он может возвращать логическоезначение

bool opIn_r (T val)

if ( have(val) ) return true

else return false

if (50 in obj)

или указатель на объект

T opIn_r (string key)

return ampstorage[string]

auto p = name in obj

Наконец доступно перенаправление (forwarding)несуществующих членов класса при доступе к ним (такназываемая диспетчеризация вызовов ndash фактическиперегрузка оператора laquoточкаraquo)

struct S

void opDispatch (string s T) (T i)

writefln(SopDispatch(s s) s i)

S s

sfoo(7)

Перенаправлять можно не только методы но исвойства

struct D

template opDispatch(string s)

enum int opDispatch = 8

D d

writeln(dfoo)

Geckogecko0307gmailcom

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 14 -

SingletonПлюсы и минусы

В РАЗРАБОТКЕ программного обеспечения шаблонпроектирования или паттерн (англ design pattern) mdashповторимая архитектурная конструкция представляющаясобой решение проблемы проектирования в рамкахнекоторого часто возникающего контекста Популярностьпаттернов во многом обязана своим ростом книге laquoDesignPatterns mdash Elements of Reusable Object-Oriented Softwareraquo вкоторой были описаны 23 шаблона проектирования Авторыкниги mdash американские программисты Эрих Гамма РичардХелм Ральф Джонсон и Джон Влиссидс mdash стали известныобщественности под названием laquoБанда четырехraquo (англ laquoGangof Fourraquo часто сокращается до laquoGoFraquo)

В этой статье мы рассмотрим один из самыхраспространенных паттернов mdash singleton (одиночка) Это класскоторый может иметь только один экземпляр Как правилоsingleton инстанцируется лениво mdash то есть только когда егоэкземпляр будет действительно необходим Singleton можетпригодится для объекта-менеджера который существует навсем протяжении работы программы и управляет другимиобъектами

laquoForgive Me Father For I Have SingletonedraquoKevlin Henney

Весь код в статье приведен на языке D Простейшийsingleton можно объявить и использовать следующим образом

class Singleton

private

static Singleton instance = null

this()

public

static Singleton opCall()

if (instance is null)

instance = new Singleton

return instance

auto st1 = Singleton()

auto st2 = Singleton()

assert (st1 == st2)

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 15 -

Однако за простотой кроется опасность как только выначнете использовать в своей программе более одного потока(а вы рано или поздно начнете) класс Singleton уже не будетгарантировать свое laquoодиночествоraquo Два потока могутодновременно обратиться к методу opCall и создать дваэкземпляра Singleton Иными словами такая реализацияпотоково-небезопасна (not thread-safe) Как же быть

К счастью разработчики D все предусмотрели Данныебезопасно разделяемые между потоками в D обозначаютсяключевым словом shared Кроме того язык предусматриваетвозможность заблокировать код для выполнения более чемодним потоком одновременно mdash для этого был введенспецификатор synchronized Код помеченный таким образомснабжается мьютексом

class Singleton

private

static shared Singleton instance = null

this()

public

static shared(Singleton) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(Singleton)()

return instance

Можно реализовать класс Singleton в виде шаблона откоторого будут наследовать другие классы которые такжедолжны существовать в единственном экземпляре

class Singleton (T)

private

this()

protected

static shared T instance = null

public

static shared(T) opCall()

if (instance is null)

return instance

synchronized

instance = new shared(T)()

return instance

class OnlyOne Singleton(OnlyOne)

private this()

auto st1 = OnlyOne()

auto st2 = OnlyOne()

assert (st1 == st2)

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 16 -

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

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

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

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

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

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

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

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

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

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 17 -

laquoМой язык mdash лучшийraquo

Заблужденияв программировании

ЗА ПОЛВЕКА существования компьютеров инженерамибыло создано несколько тысяч языков программированияРазумеется далеко не все из них сейчас актуальны поэтомусократим список хотя бы до ста языков получившихболее-менее широкое распространение Примерно половинуиз этой сотни можно считать устоявшимися стандартами Изних для создания основной массы программного обеспеченияиспользуется не больше двадцати Таким образом можносокращать список языков по критерию распространенности Номожно ли сказать что самый распространенный язык ndash самыйлучший

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

другу чем к примеру Lisp лучше C++ К слову сказать если быупотребить эти затраченные на бессмысленную полемикуэнергию и время на написание того же по объему кода (налюбом заметьте языке) ndash вышло бы куда больше пользы

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

Второе заблуждение является логическим продолжениемпервого laquoЧтобы стать лучшим программистом необходимо ссамого начала учить самый сложный языкraquo На самом деленикогда не следует начинать со сложного Никто не учитсяводить машину на болидах laquoФормулы-Iraquo Вы можете начать слюбого языка который покажется вам проще Выберите самыйпростой язык который вы понимаете изучите его полностью истаньте лучшим программистом на нем И только когда еговозможностей перестанет хватать переходите на болеесложный

Третье заблуждение очень распространенное ndash даже в среде профессионалов звучит так laquoЯ могу написать что угодно на языке который знаю Изучать другие языки и даже смотреть в их сторону ndash пустая трата времени Мой язык ndash лучшийraquo Это самое опасное заблуждение так как не ведет ни

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 18 -

к чему кроме застоя и деградации Языки программирования ndashэто всего лишь инструменты Чем больше у вас разныхинструментов тем легче и удобнее вам выполнять работуХороший программист знает 3 - 4 языка и даже больше ndashиспользуя каждый из них там где этот язык подходит лучшевсего К тому же языки беспрерывно эволюционируютаккумулируя концепции своих предшественников иприобретая новые возможности Игнорируя эту эволюцию вырискуете отстать от жизни Никогда не стесняйтесь изучатьновые языки ndash более того стремитесь к этому

Четвертое заблуждение проистекает от третьего laquoВ языкеXXX нет возможности YYY которая есть в моем языкеПоэтому он неполноценен и не годится для серьезной работыraquoЛюбой язык спроектирован с определенными идеями ицелями Одна из таких идей (причем не такая глупая какмногим может показаться) ndash минимализм и простота Еслинекая возможность не была встроена в язык значит на этобыла своя причина Создатели языка учитывая его дизайн иструктуру посчитали эту возможность излишней Если личновам непременно нужна такая возможность просто выберитедругой язык Какой смысл в том что все языки будутпревращаться в laquoкомбайныraquo наполненные редкоиспользуемыми функциями laquoКомбайныraquo нужны далеко невсем и не всегда

Следующее заблуждение является основной причиной постоянных споров laquoЯзык XXX быстрее языка YYYraquo Языки не могут быть быстрыми или медленными Быстрыми или медленными бывают программы А скорость программ ndash величина относительная Одна и та же программа на разных

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

Аналогичное заблуждение laquoЯзык XXX мощнее языка YYYraquoНи один язык не создавался для решения всех проблем насвете Каждый из них эффективен в своей предметной областиИ совсем не обязательно должен быть эффективным в другихобластях Поэтому понятие laquoмощностиraquo языка имеет смыслтолько применительно к определенному кругу задач длярешения которых он был спроектирован

Помните что самого лучшего языка не существует А разтак ndash нет смысла искать его сравнивая языки друг с другомПросто используйте их по назначению Нет языков хороших иплохих есть хорошие и плохие программисты

Geckogecko0307gmailcom

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 19 -

Вечный вопрос

Пробелыпротив табуляции

ПРИ НАПИСАНИИ исходного кода очень важноиспользовать отступы Ваш стиль программирования иоформление кода говорят о вас очень многое Иногда дажебольше чем готовая рабочая программа Достаточно взглянутьна код чтобы понять какой перед вами программист ndashтрудолюбивый и аккуратный или ленивый и небрежный

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

Однако даже если вы используете отступы громадноезначение имеет вопрос как именно это делать Уже много летидут споры что использовать для этой цели ndash пробелы илисимвол табуляции (клавишу Tab) Табуляцию все текстовыередакторы обрабатывают по-своему Обычно онаэквивалентна 2 4 или 8 обычным пробелам ndash в зависимости отпользовательских настроек

Часто можно услышать что laquoтабуляция ndash злоraquo илиlaquoпробелы ndash злоraquo На самом деле все конечно зависит от вашихсобственных предпочтений Пробелы могут кого-тораздражать но и табуляция ndash не панацея Представьтенапример такую ситуацию

enum

TABS = 2

SPACES = 1

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

enum

TABS = 2

SPACES = 1

Это нужно делать строго при помощи пробелов Используяпри этом знаки табуляции вы всего лишь добиваетесь нужногорезультата в вашем текстовом редакторе и при вашихнастройках Если у вас длина табуляции ndash 8 пробелов такоеlaquoформатированиеraquo не сохранится при табуляции в 2 или 4пробела Попробуйте и убедитесь сами

enum

TAB = 0

SPACE = 1

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 20 -

Другая распространенная ошибка многие включают вредакторе опцию laquoзаписывать пробелы вместо знаковтабуляцииraquo Нажимая клавишу Tab пользователь на самомделе вставляет 2 4 или 8 пробелов Это может быть нестрашно если так диктуют правила дизайна проекта надкоторым вы работаете Но не стоит делать этого для кодакоторый вы специально пишете для других людей ndash дляпримеров демонстраций уроков учебников и т д Так как этоткод будут использовать множество людей с самыми разнымипредпочтениями они вряд ли помянут вас хорошим словомесли им придется потратить много времени напереформатирование Используйте в таких случаях обычнуютабуляцию Если кому-то не нравится он всегда можетзапустить автоматический поиск и замену знаков табуляции наN-ное количество пробелов ndash а вот обратное не всегдасправедливо

Geckogecko0307gmailcom

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 21 -

Что такое QR-код

НАВЕРНЯКА вы заметили что с определенного моментавам на глаза стали попадаться странные квадратики с каким-тонепонятным кодом Они встречаются на сайтах в рекламе набилбордах и на визитках Что же это за код и как егорасшифровать

Эти квадратики ndash так называемый QR-код матричный(двумерный) штрихкод разработанный японской фирмойDenso-Wave в 1994 г В этом штрихкоде кодируетсяразнообразная информация состоящая из символов (включаякириллицу цифры и специальные знаки) Информациявообще говоря любая адрес сайта телефон электроннаявизитка географические координаты и так далее Один QR-кодможет содержать 7089 цифр или 4296 букв

Аббревиатура QR производна от англ quick response чтопереводится как laquoбыстрый откликraquo Основное достоинствоQR-кода mdash это легкое распознавание сканирующимоборудованием (в том числе и фотокамерой мобильноготелефона) что дает возможность использования этойтехнологии в торговле и рекламе Сегодня QR-коды большевсего распространены в Японии ndash стране где штрих-кодыпользовались такой большой популярностью что объеминформации зашифрованной в них вскоре пересталустраивать индустрию Японцы начали экспериментировать сновыми способами графического кодирования информации

В настоящее время QR-код широко распространен встранах Азии постепенно развивается в Европе и СевернойАмерике Наибольшее признание он получил средипользователей мобильной связи ndash установивпрограмму-распознаватель абонент может моментальнозаносить в свой телефон текстовую информацию добавлятьконтакты в адресную книгу переходить по web-ссылкамотправлять SMS-сообщения и тд

В Японии подобные коды наносятся практически на всетовары продающиеся в магазинах их размещают в рекламныхбуклетах и справочниках С помощью QR-кодоворганизовывают различные конкурсы и ролевые игры Японцыразмещают QR-коды даже на кладбищах ndash они содержатинформацию об усопшем

QR-коды активно используются и в туризме Например воЛьвове (Украина) местное объединение laquoТуристическоеДвижение Львоваraquo разместило QR-коды более чем на 80

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 22 -

туристических объектах Это позволяет индивидуальномутуристу легко ориентироваться в городе даже не знаяукраинского языка так как QR-коды установлены нанескольких языках

На данный момент есть достаточно широкий выборпрограмм для распознавания QR-кодов Ниже приведенперечень наиболее популярных программ для мобильныхплатформ

Android Barcode Scanner Barcode2file QR Droid NeoReaderixMAT ScannerApple iOS QR Reader for iPhone Barcode ScannerWindows Mobile QuickMark I-NigmaSymbian Kaywa reader Nokia barcode reader I-NigmaQuickMark UpCodeJava Kaywa reader I-Nigma UpCodeMaemo mbarcodeBada BeeTagg

Теперь остался вопрос каким образом вы можетесгенерировать QR-код для своих целей Можновоспользоваться каким-нибудь бесплатным онлайновымсервисом mdash например qrcoderru Кроме того существуютпрограммы и скрипты предназначенные для локальнойгенерации QR-кодов К примеру для языка Python такой скриптможно найти на httpgithubcomhcvstpyqr

Рекомендациипо созданию QR-кодов

Чтобы все мобильные устройства корректно распознавалитип информации зашифрованной в QR-коде были введеныспециальные стандарты

При кодировании адреса веб-страницы нужно обязательноуказывать полный URL включая протокол (HTTP) URL-адресанечувствительны к регистру поэтому рекомендуется писатьадрес в верхнем регистре (алгоритм это учитывает и кодируетэффективнее)

HTTPFPSMAGZYMICHOSTCOM

При кодировании адреса электронной почты нужноуказывать префикс mailto

mailtogecko0307gmailcom

При кодировании телефонного номера нужно указыватьпрефикс tel и указывать полный номер в международномформате с кодом страны Например номер 212-555-1212(США) следует представить как

tel+12125551212

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 23 -

Для кодировании контактной информации можнопридерживаться форматов MECARD или BIZCARD Напримервизитка с текстом laquoSean Owen address 76 9th Avenue 4th FloorNew York NY 10011 phone number 212 555 1212 e-mailsrowenexamplecomraquo должна быть представлена как

MECARDNOwenSeanADR76 9th Avenue 4th Floor

New York NY 10011TEL+12125551212

EMAILsrowenexamplecom

или

BIZCARDNSeanXOwenA76 9th Avenue 4th Floor

New York NY 10011B+12125551212

Esrowenexamplecom

Географические координаты например офиса Google вНью-Йорке (4071872deg северной широты и 7398905deg западнойдолготы в 100 м над уровнем моря) кодируются следующимобразом

geo4071872-7398905100

Geckogecko0307gmailcom

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 24 -

МоделиосвещенияCook-Torrance

ОДНОЙ из наиболее точных и согласованных с физикойявляется модель освещения Кука-Торренса Она такжеоснована на модели поверхности состоящей из микрогранейкаждая из которых является идеальным зеркалом Модельучитывает коэффициент Френеля и взаимозатенениемикрограней

В данной модели угол между нормалью к микрограни инормалью ко всей поверхности подчиняется законураспределения Бэкмена (см FPS 14 11) Формула моделивыглядит следующим образом

I = DFGE N

где I ndash интенсивность отраженного света D ndash распределениеБекмана F ndash коэффициент Френеля G ndash коэффициентгеометрического взаимозатенения микрограней E ndash векторнаблюдателя N ndash нормаль поверхности

Значение G вычисляется по следующей формуле

G = min(12(H N)(E N)E H 2(H N)(L N)

E H )где E ndash вектор наблюдателя N ndash нормаль поверхности L ndashвектор на источник света H ndash половинный вектор

Для вычисления коэффициента Френеля в графикереального времени обычно используют аппроксимациюШлика

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 25 -

Реализация на 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

- предполагается что в приложении уже включены и настроены

соответствующие параметры OpenGL (позиция источника света свойства

материала и др) Приведенная реализация в целях упрощения не учитывает

интенсивность источника света Исходный код предоставлен как

общественное достояние (Public Domain) и может быть использован безо

всяких ограничений

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

varying vec4 V_eye

varying vec4 L_eye

varying vec4 N_eye

const float roughness = 10

void main(void)

vec4 Ca = gl_FrontMaterialambient

vec4 Cd = gl_FrontMaterialdiffuse

vec4 Cs = gl_FrontMaterialspecular

float Csh = gl_FrontMaterialshininess

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

vec3 H = normalize(L + V)

float NL = max(00 dot(N L))

float NH = max(10e-7 dot(N H))

float NV = max(00 dot(N V))

float VH = max(00 dot(V H))

float diffuse = clamp(NL 00 10)

float NH_sq = NH NH

float NH_sq_r = 10 (NH_sq roughness roughness)

float roughness_exp = (NH_sq - 10) NH_sq_r

float beckmann = exp(roughness_exp)NH_sq_r(40NH_sq)

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 26 -

float geometric = min( 10 (20 NH VH) min(NV NL) )

float fresnel = 10 (10 + NV)

float Rs = min(Csh (beckmann fresnel geometric) (NV NL + 10e-7))

gl_FragColor = Ca + NL Rs (Cd + Cs)

gl_FragColora = 10

Geckogecko0307gmailcom

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

- 27 -

Toon shading на GLSL

ЭФФЕКТ toon shading (мультипликационное затенение)используется для придания графике laquoрисованногоraquo стиля Этонаверное самый известный метод нефотореалистичногорендеринга К сожалению в играх он используется не оченьчасто более успешно прижившись в области неинтерактивнойанимации Сейчас все почему-то стремятся к достижениюполного фотореализма ndash забывая о том что в графике важенне столько реализм сколько художественный вкус

Приведенная реализация toon shading дискретизируетосвещенность в три компонента (тень свет блик) а такжеподдерживает отрисовку контуров

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

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

const vec4 HighlightColour = vec4(08081010)

const vec4 MidColour = vec4(02021010)

const vec4 ShadowColour = vec4(00000510)

const float HighlightSize = 005

const float ShadowSize = 01

const float OutlineWidth = 03

void main(void)

vec3 V = normalize(vec3(V_eye))

vec3 L = normalize(vec3(L_eye))

vec3 N = normalize(vec3(N_eye))

float lambert = dot(LN)

vec4 colour = MidColour

if (lambertgt1-HighlightSize) colour = HighlightColour

if (lambertltShadowSize) colour = ShadowColour

if (dot(NV)ltOutlineWidth) colour = vec4(0001)

gl_FragColor = colour

gl_FragColora = 10

Это все

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

Это все

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