Flashの3D表現ライブラリの1つである、Alternativa3Dに手を出してみました。
使ってるバージョンは7.5です。
今回は、Object3Dが持つ関数の1つの「intersectRay」を使ってみました。
Alternativa3D公式のサンプルを参考にしています。
で、作ったのはこれ。
クリックすると、スタンプみたいなのが押されるはず。
以下ソースです。
package
{
import alternativa.engine3d.containers.DistanceSortContainer;
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.MouseEvent3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.RayIntersectionData;
import alternativa.engine3d.core.View;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.primitives.Box;
import alternativa.engine3d.primitives.Plane;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
[SWF(backgroundColor=0x000000)]
public class Main extends Sprite
{
[Embed(source="image.png")]
private var img:Class;
private static const RADIAN:Number = Math.PI/180;
private var rootContainer:DistanceSortContainer;
private var camera:Camera3D;
private var view:View;
private var stamp:Shape;
private var stamp_x:Number;
private var stamp_y:Number;
public function Main()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
stage.frameRate = 30;
// ベースとなるコンテナ。
rootContainer = new DistanceSortContainer();
rootContainer.sortByZ = true;
// カメラの初期化 (PV3Dでいうフリーカメラみたいなの)。
camera = rootContainer.addChild(new Camera3D) as Camera3D;
camera.z = -800;
camera.y = -400;
camera.rotationX = -30*RADIAN;
// ビューポート (View is DisplayObject)
view = new View(stage.stageWidth, stage.stageHeight);
view.logoAlign = StageAlign.TOP_LEFT;
view.logoHorizontalMargin = 80;
camera.view = addChild(view) as View;
view.interactive = true;
// デバッグ情報を表示する場合は記述
camera.diagramAlign = StageAlign.TOP_LEFT;
addChild(camera.diagram);
// スタンプを作成
stamp = new Shape;
var bmpd:BitmapData = (new img as Bitmap).bitmapData;
stamp_x = -bmpd.width*0.5;
stamp_y = -bmpd.height*0.5;
var g:Graphics = stamp.graphics;
g.beginBitmapFill(bmpd);
g.drawRect(0,0, bmpd.width, bmpd.height);
g.endFill();
// Boxを配置
var box:Box = rootContainer.addChild(new Box(180, 180, 180)) as Box;
var color:Array = [0xc7632e, 0xffdef7, 0x0000ff, 0xede07a, 0x00ffff, 0xd6def7];
for(var i:int=0 ; i<6 ; i++) box.faces[i].material = new TextureMaterial(new BitmapData(400,400,false,color[i]));
box.x = box.y = box.z = 0;
box.rotationY = 45*RADIAN;
// Planeを配置
var plane:Plane = rootContainer.addChild(new Plane(800, 800)) as Plane;
plane.setMaterialToAllFaces(new TextureMaterial(new BitmapData(700,700,false, 0x388c31)));
plane.rotationX = 90*RADIAN;
plane.rotationY = 45*RADIAN;
plane.y = 90;
// イベントの追加
rootContainer.addEventListener(MouseEvent3D.MOUSE_DOWN, onMouseDown);
addEventListener(Event.ENTER_FRAME, onFrame);
stage.addEventListener(Event.RESIZE, onResize);
}
// マウスダウン時に実行される関数
private function onMouseDown(e:MouseEvent3D):void
{
// クリックされたオブジェクトを取得
var object:Object3D = e.target as Object3D;
// レイとポリゴンの交差部分を検索。その結果を取得。
var data:RayIntersectionData = object.intersectRay(e.localOrigin, e.localDirection);
if (data != null)
{
// 交差部分の検索による、直近のマテリアルを取得
var texture:BitmapData = (data.face.material as TextureMaterial).texture;
// UV値の取得
var uv:Point = data.face.getUV(data.point);
// スタンプを押す位置を計算
var mat:Matrix = new Matrix;
mat.translate(stamp_x, stamp_y);
mat.rotate(Math.PI*Math.random());
mat.translate(uv.x*texture.width, uv.y*texture.height);
texture.draw(stamp, mat);
}
}
private function onResize(e:Event):void
{
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}
private function onFrame(e:Event):void
{
camera.render();
}
}
}
