Текущее время: 21 фев 2018, 19:12

Часовой пояс: UTC




Начать новую тему Ответить на тему  [ 1 сообщение ] 
Автор Сообщение
 Заголовок сообщения: Шейдер для Flash Player. AS3
СообщениеДобавлено: 24 май 2013, 08:45 
Не в сети
Администратор
Аватара пользователя

Зарегистрирован: 24 май 2013, 08:45
Сообщения: 12
Возможно, этот материал уже не актуален, хотя, как знать...
Pixel Bender для CS6 уже отсутствует среди предлагаемых Adobe дополнений, и, судя по форумам, где обитают счастливые обладатели нового пакета Adobe CS6, ранее написанные с помощью Pixel Bender полезности уже не прикручиваются к сервисам CS6.
Я использую Pixel Bender как "костыль", программируя шейдеры, которые включаю в код ActionScript 3.0 и Haxe. - "А это надо?" Adobe отказались от взимания платы за использование своей Alchemy, что, в общем-то, напрягало лишь тех, чьи продажи от игр, в коде которых использовалась Alchemy, превышают 40 тыс.долларов (если я правильно помню текст лицензии). Кроме того, славная команда Adobe предлагает новые средства работы с 3D. Однако, допустим, что вы решили лишь модифицировать ваш вполне успешно работающий код, вставив пару блоков на ассемблере, вместо чего-то или в дополнение чему-то. Да мало ли чего...
Вот на этот случай, и пригодится следующий материал (или на другой какой - ваше право).

Итак, потребуются:

Pixel Bender и библиотека для написания шейдеров на ассемблере.
Ранее на сайте этого, по всему судя, достойного человека, ссылку на который я привел (библиотека, автор), а вы уже посетили :) , размещалась полная документация PBJDisassembler, необходимая программисту, теперь она переместилась в https://github.com/jamesward/pbjas, отчего не стала хуже. Но сам я обнаружил, что такая библиотека существует уже после того, как нашел подобное в языке Haxe. В Haxe запись всех функций выглядит много лаконичнее, что, несомненно, удобнее, хотя вся функциональность совершенно идентична той, что предлагает James Ward.
Так что, если вам ближе Haxe, можете использовать его. Неважно, что вы предпочли, но прочитать этот пост в блоге уважаемого Nicolas Cannasse совершенно необходимо.
Pixel Bender (РВ) годится лишь для написания пиксельных шейдеров, но, если вы в меру изобретательны, то не исключено, что вам удастся создать нечто привлекательное - примеры такого рода легко найти в "обменнике" Pixel Bender Exchange, взгляните на Raytracer.
Любопытно, но сам код шейдера, скомпилированный средой РВ мне не нужен совершенно, и я в него даже не заглядываю, тем не менее, на начальном этапе, сервис разложения в коды ассемблера на странице Николаса Каннассе будет нелишним (Nicolas предлагает воспроизвести его код на своей машине, чтобы стать полностью автономным,- совершенно, знаете ли "безвоздмезно", как выразилась бы по этому поводу одна простуженная сова, и вне связи с вашими днями рождений).
Pixel Bender нужен мне лишь для визуализации воплощаемых мной образов, а код я предпочитаю писать сам - он получится логичней, лаконичней и более оптимизированным, нежели тот, что выдаст РВ.
Предположим, что вам пришла блажь построить пространственную картинку, включающую много объектов и вы затрудняетесь с их размещением (со мной такое случается). Например, я решил подсунуть текстуру шахматной доски под уже болтающиеся в пространстве кубики (см.IQubiki),- я не разрабатываю игры, и процесс создания игры был для меня нов и, во многом, интуитивен. По задумке, 4 кубика отражаются в зеркале и в тектуре стола, над которым они висят (они из сверхпроводящего материала и находятся в магнитном поле. Это понятно?). Но поскольку, кубики как-то размещены в пространстве, причем присутствует эффект перспективы, то сунуть внутрь пространства новый элемент, который надо точно позиционировать относительно уже включенных в сцену объектов, без серьезных мыслительных усилий не удастся.
Или есть вариант? Есть, и он займет, вместе с отладкой, существенно меньше времени, нежели любой другой. Ровно столько времени, сколько в вас проворства для того, чтобы выполнить следующее ...

Делаем скриншот нашей сцены, которую решили украсить ценным элементом в виде шедевральных квадратиков. Этот рисунок послужит подложкой/фоном, который мы поместим в среду разработки PB.
РВ позволит нам увидеть, верен ли наш код в целом, и ... быстренько пишем, в соответствии со спецификацией языка РВ, следующий код:
Код: [ Загрузить ] [ Скрыть ]
Использован Pixel Bender 1.0 Syntax Highlighting
  1. <languageVersion : 1.0;>
  2.  
  3. kernel Dice_Board
  4.  
  5. <   namespace : "ozrio.com";
  6.     vendor : "Dmitry Gutso";
  7.     version : 1;
  8. >
  9.  
  10. {
  11.     parameter float bias
  12.     <
  13.         minValue : 0.5;
  14.         maxValue : 90.5;
  15.         defaultValue : 85.1;
  16.         stepInterval : 1.1;
  17.     >;
  18.     parameter float turn
  19.     <
  20.         minValue : -45.5;
  21.         maxValue : 40.5;
  22.         defaultValue : -27.5;
  23.         stepInterval : 1.1;
  24.     >;
  25.     parameter float zs
  26.     <
  27.         minValue : 0.0;
  28.         maxValue : 2000.;
  29.         defaultValue : 520.0;
  30.         stepInterval : 10.0;
  31.     >;
  32.     parameter float ys
  33.     <
  34.         minValue : 0.0;
  35.         maxValue : 2000.;
  36.         defaultValue : 600.0;
  37.         stepInterval : 10.0;
  38.     >;
  39.     parameter float xs
  40.     <
  41.         minValue : 0.0;
  42.         maxValue : 2000.;
  43.         defaultValue : 1480.0;
  44.         stepInterval : 5.0;
  45.     >;
  46.     input image4 src;
  47.     output pixel4 dst;
  48.    
  49.     void
  50.     evaluatePixel()
  51.     {
  52.         dst = sampleNearest(src,outCoord());
  53.         float alfa = radians(turn);
  54.         float k = 2800.;
  55.         float wh = 1800.;
  56.         float res = 180.;
  57.         float limit = -3.;
  58.         float2 pos = outCoord();
  59.         float x = pos.x;
  60.         float y = pos.y;
  61.         float a = cos(alfa);
  62.         float b = sin(alfa);
  63.         float beta = radians(bias);
  64.         float cosbeta = cos(beta);
  65.         float sinbeta = sin(beta);
  66.         float c = b * cosbeta;
  67.         float d = a * cosbeta;
  68.         float e = b * sinbeta;
  69.         float f = a * sinbeta;
  70.         float g = zs + k;
  71.         float p = g*x-xs*k;
  72.         float q = g*y-ys*k;
  73.         float al = d*k+f*y;
  74.         float ep = b*k+f*x;
  75.         float ks = e*x-a*k;
  76.         float be = k*c+e*y;
  77.         float m = ep*be-ks*al;
  78.         float xr = (p*al-q*ep)/m;
  79.         float yr = (p*be-q*ks)/m;
  80.  
  81.         if(abs(xr)<wh && abs(yr)< wh) {
  82.             float xt = floor(xr/res);
  83.             float yt = floor(yr/res);
  84.             if(mod(xt, 2.0) > 0.0 ^^ mod(yt, 2.0) > 0.0)
  85.             {
  86.                 if(yt>limit) { dst = pixel4(.424, .535, .62, .4) * dst; }// delete dst
  87.                 else dst = pixel4(.0, .535, .62, 1) * dst;
  88.             }
  89.             else
  90.             {
  91.                 if(yt>limit) { dst = pixel4(.0, .535, .62, 1) * dst; }
  92.                 else { dst = pixel4(.424, .535, .62, .4) * dst; }
  93.             }
  94.         }
  95.     }
  96. }
  97.  
Parsed in 0.016 seconds, using GeSHi 1.0.8.11

Затем, ищем положение рычажков слайдеров панели управления, при котором наша подложка размещена в сцене именно так, как нам бы хотелось, и запоминаем значения параметров, соответствующие этому положению. Эти параметры будем передавать шейдеру, код которого сейчас напишем.
Изображение
Впрочем, можно просто скомпилировать средой РВ код шейдера, который затем встроить в код программы на AS3 или подгрузить на этапе выполнения. Исчерпывающие рекомендации по использованию шейдеров имеются в руководствах Adobe по AS3. Если скорость выполнения кода и нагруженность клиентской машины, где будет исполняться код, не имеют большого значения, разработчик может сберечь собственное ценное время просто воспользовавшись кнопкой "Экспорт во Flash Player", и получить скомпилированный РВ готовый шейдер. В качестве альтернативы, существует следующий путь.
Я приведу пример, как это делается на Haxe, отличия с компиляцией в среде AS3 незначительны. Можете компилировать любым компилятором, способным выдать читаемый Flash Player'ом байт-код, я скромно пользую рекомендованный Adobe MXMLC. Вся программа будет скомпилированна сразу в один swf-файл.
FlashDevelop не позволит вам забыть необходимые импорты, при компиляции будет использована библиотека format. Что заключает в себе отдельную приятность, так это возможность при разработке кода записывать внутри комментариев значения задействованных регистров по мере операций с ними.
Если развернуть в коды ассемблера pbj-файл, выданный РВ, можно видеть, что он существенно хуже оптимизирован, чем код приведенный ниже:
Код: [ Загрузить ] [ Скрыть ]
Использован ActionScript 3 Syntax Highlighting
  1. import ...
  2. ........
  3. import format.pbj.Data;
  4. import haxe.io.Bytes;
  5.  
  6.         static function checkerBoardPBJ() {
  7.         var pbj : PBJ = {
  8.             version : 1,
  9.             name : "checkerboard",
  10.             metadatas : [],
  11.             parameters : [
  12.                 { name : "_OutCoord", p : Parameter(TFloat2, false, RFloat(0, [R, G])), metas : [] },
  13.                 { name : "src", p : Texture(4, 0), metas : [] },
  14.                 { name : "dst", p : Parameter(TFloat4, true, RFloat(1)), metas : [] },
  15.                                 { name : "fl", p : Parameter(TFloat2, false, RFloat(0, [B, A])), metas : [] }, // f and limit =-3
  16.                                 { name : "abcd", p : Parameter(TFloat4, false, RFloat(2)), metas : [] },
  17.                                 { name : "mnge", p : Parameter(TFloat4, false, RFloat(3)), metas : [] },
  18.                                 { name : "hr", p : Parameter(TFloat2, false, RFloat(4, [R, G])), metas : [] }, // w/h board, size of edge,
  19.                                 { name : "colorf", p : Parameter(TFloat4, false, RFloat(5)), metas : [] },
  20.                                 { name : "colort", p : Parameter(TFloat4, false, RFloat(6)), metas : [] },
  21.             ],
  22.             code : [
  23.                 OpSampleNearest(RFloat(7), RFloat(0, [R, G]), 0),
  24.                                 OpMov(RFloat(8, [R, G, B, A]), RFloat(0, [R, G, R, G])), // f8: x*, y*, x*, y*
  25.                                 OpMul(RFloat(8, [R, G]), RFloat(3, [A, A])),             // f8: e * x*, e * y*, x*, y*
  26.                                 OpMul(RFloat(8, [B, A]), RFloat(0, [B, B])),             // f8: e * x*, e * y*, f * x*, f * y*
  27.                                 OpSub(RFloat(8, [R]), RFloat(2, [R])),                   // f8: e * x* - a = ks, e * y*, f * x*, f * y*
  28.                                 OpAdd(RFloat(8, [G, B, A]), RFloat(2, [G, B, A])),       // f8: ks, e * y* + b = be, f * x* + c = ep, f * y* + d = al
  29.                                 OpMov(RFloat(4, [B, A]), RFloat(0, [R, G])),             // f4: h, r, x*, y*
  30.                                 OpMul(RFloat(4, [B, A]), RFloat(3, [B, B])),             // f4: h, r, g*x*, g*y*
  31.                                 OpSub(RFloat(4, [B, A]), RFloat(3, [R, G])),             // f4: h, r, g*x* - m = p, , g*y* - n = q
  32.                                 OpMov(RFloat(9, [R, G]), RFloat(8, [R, G])),             // f9: ks, be, (), ()
  33.                                 OpMul(RFloat(9, [R, G]), RFloat(8, [A, B])),             // f9: ks*al, be*ep, (),()
  34.                                 OpSub(RFloat(9, [G]), RFloat(9, [R])),                   // f9: (), be*ep-ks*al
  35.                                 OpRcp(RFloat(9, [R]), RFloat(9, [G])),                   // f9: 1/(be*ep-ks*al) = mega, (),(),()
  36.                                 OpMul(RFloat(8), RFloat(4, [A, B, A, B])),               // f8: ks*q, be*p, ep*q, al*p
  37.                                 OpSub(RFloat(8, [G, A]), RFloat(8, [R, B])),            
  38.                                 OpMul(RFloat(8, [G, A]), RFloat(9, [R, R])),             // f8: (), y, (), x
  39.                                 OpAbs(RFloat(8, [R, B]), RFloat(8, [G, A])),             // f8: /y/,y,/x/,x
  40.                                 OpLessThan(RFloat(8, [R]), RFloat(4, [R])),              // /y/ < width of board
  41.                                 OpMov(RInt(0, [G]), RInt(0, [R])),
  42.                                 OpLessThan(RFloat(8, [B]), RFloat(4, [R])),              // /x/ < width of board
  43.                                 OpLogicalAnd(RInt(0, [R]), RInt(0, [G])),
  44.                                 OpIf(RInt(0, [R])),
  45.                                         OpLoadFloat(RFloat(9, [A]), -8),
  46.                                         OpSub(RFloat(9, [A]), RFloat(4, [G])),
  47.                                         OpLoadFloat(RFloat(9, [B]), 0),
  48.                                         OpSub(RFloat(9, [B]), RFloat(4, [G])),
  49.                                         OpLessThan(RFloat(8, [G]), RFloat(9, [B])),          // f9: mega, (), -180, -188
  50.                                         OpMov(RInt(0, [G]), RInt(0, [R])),
  51.                                         OpLessThan(RFloat(9, [A]), RFloat(8, [G])),
  52.                                         OpLogicalAnd(RInt(0, [R]), RInt(0, [G])),
  53.                                         OpIf(RInt(0, [R])),
  54.                                                 OpLoadFloat(RFloat(7, [B]), .55),
  55.                                                 OpMov(RFloat(7, [R, G]), RFloat(7, [B, B])),
  56.                                         OpElse,
  57.                                                 OpRcp(RFloat(8, [R]), RFloat(4, [G])),               // f8: 1/r, y, (), x
  58.                                                 OpMov(RFloat(9, [R, G]), RFloat(8, [G, A])),         // f9: y, x, (), ()
  59.                                                 OpMul(RFloat(9, [R, G]), RFloat(8, [R, R])),         // f9: y/r, x/r, y
  60.                                                 OpFloor(RFloat(8, [R, G]), RFloat(9, [R, G])),       // f8: floor y/r, floor x/r, (), ()
  61.                                                 OpMov(RFloat(8, [B]), RFloat(8, [R])),               // f8: floor y/r, floor x/r, floor y/r,()
  62.                                                 OpLoadFloat(RFloat(8, [A]), 2),                      // f8: floor y/r, floor x/r, floor y/r, 2.
  63.                                                 OpMod(RFloat(8, [R, G]), RFloat(8, [A, A])),         // f8: mod, mod, floor y/r, 2.
  64.                                                 OpLoadFloat(RFloat(8, [A]), 0),                      // f8: mod, mod, floor y/r, 0.
  65.                                                 OpLessThan(RFloat(8, [A]), RFloat(8, [R])),
  66.                                                 OpMov(RInt(0, [G]), RInt(0, [R])),
  67.                                                 OpLessThan(RFloat(8, [A]), RFloat(8, [G])),
  68.                                                 OpLogicalXor(RInt(0, [R]), RInt(0, [G])),
  69.                                                 OpIf(RInt(0, [R])),
  70.                                                         OpLessThan(RFloat(0, [A]), RFloat(8, [B])),
  71.                                                         OpIf(RInt(0, [R])),
  72.                                                                 OpMul(RFloat(7), RFloat(5)),
  73.                                                         OpElse,
  74.                                                                 OpMul(RFloat(7), RFloat(6)),
  75.                                                         OpEndIf,
  76.                                                 OpElse,
  77.                                                         OpLessThan(RFloat(0, [A]), RFloat(8, [B])),
  78.                                                         OpIf(RInt(0, [R])),
  79.                                                                 OpMul(RFloat(7), RFloat(6)),
  80.                                                         OpElse,
  81.                                                                 OpMul(RFloat(7), RFloat(5)),
  82.                                                         OpEndIf,
  83.                                                 OpEndIf,
  84.                                         OpEndIf,
  85.                                 OpEndIf,
  86.                                 OpMov(RFloat(1), RFloat(7)),
  87.                 ],
  88.         };
  89.         var output = new haxe.io.BytesOutput();
  90.         var writer = new format.pbj.Writer(output);
  91.         writer.write(pbj);
  92.         return output.getBytes();
  93.     }
  94.  
Parsed in 0.060 seconds, using GeSHi 1.0.8.11

Надеюсь, этот опыт еще пригодится кому-нибудь.
Удачи!

_________________
"- Но я хотя бы попытался, - говорит он. - Черт возьми, на это по крайней мере меня хватило, так или нет?"
© Кен Кизи «Над кукушкиным гнездом»


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ 1 сообщение ] 

Часовой пояс: UTC


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB