ProjectionMappingできるかな


先日ここでも告知した、「Flashとおやつの会(学生歓迎編)」では、最終日には参加者が作ったムービーをプロジェクションマッピングにして表示してみました。プロジェクションマッピング用の映像の変形もFlashで行っています。


プロジェクションマッピング用の変形などの処理は私のほうで用意して、投影内容のアニメーションは参加者が作りました。

よくある、キューブの三面に投影することを前提にして、シンプルなUIを目指しました。

ProjectionMappingできるかな4 – wonderfl build flash online

[sourcecode language=”as3″]
package
{
import flash.display.Sprite;
import flash.events.Event;
/**
* …
* @author umhr
*/
[SWF(width = 465, height = 465, backgroundColor = 0x000000, frameRate = 30)]
public class WonderflMain extends Sprite
{

private var maru:Sprite = new Sprite();
public function WonderflMain():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}

private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point

stage.scaleMode = "noScale";
stage.align = "TL";

addChild(new Canvas());
stage.addEventListener(Event.RESIZE, stage_resize);

stage_resize(null);
}
private function stage_resize(event:Event):void
{
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill();
}

}

}

import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
/**
* …
* @author umhr
*/
class Box extends Sprite
{

public function Box()
{
init();
}

private function init():void
{
if (stage) onInit();
else addEventListener(Event.ADDED_TO_STAGE, onInit);
}

private var _handleList:Vector.<Sprite> = new Vector.<Sprite>();
private var _diamondList:Vector.<Diamond> = new Vector.<Diamond>();
//private var _movieResource:MovieResource = new MovieResource();
private var _resourceManager:ResourceManager = ResourceManager.getInstance();
private var _isHideUI:Boolean;

private function onInit(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// entry point

var n:int = 0;
var i:int = 0;

for (i = 0; i < 3; i++)
{
var diamond:Diamond = new Diamond();
addChild(diamond);
_diamondList[i] = diamond;
diamond.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
}

n = 7;
for (i = 0; i < n; i++)
{
var handle:Sprite = new Sprite();
handle.graphics.lineStyle(0, 0xFFFFFF);
handle.graphics.beginFill(0xFF0000, 0.3);
handle.graphics.drawCircle(0, 0, 10);
handle.graphics.endFill();
if(i > 0){
handle.x = Math.sin((i / 6) * 2 * Math.PI) * 100;
handle.y = -Math.cos((i / 6) * 2 * Math.PI) * 100;
}
handle.addEventListener(MouseEvent.MOUSE_DOWN, handle_mouseDown);
addChild(handle);
_handleList.push(handle);
}

x = 200;
y = 200;

}

private function mouseDown(event:MouseEvent):void
{
startDrag();
parent.addChild(this);
}

private function handle_mouseDown(event:MouseEvent):void
{
var handle:Sprite = (event.target) as Sprite;
handle.startDrag();
}

public function mouseUp():void
{
stopDrag();
var n:int = _handleList.length;
for (var i:int = 0; i < n; i++)
{
_handleList[i].stopDrag();
}
}

public function enterFrame():void
{
if (hasEventListener(Event.ADDED_TO_STAGE)) {
return;
}

_diamondList[0].setDiamond(Vector.<Point>([new Point(_handleList[0].x, _handleList[0].y),new Point(_handleList[1].x, _handleList[1].y),new Point(_handleList[2].x, _handleList[2].y),new Point(_handleList[3].x, _handleList[3].y)]));
_diamondList[1].setDiamond(Vector.<Point>([new Point(_handleList[0].x, _handleList[0].y),new Point(_handleList[5].x, _handleList[5].y),new Point(_handleList[4].x, _handleList[4].y),new Point(_handleList[3].x, _handleList[3].y)]));
_diamondList[2].setDiamond(Vector.<Point>([new Point(_handleList[0].x, _handleList[0].y),new Point(_handleList[1].x, _handleList[1].y),new Point(_handleList[6].x, _handleList[6].y),new Point(_handleList[5].x, _handleList[5].y)]));

var bitmapData:BitmapData = _resourceManager.getBitmapData();

_diamondList[0].bitmapData = bitmapData.clone();
_diamondList[1].bitmapData = bitmapData.clone();
_diamondList[2].bitmapData = bitmapData.clone();
}

public function set isHideUI(value:Boolean):void
{
if (_isHideUI == value) { return; };
_isHideUI = value;

var i:int;
var n:int = _handleList.length;
for (i = 0; i < n; i++)
{
_handleList[i].visible = !_isHideUI;
}
n = _diamondList.length;
for (i = 0; i < n; i++)
{
_diamondList[i].isHideUI = _isHideUI;
}
}

public function getPositionList():Vector.<Point> {
var result:Vector.<Point> = new Vector.<Point>();
result[0] = new Point(x, y);

var i:int;
var n:int = _handleList.length;
for (i = 0; i < n; i++)
{
result.push(new Point(_handleList[i].x, _handleList[i].y));
}

return result;
}

public function setPositionList(positionList:Vector.<Point>):void {
x = positionList[0].x;
y = positionList[0].y;

var i:int;
var n:int = positionList.length – 1;
for (i = 0; i < n; i++)
{
_handleList[i].x = positionList[i + 1].x;
_handleList[i].y = positionList[i + 1].y;
}

}
}

import flash.display.BitmapData;
import flash.geom.Matrix;
import flash.media.Camera;
import flash.media.Video;
/**
* …
* @author umhr
*/
class CameraManager
{
private static var _instance:CameraManager;
public function CameraManager(block:SingletonBlock){init();}
public static function getInstance():CameraManager{
if ( _instance == null ) {_instance = new CameraManager(new SingletonBlock());};
return _instance;
}

private var _bitmapData:BitmapData;
private var _video:Video;
private var _matrix:Matrix;
private var _isCameraChecked:Boolean;
private function init():void
{
setSize(100, 100);
}

public function setSize(width:int, height:int):void {
_matrix = new Matrix();
var scale:Number = Math.max(width / 320, height / 240);
_matrix.scale(scale, scale);
_matrix.translate((width – 320 * scale) * 0.5, (height – 240 * scale) * 0.5);
_bitmapData = new BitmapData(width, height);

}

private function setCamera():void
{
var camera:Camera = Camera.getCamera();
//カメラの存在を確認
if (camera) {
camera.setMode(320, 240, 15);
_video = new Video(320, 240);
_video.attachCamera(camera);
_video.width = 320;
_video.height = 240;
} else {
trace("カメラが見つかりませんでした。");
}
_isCameraChecked = true;
}

public function getBitmapData():BitmapData {
if(_video){
_bitmapData.draw(_video, _matrix);
}else if (_isCameraChecked) {

}else{
setCamera();
}
return _bitmapData;
}

}

class SingletonBlock { };

import com.bit101.components.PushButton;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.ui.Mouse;
/**
* …
* @author umhr
*/
class Canvas extends Sprite
{

public function Canvas()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}

private var _isHideUI:Boolean;
private var _controller:Sprite = new Sprite();
private var _boxCanvas:Sprite = new Sprite();
private var _boxList:Vector.<Box> = new Vector.<Box>();
private var _mouseMoveCount:int = 0;
private var _sandBox:Sprite = new Sprite();
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);

stage.addEventListener(MouseEvent.MOUSE_UP, stage_mouseUp);
stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMove);
addEventListener(Event.ENTER_FRAME, enterFrame);

addChild(_boxCanvas);
addChild(_controller);

new PushButton(_controller, 0, 0, "AddBox", addBox);
new PushButton(_controller, 120, 0, "RemoveBox", removeBox);
new PushButton(_controller, 0, 30, "FullScreen", onFullScreen);
new PushButton(_controller, 0, 60, "WebCam", onWebCam);
new PushButton(_controller, 0, 90, "LoadSWC", onLoadSWC);

setBox();
}

private function onLoadSWC(event:MouseEvent):void {
if (event.target.label == "LoadSWC") {
var loadFile:LoadFile = new LoadFile();
loadFile.addEventListener(Event.COMPLETE, loadFile_complete);
loadFile.Start();
event.target.label = "UnLoadSWC";
}else if(event.target.label == "UnLoadSWC") {
ResourceManager.getInstance().displayObject = null;
event.target.label = "LoadSWC";
}

}
private function loadFile_complete(event:Event):void
{
addChild(_sandBox);
var content:Sprite = event.target.content;
_sandBox.visible = false;

ResourceManager.getInstance().displayObject = content;
_sandBox.addChild(content);
}

private function setBox():void
{
var boxArray:Vector.<Vector.<Point>> = SharedObjectManager.getInstance().getData();

var n:int = boxArray.length;
for (var i:int = 0; i < n; i++)
{
var box:Box = new Box();
_boxCanvas.addChild(box);
_boxList.push(box);
box.setPositionList(boxArray[i]);
}

if (n == 0) {
addBox(null);
}
}

private function stage_mouseMove(e:MouseEvent):void
{
_mouseMoveCount = 0;
}

private function addBox(event:MouseEvent):void {
var box:Box = new Box();
_boxCanvas.addChild(box);
_boxList.push(box);
}

private function removeBox(event:MouseEvent):void {

var n:int = _boxCanvas.numChildren;
if (n == 0) {
return;
}
var box:Box = _boxCanvas.getChildAt(n – 1) as Box;

_boxCanvas.removeChild(box);

for (var i:int = 0; i < n; i++)
{
if (_boxList[i] == box) {
_boxList.splice(i, 1);
return;
}
}
}

private function onFullScreen(event:MouseEvent):void {
if(stage.displayState == "normal"){
stage.displayState = "fullScreen";
}else{
stage.displayState = "normal";
}

}

private function onWebCam(event:MouseEvent):void {
ResourceManager.isCamera = !ResourceManager.isCamera;
}

private function enterFrame(event:Event):void
{
var n:int = _boxList.length;
for (var i:int = 0; i < n; i++)
{
_boxList[i].enterFrame();
}
_mouseMoveCount ++;

isHideUI = (_mouseMoveCount > 150);

if (_mouseMoveCount == 30) {
save();
}
}

private function stage_mouseUp(event:MouseEvent):void
{
var n:int = _boxList.length;
for (var i:int = 0; i < n; i++)
{
_boxList[i].mouseUp();
}
}

public function save():void {
var boxArray:Array = [];
var n:int = _boxCanvas.numChildren;
for (var i:int = 0; i < n; i++)
{
var box:Box = _boxCanvas.getChildAt(i) as Box;
var pointList:Array = [];
var positionList:Vector.<Point> = box.getPositionList();
var m:int = positionList.length;
for (var j:int = 0; j < m; j++)
{
pointList[j] = { x:positionList[j].x, y:positionList[j].y };

}
boxArray[i] = pointList;
}

SharedObjectManager.getInstance().setData(boxArray);
}

public function get isHideUI():Boolean
{
return _isHideUI;
}

public function set isHideUI(value:Boolean):void
{
if (_isHideUI == value) { return; };
_isHideUI = value;

if (_isHideUI) {
Mouse.hide();
}else {
Mouse.show();
}

_controller.visible = !_isHideUI;
var n:int = _boxList.length;
for (var i:int = 0; i < n; i++)
{
_boxList[i].isHideUI = _isHideUI;
}
}

}

import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Point;
/**
* …
* @author umhr
*/
class Diamond extends Sprite
{
private var _line:Shape = new Shape();
private var _fill:Shape = new Shape();
private var _isHideUI:Boolean;
private var _bitmapData:BitmapData;
public function Diamond()
{
init();
}
private function init():void
{
addChild(_line);
addChild(_fill);
}

public function setDiamond(positionList:Vector.<Point>):void {

_line.graphics.clear();
if(!_isHideUI){
_line.graphics.lineStyle(0, 0x00FF00);
_line.graphics.moveTo(positionList[0].x, positionList[0].y);
_line.graphics.lineTo(positionList[1].x, positionList[1].y);
_line.graphics.lineTo(positionList[2].x, positionList[2].y);
_line.graphics.lineTo(positionList[3].x, positionList[3].y);
_line.graphics.lineTo(positionList[0].x, positionList[0].y);
}
draw(positionList);
}

public function get bitmapData():BitmapData {
return _bitmapData;
}
public function set bitmapData(value:BitmapData):void {
_bitmapData = value;
}

public function draw(positionList:Vector.<Point>):void {
if (_bitmapData) {
_fill.graphics.clear();
_fill.graphics.beginBitmapFill(_bitmapData, null, false, true);
_fill.graphics.drawTriangles.apply(this, getTriangles(positionList));
_fill.graphics.endFill();
}
}

private function getTriangles(positionList:Vector.<Point>):Array {
var vertices:Vector.<Number> = new Vector.<Number>();

// x方向の分割数
var partitionX:int = 4;
// y方向の分割数
var partitionY:int = 4;

var p0:Point = positionList[0];
var p1:Point = positionList[1];
var p2:Point = positionList[3];
var p3:Point = positionList[2];

var m:int = partitionY + 1;
for (var j:int = 0; j < m; j++)
{
var dy:Number = j / (m – 1);
var t0x:Number = (p2.x – p0.x) * dy + p0.x;
var t0y:Number = (p2.y – p0.y) * dy + p0.y;
var t1x:Number = (p3.x – p1.x) * dy + p1.x;
var t1y:Number = (p3.y – p1.y) * dy + p1.y;

var n:int = partitionX + 1;
for (var i:int = 0; i < n; i++)
{
var dx:Number = i / (n – 1);
vertices.push((t1x – t0x) * dx + t0x, (t1y – t0y) * dx + t0y);
}
}

var indices:Vector.<int> = new Vector.<int>();

m = partitionY;
for (j = 0; j < m; j++)
{
var ty:int = j * (partitionX + 1);
n = partitionX;
for (i = 0; i < n; i++)
{
indices.push(ty + i + 0, ty + i + 1, ty + i + n + 2);
indices.push(ty + i + 0, ty + i + n + 1, ty + i + n + 2);
}
}

var uvtData:Vector.<Number> = new Vector.<Number>();
m = partitionY+1;
for (j = 0; j < m; j++)
{
n = partitionX+1;
for (i = 0; i < n; i++)
{
uvtData.push(i / (n – 1), j / (m – 1));
}
}

return [vertices, indices, uvtData];
}

public function set isHideUI(value:Boolean):void
{
if (_isHideUI == value) { return; };
_isHideUI = value;
}
}

import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.net.FileReference;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
class LoadFile extends EventDispatcher{
private var _fileReference:FileReference;
/**
* 開始
*/
public function Start():void
{
if(_fileReference){
return;
}
_fileReference = new FileReference();
_fileReference.browse();
_fileReference.addEventListener(Event.SELECT,atSelect);
}

public var content:*;

/**
* ファイルの選択が完了すると動く
* @param event
*
*/
private function atSelect(event:Event):void{
_fileReference.removeEventListener(Event.SELECT, atSelect);
_fileReference.addEventListener(Event.COMPLETE, atFileComplete);
_fileReference.load();
}
/**
* 選択したファイルを読み込み完了すると動く
* @param event
*
*/
private function atFileComplete(event:Event):void{
_fileReference.removeEventListener(Event.COMPLETE, atFileComplete);
var loader:Loader = new Loader();

var byteArray:ByteArray = event.target.data as ByteArray;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, atBytesComplete);
loader.loadBytes(byteArray, new LoaderContext());
}

/**
* 読み込んだファイルのバイトアレイを変換完了で動く
* @param event
*
*/
private function atBytesComplete(event:Event):void {
event.target.removeEventListener(Event.COMPLETE, atBytesComplete);
content = event.target.content;
dispatchEvent(event);
_fileReference = null;
}
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
import flash.display.PixelSnapping;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Rectangle;
/**
* …
* @author umhr
*/
class ResourceManager
{
private static var _instance:ResourceManager;
public function ResourceManager(block:SingletonBlock){init();}
public static function getInstance():ResourceManager{
if ( _instance == null ) {_instance = new ResourceManager(new SingletonBlock());};
return _instance;
}

static public var isCamera:Boolean;
private var _width:int = 200;
private var _height:int = 200;
private var _displayObject:DisplayObject;
private function init():void
{
CameraManager.getInstance().setSize(_width, _height);
}

private function getResource():Shape
{
var result:Shape = new Shape();
var tx:Number = 0;
var ty:Number = 0;
for (var i:int = 0; i < 25; i++)
{
tx = (i * (_width/5)) % _width;
ty = int(i / 5) * (_height/5);

if (new Date().seconds*0.5 > i) {
result.graphics.beginFill(0x666666);
}else {
result.graphics.beginFill(0x0000FF);
}

result.graphics.drawRect(tx, ty, (_width*0.1), (_height*0.1));

if (new Date().seconds * 0.5 > i + 0.5) {
result.graphics.beginFill(0x888888);
}else {
result.graphics.beginFill(0x0000FF);
}
result.graphics.drawRect(tx + (_width*0.1), ty + (_height*0.1), (_width*0.1), (_height*0.1));
result.graphics.endFill();
}
result.graphics.endFill();
result.graphics.beginFill(0xFFFF00);
result.graphics.drawRect(0, 0, _width, _height);
result.graphics.drawRect(_width*0.025, _height*0.025, _width*0.95, _height*0.95);
result.graphics.endFill();

result.graphics.beginFill(0xFF0000, 1);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.40);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.39);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.30);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.29);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.20);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.19);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.10);
result.graphics.drawCircle(_width*0.5, _height*0.5, _width*0.09);
result.graphics.endFill();

return result;
}

public function getBitmapData():BitmapData {
if (ResourceManager.isCamera) {
return CameraManager.getInstance().getBitmapData();
}
var result:BitmapData = new BitmapData(_width, _height, true, 0xFF000000);

if (_displayObject) {
var bitmap:Bitmap = new Bitmap(new BitmapData(465, 465, false, 0xFF000000), "auto", true);
var dx:Number = _width / 465;
var dy:Number = _height / 465;

bitmap.bitmapData.draw(_displayObject, new Matrix(dx, 0, 0, dy), null, null, null,true);

result.draw(bitmap, null, null, null, null,true);
}else {
result.draw(getResource());
}

return result;
}

public function set displayObject(value:DisplayObject):void {
_displayObject = value;
}

}

import flash.geom.Point;
import flash.net.SharedObject;
/**
* …
* @author umhr
*/
class SharedObjectManager
{
private static var _instance:SharedObjectManager;
public function SharedObjectManager(block:SingletonBlock){init();}
public static function getInstance():SharedObjectManager{
if ( _instance == null ) {_instance = new SharedObjectManager(new SingletonBlock());};
return _instance;
}

private function init():void
{

}

public function setData(data:Array ):void {
var sharedObject:SharedObject = SharedObject.getLocal("jpMztmMapping", "/");
if (sharedObject) {
var soData:Object = sharedObject.data;
soData["list"] = data;
sharedObject.flush();
}
}

public function getData():Vector.<Vector.<Point>> {
var sharedObject:SharedObject = SharedObject.getLocal("jpMztmMapping", "/");
if (sharedObject && sharedObject.data && sharedObject.data["list"]) {

var soData:Object = sharedObject.data;

var boxArray:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>();
var n:int = soData.list.length;
for (var i:int = 0; i < n; i++)
{

var pointList:Vector.<Point> = new Vector.<Point>();
var m:int = soData.list[i].length;
for (var j:int = 0; j < m; j++)
{
pointList[j] = new Point(soData.list[i][j].x, soData.list[i][j].y );
}
trace(pointList)
boxArray[i] = pointList;

}
//trace(boxArray)
return boxArray;
}else {
return new Vector.<Vector.<Point>>();
}
}

}

[/sourcecode]