Monthly Archive for May, 2008

onEnterFrame.ru

1. Зарегил onEnterFrame.ru
2. …
3. Profit!

Flex4

А тем временем Adobe раздает Flex4 SDK. Честно говоря, разбираться что там нового нет особого желания.

Вот почему у меня 60фпс везде.

Оказывается, все-таки есть ограничение на fps в браузере. Слава Богу, я-то наивно полагал, что в браузере просто все очень медленно.

ShaderJob

Осталось придумать как использовать ShaderJob для ресурсоемких вычислений на фоне.

This is Your Chance to Own valyard.com

Первый раз столкнулся. Был у меня домен valyard.com, на котором был редирект на valyard.ru. Я решил его не продлевать, т.к. не пользуюсь и не буду пользоваться. И вот сегодня получаю письмо:

«Recently, valyard.com expired and we acquired it in a domain name auction.  Time is running out, and now may be the ONLY opportunity for you to own the preferred .com version of your domain name.»

 Предлагают выкупить за 557 баксов. С основными доменами буду аккуратнее ((8

Flash Player 10, шейдеры, bump mapping…

Warning! Пост устарел, файлы были потеряны.
Единственный пример, который удалось найти — http://valyard.ru/tmp/bump_mapping_flash_10_2.swf

Я как всегда все новое пропустил, поэтому пришлось быстренько наверстывать. Что тут сказать, товарищи из Adobe как обычно радуют нас новыми плюшками. Особенно интересны шейдеры, 3D трансформации, текстовые эффекты и новый drawing API. Очень надеюсь, что бравые ребята из Papervision3D будут использовать эти новинки на полную катушку.

Какое-то время назад я пытался сделать эффект Bump Mapping‘а во флэше. На картинке 256×256 получилось ужасно медленно и некрасиво. Не знаю как разработчикам Alternativa Platform удалось сделать картинки с Parallax Effect с таким классным FPS’ом, да и некогда особо рыть литературу.

Вот что получилось в итоге на десятке с шейдерами.
Видно что-то типо динамических теней от пупырышков. На произвольной картинке. Скроллером менять уровень света от источника.

Настраиваем оборудование.

И вот в холодное летнее воскресное утро я скачал Adobe Pixel Bender Toolkit, документацию по новому Flash Player 10 API, новый Flex SDK и сел делать свой Bump Mapping «с блэкджеком и шлюхами (с)». Для начала, следует подточить напильником старый добрый Flex Builder 3 как написано тут:

  1. Качаем Flex SDK nightly build.
  2. Распаковываем его в папку sdks в папке Flex Builder’a.
  3. Создаем новые ActionScript project.
  4. Где нам предлагают выбрать какой SDK использовать, тыкаем на “Configure Flex SDKs”.
  5. Добавляем наш новый SDK, жмем ОК и выбираем его из списка для создаваемого проекта, нажимаем Finish.
  6. Идем в свойства проекта, закладка Build Path -> Library Path, там убираем playerglobal.swc.
  7. Там же справа жмем на кнопку Add SWC, выбираем playerglobal.swc, который находится по адресу frameworks/libs/player/10/.
  8. Устанавливаем ему Link Type в External.
  9. Идем в закладку ActionScript Compiler, ставим версиюплеера 10.0.0.
  10. Убедитесь, что у вас установлен Flash Player 10, а лучше скачайте Standalone Debug Flash Player 10.

Все, теперь можно компилить и тестить приложения под десятку.

Сгибаем шейдер.

Само собой, нам понадобится Adobe Pixel Bender Toolkit для создания шейдера. Программа не блещет функциональностью и, честно говоря, весьма кривая. Также, кроме встроенных pdf’ок особой документации я не нашел. Да и то, что там написано, частично не работает, например «Сгибальщик» отказывался хавать функции min и max, rоторые в доках описаны.

В итоге методом проб и ошибок я подобрал следующий код для бамп мэппинга. Он берет две картинки: оригинальную картинку и карту выпуклости. Положение и яркость источника света меняется слайдерами.

<languageVersion: 1.0;>
kernel map
<
namespace : "AIF";
vendor : "Valentin valyard Simonov";
version : 2;
description : "A simple bump mapping shader";
>

{
  input image4 src; // оригинальная картинка
  input image4 map; // карта нормалей
  output float4 dst; // пиксель на выходе

  parameter float3 light // параметры света
  <
    minValue:float3(0, 0, 0);
    maxValue:float3(255, 255, 255);
    defaultValue:float3(0, 0, 40);
  >;
  void evaluatePixel()
  {
    float3 light = light.xyz - float3(outCoord().x, outCoord().y, 0); // создаем свой вектор света для каждого пикселя
    light = normalize(light);
    float3 normal = 2.0*(sampleNearest(map, outCoord()).rgb - 0.5); // читаем нормаль из карты для текущего пикселя
    float dp = dot(normal, light); // скалярное произведения нормали на вектор света
    if (dp < 0.0) dp = 0.0; // ограничиваем от нуля до 1
    if (dp > 1.0) dp = 1.0;
    dst = float4(0, 0, 0, 1);
    dst.rgb = sampleNearest(src, outCoord()).rgb * dp; // умножаем текущий цвет на коэффициент
  }
}

Немного неправильно называть картинку картой выпуклостей. Это карта нормалей к поверхности. Пространство трехмерное, картинка разбивается на три цветовых канала: красный, зеленый и синий. Берем и кодируем направление вектора нормали в трех цветах.

Вставляем во Флэш.

Сперва я пытался использовать ShaderFilter, но несмотря на то, что в хэлпе отчетливо сказано, что картинка вставляется в первый input параметр автоматически, никуда она не вставлялась, а плеер ругался на то, что свойство src не установлено. В итоге я вручную стал устанавливать все свойства и рисовать через Graphics.beginShaderFill.

package {
 import flash.display.Bitmap;
 import flash.display.BitmapData;
 import flash.display.Shader;
 import flash.display.Sprite;
 import flash.events.Event;
 import flash.events.MouseEvent;
 import flash.filters.ShaderFilter;
 import flash.text.StyleSheet;
 import flash.text.TextField;
 import flash.text.TextFormat;	[SWF(width="500", height="256", backgroundColor="0x000000", frameRate="500")]
 public class bump_mapping_flash_10 extends Sprite
 {
	[Embed(source="bumpmap.pbj", mimeType="application/octet-stream")]
 	protected var BumpMapFilter:Class;
 	[Embed(source="img.jpg")]
 	protected var SourceImage:Class;
 	[Embed(source="map.jpg")]
 	protected var MapImage:Class;
	protected var bumpMapShader:Shader;
 	protected var shaderFilter:ShaderFilter;
 	protected var source_img:Bitmap;
 	protected var map_img:Bitmap;
 	protected var result_mc:Sprite;
	protected var light:Number = 40;

	public function bump_mapping_flash_10()
 	{
 		initImages();
 		initShader();

		var fps:FPSCounter = new FPSCounter();
 		addChild(fps);

 		fps.y = 240;
 		fps.x = 10;
		var text:TextField = new TextField();
 		text.text = "Move mouse and use scroll to change \nlight intensity";
 		text.textColor = 0xFFFFFF;
 		text.selectable = false;
 		text.width = 300;
 		addChild(text);
 		text.x = 10;
 		text.y = 210;

		addEventListener(MouseEvent.MOUSE_MOVE, handlerMouseMove);
 		addEventListener(MouseEvent.MOUSE_WHEEL, handlerMouseWheel);
 		redraw();
 	}

	protected function initImages():void
 	{
		result_mc = new Sprite;
 		addChild(result_mc);
 		result_mc.x = 0;
 		result_mc.y = 0;
		source_img = new SourceImage();
 		map_img = new MapImage();
 		addChild(source_img);
 		source_img.x = 250;
 		addChild(map_img);
 		map_img.x = 512;
 	}

	protected function initShader():void
 	{
		// устанавливаем параметры шейдера, в том числе и картинки
 		bumpMapShader = new Shader(new BumpMapFilter());
		var bmp:BitmapData = new BitmapData(map_img.width, map_img.height);
 		bmp.draw(map_img);
 		var src:BitmapData = new BitmapData(map_img.width, map_img.height);
 		src.draw(source_img);
		bumpMapShader.data.src.input = src;
 		bumpMapShader.data.map.input = bmp;
 	}

	protected function redraw():void
 	{
 		bumpMapShader.data.light.value = [result_mc.mouseX, result_mc.mouseY, light]
		result_mc.graphics.clear();
 		result_mc.graphics.lineStyle(0);
 		result_mc.graphics.beginShaderFill(bumpMapShader);
 		result_mc.graphics.moveTo(0, 0);
 		result_mc.graphics.lineTo(255, 0);
 		result_mc.graphics.lineTo(255, 255);
 		result_mc.graphics.lineTo(0, 255);
 		result_mc.graphics.lineTo(0, 0);
 		result_mc.graphics.endFill();
 	}

	protected function handlerMouseMove(evt:MouseEvent):void
 	{
 		redraw();
 	}

	protected function handlerMouseWheel(evt:MouseEvent):void
 	{
 		light += evt.delta;
 		redraw();
 	}
 }
}

Итог.

В Standalone Player этот код выполняется на 220 FPS, а в IE всего 62. Он на столько медленнее или там какое-от ограничение? В любом случае, при использовании одинаковой логики мое творение непосредственно во флэше работает раз в 60 медленнее.

Теперь надо бы узнать как полегче генерить эти карты нормалей. Ну и взглянуть трезвым взглядом в понедельник, чтобы что-то заоптимизировать.