пятница, 15 апреля 2011 г.

Использование карты прозрачности (ActionScript)

Преамбула:
Заказали как то раз сварганить флешку назначение которой было простое: обеспечить возможность всестороннего разглядывания новой упаковки, с достаточно фотореалистичным отображением. Т.к. нужен всесторонний обзор, решено было крутить-вертеть упаковку в 3D пространстве.

В качестве движка заюзал, всеми горячо любимый (особенно после нового лицензионного соглашения, разрешающего свободное его использование), движек Alternativa3D. Особенно кстати пришлась вышедшая, к началу работы над проектом, версия 7.7. Где были добавлены новые материалы, свет и проч.

Модель во флешке собирается в рантайме, т.е. подгружаются/вкоприливаются необходимые ресурсы (3DS-модель + текстуры), средствами движка парсится модель, на основе текстур создаются соответствующие материалы, все это накладывается/состыковывается.

Встала проблема с прозрачностью некоторых материалов, а именно материала покрывающего большую часть модели (упаковка полупрозрачная). В библиотеке движка есть такой полезный класс как MaterialLoader, которому нужно скормить Vector из экземпляров класса TextureMaterial или его потомков с предварительно заполненными полями (урл дифузной текстуры, урл текстуры карты прозрачности, ...). Т.к. создание материалов идет "вручную", то MaterialLoader мне показался плохим помощником. В башке зародилась мысля, а что если в качестве дифузной текстуры скормить предварительно подготовленную текстуру с наложенной картой прозрачности. Осталось дело за малым - наложить эту самую карту прозрачности.

Проблема:
Применить к текстуре карту прозрачности.

Решение:
Родился единственный метод который эту карту накладывает.
private function overlayOpacityMap(texture:BitmapData, opacityMap:BitmapData):BitmapData
{
   if (!opacityMap)
      return texture;
   
   var retval:BitmapData = new BitmapData(texture.width, texture.height, true, 0xffffffff);
   
   retval.copyPixels(texture, new Rectangle(0, 0, texture.width, texture.height), new Point());
   
   var textureColor:uint;
   var opacityColor:uint;
   for (var px:int = 0; px < retval.width; px++) 
   {
      for (var py:int = 0; py < retval.height; py++) 
      {
         textureColor = retval.getPixel32(px, py);
         opacityColor = opacityMap.getPixel(px, py);
         
         opacityColor &= 0x0000ff;
         textureColor &= 0x00ffffff;
         textureColor |= (0xff - opacityColor) << 24; 
         
         retval.setPixel32(px, py, textureColor);
      }
   }
   
   return retval;
}
В результате волшебных пассов результат получился достаточно достойным и фотореалистичным, жаль заказчик не понял всю "тяжесть, степень, глубину" и в финальной стадии разработки принял решение заменить 3D на секвенцию из 30, на мой взгляд, не лучшим образом отфотканных ракурсов.
В дополнение к выше сказанному привожу скриншот демо-проектика(used FlashDevelop) демонстрирующего наложение карты прозрачности на изображение.

В ходе написания данного поста, вспомнил, что видел где-то данный подход для эмуляции (назову её так) изображений в формате PNG с прозрачностью, и это надо сказать очень эффективно в плане трафика и места для хранения изображений аля png, по другим параметрам может и уступает.

По использованным в демо-проекте изображениям картина выглядит так:
  1. исходное изображение (jpg) + серая карта прозрачности (jpg) = 29.8 + 15.7 = 45.4 Кб
  2. исходное изображение (png) = 155.8 Кб

1 комментарий: