Collada Import & Bone [Alternativa3D 7.6]
とりあえず、アニメシーケンス設定しない状態で読み込んだ、Bone付きSkinを読み込んで、直接bone(Joint)を操作したサンプルです。
7.5.0では、フリーの3Dツール、Blenderから吐き出したColladaファイル(Dae)は、Boneを設定すると正しくParse出来なかったのですが、7.5.1で、修正された模様です。
ローカルでテストする場合は、最新のSWCを入手してください。
なお、直接プリミティブを作成し、Boneを埋め込むテストもしてみましたが、残念ながらBoneとSkinの頂点関連付けにバグ?があるのか(はたまた、必要なメソッドが公開されてないのか・・・)で、現Ver7.5.1でもできませんでした:P
書ききれないので、ソースコード中のコメントに続くw
2011/01/12 7.5から7.6仕様に変更
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/dJHS
*/
// forked from narutohyper's Alternativa3D 7.5 Template
package
{
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Debug;
import alternativ7.engine3d.core.Sorting;
import alternativ7.engine3d.loaders.ParserCollada;
import alternativ7.engine3d.materials.FillMaterial;
import alternativ7.engine3d.objects.Joint;
import alternativ7.engine3d.objects.Mesh;
import alternativ7.engine3d.objects.Skin;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
/**
* Alternativa3D 7.5
*
* Collada(dae)ファイルの読み込み、パースとBoneの操作
*
* とりあえず、アニメシーケンス設定しない状態で読み込んだ、Bone付きSkinを読み込んで、直接bone(Joint)を操作したサンプルです。
*
* 7.5.0では、フリーの3Dツール、Blenderから吐き出したColladaファイル(Dae)は、
* Boneを設定すると正しくParse出来なかったのですが、7.5.1で、修正された模様です。
* ローカルでテストする場合は、最新のSWCを入手してください。
*
* なお、直接プリミティブを作成し、Boneを埋め込むテストもしてみましたが、
* 残念ながらBoneとSkinの頂点関連付けにバグ?があるのか(はたまた、必要なメソッドが公開されてないのか・・・)で、
* 現Ver7.5.1でもできませんでした:P
*
* 書き出しに使用した、Blenderファイル
* 'http://marubayashi.net/archive/sample/alt3d7/bone/boxAndBone.blend'
*
* Blenderは、かなりクセがあるTOOLですが、現状フリーでBone付きアニメがColladaで書き出せるTOOLはこれだけなので、
* なんとか使いこなして行きたいものです。(3DMaxは高すぎて買えないしw)
* そのうち、Blenderからのalternativa3Dへの描き出しとか、ブログにあっぷします・・・たぶんw
* なお、最新のBlenderのColladaプラグインでも、へっぽこデータしか出てこないので、以下kumaryu.netサイトから、
* パッチを入手し充てておく必要あり
* http://www.kumaryu.net/?(Blender)+COLLADA+Exporter
*
* kumaryu.net様に多謝
*
* @author narutohyper
*/
[SWF(backgroundColor="#000000", frameRate="100", width="800", height="600")]
public class Main extends Sprite
{
private var loader:URLLoader;
private var modelURL:String = 'http://marubayashi.net/archive/sample/alt3d7/bone/boxAndBone.dae';
private const SCALE:Number = 5;
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event=null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//daeファイルの読み込み
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onModelLoad);
loader.load(new URLRequest(modelURL));
}
private function onModelLoad(e:Event):void {
loader.removeEventListener(Event.COMPLETE, onModelLoad);
//AlternativaTemplate作成
var scene:AlternativaTemplate = new AlternativaTemplate(this);
//Objectを格納するContainer(ObjectContainerでもいい気がするが・・・)
var colladaContainer:ConflictContainer = new ConflictContainer();
scene.container.addChild(colladaContainer);
// 注意!!
//Blenderが吐き出すDaeファイルでは、以下の置換が必要
//Daeで直接書き直してもOKだが、ファイルエクスポートの度に書き直すのはめんどくさいので、置換
var myPattern:RegExp = /IDREF/g;
loader.data=loader.data.replace(myPattern, "Name");
//----------------------------------------------------
//Pars
//----------------------------------------------------
var collada:ParserCollada = new ParserCollada();
collada.parse(XML(loader.data), modelURL);
var objects:* = collada.objects;
//----------------------------------------------------
//objectの抜き出し
//----------------------------------------------------
var count:int = objects.length;
var i:int;
var testSkin:Skin;
for (i = 0; i < count; i++) {
if (objects[i].name == 'Camera') {
//trace(objects[o].name,o)
} else {
if (objects[i].constructor == Mesh) {
} else if (objects[i].constructor == Skin) {
//カメラや、ライトは、Object3Dとして書き出される。
//アーマチュアー(Bone)を関連付けされたMeshはSkinとして書き出される
//Boneが関連付けされていないMeshはMeshとして書き出される
testSkin = objects[i] as Skin;
//必ず、calculateBindingMatricesを実行。しないと、3Dモデルがつぶれます。(時に、ぐちゃぐちゃになる)
testSkin.calculateBindingMatrices();
testSkin.sorting = Sorting.AVERAGE_Z;
testSkin.scaleX = SCALE;
testSkin.scaleY = SCALE;
testSkin.scaleZ = SCALE;
colladaContainer.addChild(testSkin);
}
}
}
//読み込んだSkinからBone(Joint)を取り出す;
//(Blenderが吐き出すBoneはJoint)
testSkin.y = 0;
var bones:Vector.<Joint> = new Vector.<Joint>;
//rootBoneの取得
bones[0] = testSkin.getJointAt(0);
bones[1] = bones[0].getChildAt(0);
//bones[1].rotationX=140*Math.PI/180
//material
var material:FillMaterial = new FillMaterial(0xCCCCFF,1,0,1);
testSkin.setMaterialToAllFaces(material);
//----------------------------------------------------
// Camera controller
//----------------------------------------------------
var colladaController:SimpleObjectController = new SimpleObjectController(stage, colladaContainer, 200);
colladaController.mouseSensitivity = 0.5;
colladaController.unbindAll();
scene.camera.debug = true;
addChild(scene.camera.diagram);
scene.camera.debug = true;
scene.camera.addToDebug(Debug.BONES, Joint);
//BlenderDaeはJointなので、Debug.BONESでは表示できない?
//JointをBoneに変換も出来ず(頂点の関連付けが、現Verではどうやらバグがある?為)
//scene.camera.addToDebug(Debug.BONES, bones[0]);
//scene.camera.addToDebug(Debug.EDGES, Skin);
//カメラの調整
//カメラはControllerに関連付けている為、x,y,zで直接位置を指定できないので
//SimpleController.setObjectPosXYZを使用
scene.cameraController.setObjectPosXYZ(0, -100, 0);
scene.cameraController.lookAtXYZ(0, 0, 0);
var angle:Number = 0;
var RADIAN:Number = Math.PI / 180;
scene.onPreRender = function():void {
//Boneをうねうね動かす。
angle+=4;
bones[1].rotationZ = (Math.cos(angle * RADIAN) * 60+180) * RADIAN;
colladaController.update();
}
//描画開始
scene.startRendering();
}
}
}
/**
* BasicTemplate for Alternativa3D 7.5
* Alternativa3D 7.5を扱いやすくするためのテンプレートです
* @author narutohyper & clockmaker
*
*/
import alternativ7.engine3d.containers.BSPContainer;
import alternativ7.engine3d.containers.ConflictContainer;
import alternativ7.engine3d.containers.DistanceSortContainer;
import alternativ7.engine3d.containers.KDContainer;
import alternativ7.engine3d.containers.LODContainer;
import alternativ7.engine3d.controllers.SimpleObjectController;
import alternativ7.engine3d.core.Camera3D;
import alternativ7.engine3d.core.Object3DContainer;
import alternativ7.engine3d.core.View;
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
class AlternativaTemplate extends Sprite
{
/**
* 子オブジェクトを最適な方法でソートするコンテナ
* (ConflictContainer)
*/
public static const CONFLICT:String = 'conflict';
/**
* 子オブジェクトをBSP(バイナリ空間分割法)によってソートするコンテナ
* (BSPContainer)
*/
public static const BSP:String = 'bsp';
/**
* 子オブジェクトをカメラからのZ値でソートするコンテナ
* (DistanceSortContainer)
*/
public static const ZSORT:String = 'zsort';
/**
* KDツリー(http://ja.wikipedia.org/wiki/Kd%E6%9C%A8)によってソートするコンテナ
* (KDContainer)
*/
public static const KD:String = 'kd';
/**
* detalizationと子オブジェクトの距離でソートするコンテナ(詳細は調査中)
* (LODContainer)
*/
public static const LOD:String = 'lod';
/**
* 3dオブジェクト格納するコンテナインスタンス。
*/
public var container:Object3DContainer;
/**
* ビューインスタンスです。
*/
public var view:View;
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraController:SimpleObjectController;
private var _mc:DisplayObjectContainer;
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
private var _containerType:String;
/**
* 新しい Alternativa3DTemplate インスタンスを作成します。
* @param mc
* @param containerType
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function AlternativaTemplate(mc:DisplayObjectContainer,containerType:String=CONFLICT,viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true)
{
_mc = mc;
_mc.addChild(this);
_containerType = containerType;
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
protected function atPreRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング前に実行したい処理をオーバーライドして記述します。
*/
private var _onPreRender:Function = function():void{};
public function get onPreRender():Function { return _onPreRender; }
public function set onPreRender(value:Function):void
{
_onPreRender = value;
}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理をオーバーライドして記述します。
*/
protected function atPostRender():void {}
/**
* Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
private var _onPostRender:Function = function():void{};
public function get onPostRender():Function { return _onPostRender; }
public function set onPostRender(value:Function):void
{
_onPostRender = value;
}
/**
* レンダリングを開始します。
*/
public function startRendering():void
{
addEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* レンダリングを停止します。
*/
public function stopRendering():void
{
removeEventListener(Event.ENTER_FRAME, onRenderTick);
}
/**
* シングルレンダリング(レンダリングを一回だけ)を実行します。
*/
public function singleRender():void
{
onRenderTick();
}
/**
* @private
*/
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
//Root objectの作成
if (_containerType == CONFLICT) {
container = new ConflictContainer();
} else if (_containerType == BSP) {
container = new BSPContainer();
} else if (_containerType == ZSORT) {
container = new DistanceSortContainer();
} else if (_containerType == KD) {
container = new KDContainer();
} else if (_containerType == LOD) {
container = new LODContainer();
}
//Viewの作成
view = new View(stage.stageWidth, stage.stageHeight);
_mc.addChild(view);
//cameraの作成
camera = new Camera3D();
camera.view = view;
camera.x = 0;
camera.y = -500;
camera.z = 0;
container.addChild(camera);
// Camera controller
cameraController = new SimpleObjectController(stage, camera, 10);
cameraController.mouseSensitivity = 0;
cameraController.unbindAll();
cameraController.lookAtXYZ(0, 0, 0);
onResize();
stage.addEventListener(Event.RESIZE, onResize);
atInit();
}
/**
* @private
*/
private function onResize(e:Event = null):void
{
if (_scaleToStage)
{
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}
else
{
view.width = _viewWidth;
view.height = _viewHeight;
}
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void
{
atPreRender();
_onPreRender();
cameraController.update();
camera.render();
atPostRender();
_onPostRender();
}
}