2010年4月16日金曜日

[Pv3D] Meteor Attack(@wonderfl)の解説

一時的にだけど、[Pv3D] Meteor AttackWonderflでデイリーのPVで一位になったのを記念に解説をこちらのほうでやってみます。


と言ってもこれはそんなに難しいことをしているわけではないんですよね。
やっていることをまとめると、
「球(スフィア)の配置」「カメラ、ライト移動のためのイベント」「画像のロード」「シェーダー、マテリアルの設定」「球(スフィア)のクリックイベント」「アニメーション」「バンプマップの更新」
ぐらいです。

全部説明するのは面倒疲れるので、「球(スフィア)のクリックイベント」「バンプマップの更新」だけ解説します。
該当部はここらへん。
//private function onMapComplete(e:Event):void {
private function onMapComplete():void {
 //var bmpData:BitmapData = new BitmapData(e.target.loader.width, e.target.loader.height);
 var loader1:Loader = imageArray.pop();
 var bmpData:BitmapData = new BitmapData(loader1.width, loader1.height);
 bmpData.draw(loader1);
 moonBmpData = bmpData;
 var loader2:Loader = imageArray.pop();
 bmpData = new BitmapData(loader2.width, loader2.height);
 bmpData.draw(loader2);
 bumpBmpData = bmpData;
 scene.addChild(light);
 
 shader = new PhongShader(light, 0xFFFFFF, 0x666666, 0, bumpBmpData);
 var material:ShadedMaterial = new ShadedMaterial(new BitmapMaterial(moonBmpData), shader);
 material.interactive = true;
 material.smooth = true;
 var sphere:Sphere = new Sphere(material, 100, 15, 15);
 sphere.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onObjectClick);
 scene.addChild(sphere);
 
 var particles:ParticleField = new ParticleField(new ParticleMaterial(0xffffff, 1, 1), 200, 2, 500, 500, 500);
 scene.addChild(particles);
}

private function onObjectClick(e:InteractiveScene3DEvent):void {
 var ball:Sphere = new Sphere(new ColorMaterial(0xEEEEEE), 10);
 scene.addChild(ball);
 var tween:ITween = BetweenAS3.tween(ball, {x: e.renderHitData.x * 0.9, y: e.renderHitData.y * 0.9, z: e.renderHitData.z * 0.9}, {x: e.renderHitData.x * 3.5, y: e.renderHitData.y * 3.5, z: e.renderHitData.z * 3.5});
 tween.play();
 tween.onComplete = function():void {
  var sp:Sprite = new Sprite();
  sp.graphics.beginFill(0xFFFFFF);
  sp.graphics.drawCircle(25, 25, 20);
  sp.graphics.endFill();
  sp.graphics.beginFill(0x000000);
  sp.graphics.drawCircle(25, 25, 17);
  sp.graphics.endFill();
  var bmpData:BitmapData = new BitmapData(50, 50, true, 0x00000000);
  bmpData.draw(sp);
  bumpBmpData.draw(bmpData, new Matrix(1, 0, 0, 1, e.x * 1000 - 25, e.y * 500 - 25));
  shader.bumpmap = bumpBmpData;
  scene.removeChild(ball);
 }
}
上のほうはシェーダーの設定です。
sphere.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onObjectClick);
でSphereのクリックイベントを設定しています。

で、イベントハンドラで、
(InteractiveScene3DEvent).x及び、(InteractiveScene3DEvent).yは、SphereのマテリアルのUV情報、
(InteractiveScene3DEvent).renderHitData.x(.y, .z)は、クリックしたXYZ座標の値を取ってくることができます。
UVについてはこちらが自分はわかりやすいと思いました。英語だけど。
要するに、UVの値からテクスチャにおける座標を取得したいと思ったら、UVそれぞれにテクスチャの幅と高さを掛けてやれば良いわけです。
(InteractiveScene3DEvent).x * (image).widthという感じで。

上記のプログラムの32行目~は、外側が白で、内側が黒の円を描いて、円の中心がクリックした点になるように移動し、shader.bumpmap = bumpBmpData;でバンプマップを更新しているわけです。

バンプマップを更新したところで、地味で目立たないですね。
というかこれ、以前の記事のプログラムの流用です。

・・・解説下手だなー。