Alternativa3D Tips 読み込んだ、3DSモデルの中身を操作する
Alternativa3D Tips 読み込んだ、3DSモデルの中身を操作する
Clickで、腕振ります
BetweenとかTweener使えば、滑らかに動かせますが、中身を操作するTIPSなので、そのあたりは適当です。
folk元は、まだalternativa template前の物でしたので、templateに移植してます。
@narutohyper
Alternativa3D で3Dモデルを読み込むテスト
マウスドラッグでミクを回せます
ライブラリでサポートしているファイルは「3DS」と「OBJ」(Colladaは対応していない)
このサンプルでは3dsファイルを読み込んでいます
3Dデータはnote.xさんのところのズサさんご提供のものを使用しています。
http://blog.r3c7.net/?p=121
※ColladaファイルをBlenderで3DSファイルに変換したものを使用
↑
この記事のデモと速度や表示を比較してみるといいかも
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/4Ixz
*/
// forked from clockmaker's [Alternativa3D] Negi Miku
package {
import alternativ5.engine3d.materials.FillMaterial;
import alternativ5.engine3d.primitives.Plane;
import alternativ5.engine3d.primitives.Cone;
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.core.Mesh;
import alternativ5.engine3d.events.MouseEvent3D
import alternativ5.engine3d.loaders.*;
import alternativ5.types.Point3D;
import alternativ5.types.Texture;
import alternativ5.utils.*
import flash.system.LoaderContext;
import flash.display.StageQuality;
import flash.display.Sprite;
import flash.display.BlendMode;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.GradientType;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.utils.getDefinitionByName;
import flash.text.*;
import flash.geom.Matrix;
import flash.utils.*;
[SWF(width = 465, height = 465, frameRate = 60,backgroundColor=0x000000)]
/**
* Alternativa3D Tips 読み込んだ、3DSモデルの中身を操作する
*
* Clickで、腕振ります
* BetweenとかTweener使えば、滑らかに動かせますが、中身を操作するTIPSなので、そのあたりは適当です。
*
* folk元は、まだalternativa template前の物でしたので、templateに移植してます。
*
* @narutohyper
*/
/**
* Alternativa3D で3Dモデルを読み込むテスト
* マウスドラッグでミクを回せます
*
* ライブラリでサポートしているファイルは「3DS」と「OBJ」(Colladaは対応していない)
* このサンプルでは3dsファイルを読み込んでいます
*
* 3Dデータはnote.xさんのところのズサさんご提供のものを使用しています。
* http://blog.r3c7.net/?p=121
* ※ColladaファイルをBlenderで3DSファイルに変換したものを使用
* ↑
* この記事のデモと速度や表示を比較してみるといいかも
*/
public class SimpleDemo extends Sprite {
public function SimpleDemo():void {
// テンプレートを作成します
var template:BasicTemplate = new BasicTemplate();
addChild(template);
template.camera.z = -500;
// FPS display launch
FPS.init(stage);
var dbg:TextField=new TextField()
dbg.autoSize=TextFieldAutoSize.LEFT
dbg.selectable=false;
dbg.mouseEnabled=false;
var format:TextFormat=new TextFormat();
format.color=0x666666
format.size=12;
format.font='_ゴシック';
dbg.defaultTextFormat=format
this.addChild(dbg)
var context:LoaderContext = new LoaderContext();
var loader:Loader3DS = new Loader3DS();
loader.addEventListener(Event.COMPLETE, loadCompleteHandler);
loader.load("http://clockmaker.jp/labs/090807_alternativa3d/test.3ds", context);
var lm:Object3D;
var rarm:Mesh
var negi:Mesh
var near:Mesh
var far:Mesh
function loadCompleteHandler(e:Event):void {
template.scene.root.addChild(loader.content);
loader.content.scaleX = loader.content.scaleY = loader.content.scaleZ = 20;
lm=loader.content
//読み込んだ3ds(Object3D)の子Objectにはnameがわかれば個別にアクセスできるようになります
//自分で作成したモデルなどでは、問題ありませんが、もし名前等がわからない場合は
//以下のような方法で調べます
//メソッド[Object3D.forEach()]ですべての子Object3Dにアクセスできます
lm.forEach(test)
function test():void {
//traceで('R_arm'、'negi'、'miku_near'、'miku_far'という名前のMeshが確認できます)
//ついでに、3dsモデルのゴミ掃除をします
if(this is Mesh) {
//trace('掃除前',this.name,this);
dbg.appendText('掃除前 '+this.name+' '+this+'\n')
//サーフェースに属していないFacsを削除します。
MeshUtils.removeSingularFaces(Mesh(this));
//直線上に存在する、Faceの頂点になっていない点を削除します
MeshUtils.removeUselessVertices(Mesh(this));
//使われていない、孤立した点を削除します
MeshUtils.removeIsolatedVertices(Mesh(this));
//同じ座標で複数存在する点を、一つにまとめます
MeshUtils.autoWeldVertices(Mesh(this), 0.01);
//重なっている、面を統合します。
MeshUtils.autoWeldFaces(Mesh(this), 0.01, 0.001);
//trace('掃除後',this.name,this);
dbg.appendText('掃除後 '+this.name+' '+this+'\n')
}
}
//名前がわかれば、Object3D.getChildByNameでアクセスできます。
rarm=Mesh(lm.getChildByName('R_arm'));
negi=Mesh(lm.getChildByName('negi'));
near=Mesh(lm.getChildByName('miku_near'));
far =Mesh(lm.getChildByName('miku_far'));
var angle:Number=0
//lm.rotationX=MathUtils.toRadian(90);
rarm.rotationX += 10 * Math.PI / 180;
negi.rotationX += 10 * Math.PI / 180;
//毎Frame毎のレンダリングを中止
template.stopRendering()
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
// ----------------------------------------------
// Mouse Interactive
// ----------------------------------------------
var isOribiting:Boolean;
var cameraPitch:Number = 200;
var cameraYaw:Number = 180;
var previousMouseX:Number;
var previousMouseY:Number;
rarm.rotationX = MathUtils.toRadian(0);
negi.rotationX = MathUtils.toRadian(0);
singleRender(null);
function onMouseDown(event:MouseEvent=null):void {
isOribiting = true;
previousMouseX = event.stageX;
previousMouseY = event.stageY;
rarm.rotationX = MathUtils.toRadian(20);
negi.rotationX = MathUtils.toRadian(20);
rarm.rotationZ = MathUtils.toRadian(0);
negi.rotationZ = MathUtils.toRadian(0);
rarm.y=0.05;
negi.y=0.05;
rarm.z=0.2;
negi.z=0.2;
singleRender(null);
}
function onMouseUp(event:MouseEvent=null):void {
isOribiting = false;
stage.quality = StageQuality.HIGH;
rarm.rotationX = MathUtils.toRadian(0);
negi.rotationX = MathUtils.toRadian(0);
rarm.rotationZ = MathUtils.toRadian(0);
negi.rotationZ = MathUtils.toRadian(0);
rarm.y=0;
negi.y=0;
rarm.z=0;
negi.z=0;
singleRender(null);
}
function onMouseMove(event:MouseEvent=null):void {
var differenceX:Number = event.stageX - previousMouseX;
var differenceY:Number = event.stageY - previousMouseY;
if(isOribiting) {
//stage.quality = StageQuality.MEDIUM;
cameraPitch += differenceY;
cameraYaw += differenceX * 0.25;
previousMouseX = event.stageX;
previousMouseY = event.stageY;
singleRender(null);
}
}
function singleRender(e:Event):void
{
// Mouse Interactive
template.camera.x = 500 * Math.sin(cameraYaw * Math.PI / 180);
template.camera.y = 500 * Math.cos(cameraYaw * Math.PI / 180);
template.camera.z = cameraPitch;
template.cameraContoller.lookAt(new Point3D());
// Scene calculating
template.singleRender()
}
}
}
}
}
import alternativ5.engine3d.controllers.CameraController;
import alternativ5.engine3d.core.Camera3D;
import alternativ5.engine3d.core.Object3D;
import alternativ5.engine3d.core.Scene3D;
import alternativ5.engine3d.display.View;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
/**
* BasicTemplate for Alternativa3D
* Alternativa3Dを扱いやすくするためのテンプレートです
* @author Yasu
*/
class BasicTemplate extends Sprite{
/**
* シーンインスタンスです。
*/
public var scene:Scene3D;
/**
* ビューインスタンスです。
*/
public var view:View;
/**
* カメラインスタンスです。
*/
public var camera:Camera3D;
/**
* カメラコントローラーです。
*/
public var cameraContoller:CameraController;
private var _viewWidth:int;
private var _viewHeight:int;
private var _scaleToStage:Boolean;
/**
* 新しい BasicTemplate インスタンスを作成します。
* @param viewWidth
* @param viewHeight
* @param scaleToStage
*/
public function BasicTemplate(viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true) {
_viewWidth = viewWidth;
_viewHeight = viewHeight;
_scaleToStage = scaleToStage;
// Creating scene
scene = new Scene3D();
scene.splitAnalysis = false; // not analysis for performance
scene.root = new Object3D();
// Adding camera
camera = new Camera3D();
camera.z = -1000;
scene.root.addChild(camera);
// camera contoller
cameraContoller = new CameraController(this);
cameraContoller.camera = camera;
// set view
view = new View();
view.camera = camera;
addChild(view);
// stage
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理をオーバーライドして記述します。
*/
protected function atInit():void {}
/**
* 初期化されたときに実行されるイベントです。
* 初期化時に実行したい処理を記述します。
*/
private var _onInit:Function = function():void { };
public function get onInit():Function { return _onInit; }
public function set onInit(value:Function):void {
_onInit = value;
}
/**
* 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 時に実行されるレンダリングのイベントです。
* レンダリング後に実行したい処理を記述します。
*/
protected 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 {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.HIGH;
// resize
stage.addEventListener(Event.RESIZE, onResize);
onResize(null);
// render
startRendering();
atInit();
_onInit();
}
/**
* @private
*/
private function onRenderTick(e:Event = null):void {
atPostRender();
_onPostRender();
scene.calculate();
atPreRender();
_onPreRender();
}
/**
* @private
*/
private function onResize(event:Event = null):void {
if (_scaleToStage) {
view.width = stage.stageWidth;
view.height = stage.stageHeight;
}else {
view.width = _viewWidth;
view.height = _viewHeight;
}
}
}