// forked from sake's レインボーロード! forked from: nengafl // forked from nengafl's nengafl /* PV3Dで簡単に綺麗な図形を作ってみよう! PV3Dを使うと3Dを超簡単に扱えます。 そこで、PV3Dで簡単に綺麗な図形を作ってみましょう。 簡単な数式とパラメータだけで綺麗な図形が完成! 下で定義してある定数のp, q, a, l, m をいじってみてください。 また、for文の中の数式を書き換えるとさらに形が変わります。 単純に、sin → cos みたいに書き換えてみてもおもしろいかも! */ package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; import flash.events.Event; import flash.geom.Matrix; import frocessing.color.*; import org.papervision3d.core.geom.Pixels; import org.papervision3d.core.geom.renderables.Pixel3D; import org.papervision3d.view.BasicView; import org.papervision3d.view.layer.BitmapEffectLayer; import org.papervision3d.objects.*; import org.papervision3d.core.math.*; [SWF(width="465", height="465", backgroundColor="0x000000", frameRate="30")] public class Nengafl extends BasicView { // 計算に使うパラメータ // このあたりを適当に変えてみるだけでも面白いです! //---------------------------------------------------------------- private const p:int=3; private const q:int=7; private const a:int=100; private const l:Number=0.9; private const m:Number=1.1; //---------------------------------------------------------------- private var pixels:Pixels; private var canvas:BitmapData; private var mtx:Matrix; // コンストラクタ public function Nengafl() { super(0, 0, true, false); graphics.beginFill(0x000000); graphics.drawRect(0, 0, 465, 465); graphics.endFill(); // レイヤー作成。PV3Dでエフェクト使うときはこれを最初に作ります var layer:BitmapEffectLayer=new BitmapEffectLayer(viewport, 465, 465, true, 0, "clear_pre", true); layer.clearBeforeRender=true; viewport.containerSprite.addLayer(layer); // camera.z=-500; // Pixelsの初期化 pixels=new Pixels(layer); scene.addChild(pixels); var cc:ColorHSV=new ColorHSV(); // パラメータと数式でPixelの位置を計算する for(var i : Number = 0;i < 720;i+=0.2){ var t : Number = i * Math.PI / 120; // 数式に従ってx, y, z を計算。ここを適当に変えてみても面白いです。 // 簡単にsin → cos に変えてみるとか! var xx:Number=(2 + Math.cos(q / p * t)) * Math.cos(t) * a; var yy:Number=Math.sin(q / p * t) * a * 1.6; var zz:Number=(2 + Math.cos(q / p * t)) * Math.sin(t) * a; // 綺麗なグラデーションになるように色を設定 // こういうときはHSVを使うのが便利です cc.hsv(i, 1, 1); var color:uint=cc.value32; for (var j:int=0; j < 15; j++) { // x, y, z を l~mの範囲で散らします。 // l~mの区間の乱数を出す計算:(m - l) * Math.random() + l var px:Pixel3D=new Pixel3D(color, xx * ((m - l) * Math.random() + l), yy * ((m - l) * Math.random() + l), zz * ((m - l) * Math.random() + l)); pixels.addPixel3D(px); } } // キラキラロジック canvas=new BitmapData(465 / 4, 465 / 4, false, 0x000000); var bmp:Bitmap=new Bitmap(canvas, "never", true); bmp.scaleX=bmp.scaleY=4; bmp.smoothing=true; bmp.blendMode=BlendMode.ADD; addChild(bmp); mtx=new Matrix(0.25, 0, 0, 0.25); // PV3Dの描写開始! startRendering(); _rider = new DisplayObject3D(); _rider.x =(2 + Math.cos(q / p * _t)) * Math.cos(_t) * a; _rider.y =Math.sin(q / p * _t) * a * 1.6; _rider.z =(2 + Math.cos(q / p * _t)) * Math.sin(_t) * a; _camera = new RidingCamera(_rider, new Number3D(0, 1, 0), null); } private var _t : Number = 0.0; private var _rider : DisplayObject3D; // フレームイベント用関数 override protected function onRenderTick(e : Event = null) : void { // キラキラを描写 canvas.fillRect(canvas.rect, 0x000000); canvas.draw(viewport, mtx); // Y軸でローテーション // pixels.rotationY+=0.2; _t += 0.01; var xx:Number=(2 + Math.cos(q / p * _t)) * Math.cos(_t) * a; var yy:Number=Math.sin(q / p * _t) * a * 1.6; var zz:Number=(2 + Math.cos(q / p * _t)) * Math.sin(_t) * a; _rider.x = xx; _rider.y = yy; _rider.z = zz; RidingCamera(_camera).move(0, 0); super.onRenderTick(e); } } } import org.papervision3d.core.math.*; import org.papervision3d.objects.*; import org.papervision3d.cameras.*; // ジンバルロックを解消した以外はCamera3Dと同じ class QCamera3D extends Camera3D { public var _up : Number3D; // カメラの上の向きの単位ベクトル protected var _front : Number3D; private var _prevDir : Number3D; private var _ltarg : DisplayObject3D; public function QCamera3D(up : Number3D, front : Number3D = null) { super(); _up = null; _ltarg = new DisplayObject3D(); init(up, front); } // prevDirからcurDirへ向ける回転を_upにかけるだけ。カメラ自体に操作はしない public function rotate(curDir : Number3D) : void { if(_prevDir != null){ var n : Number3D = Number3D.cross(_prevDir, curDir); // if(n.moduloSquared > 0.00000001){ if(n.moduloSquared != 0){ n.normalize(); var angle : Number = Math.acos(Number3D.dot(_prevDir, curDir)); if(_front != null){ var a : Array = applyQuaternion([_front, _up], n, angle); _front = a[0]; _up = a[1]; }else{ _up = applyQuaternion([_up], n, angle)[0]; } } _prevDir.copyFrom(curDir); }else{ _prevDir = curDir.clone(); } } // カメラの右方向へx[rad], 上方向へy[rad]回転させる public function rotateXY(x : Number, y : Number) : void { if(_front == null)return; // X方向の移動 _front = applyQuaternion([_front], _up, -x)[0]; // Y方向の移動 var right : Number3D = Number3D.cross(_up, _front); right.normalize(); var ret : Array = applyQuaternion([_front, _up], right, y); _front = ret[0]; _up = ret[1]; } public function head() : void { if(_front != null){ // まわりくどい var ltpos : Number3D = this.position.clone(); ltpos.plusEq(_front); _ltarg.position = ltpos; this.lookAt(_ltarg, _up); } } public function init(up : Number3D = null, front : Number3D = null) : void { if(up != null){ _up = up.clone(); _up.normalize(); } if(front != null){ _front = front.clone(); _front.normalize(); }else{ _front = null; } _prevDir = null; } // axisを軸にangle回転させる変換を、srcsの要素それぞれに適用する public static function applyQuaternion(srcs : Array, axis : Number3D, angle : Number) : Array { var q : Quaternion = Quaternion.createFromAxisAngle( axis.x / axis.modulo, axis.y / axis.modulo, axis.z / axis.modulo, angle ); var qc : Quaternion = Quaternion.conjugate(q); var ret : Array = []; for each(var src : Number3D in srcs){ var qSrc : Quaternion = new Quaternion(src.x, src.y, src.z, 0); var qDst : Quaternion = Quaternion.multiply(qc, qSrc); qDst.mult(q); ret.push(new Number3D(qDst.x, qDst.y, qDst.z)); } return ret; } } // ゲットライド! class RidingCamera extends QCamera3D { private var _ride : DisplayObject3D; private var _prevPos : Number3D; public function RidingCamera(ride : DisplayObject3D, up : Number3D, front : Number3D = null) { super(up, front); _ride = ride; _prevPos = _ride.position.clone(); } public function move(up : Number = 0, back : Number = 0) : void { var curDir : Number3D = Number3D.sub(_ride.position, _prevPos); curDir.normalize(); if(_front == null){ _front = curDir.clone(); } rotate(curDir); var curPos : Number3D = _ride.position.clone(); var temp : Number3D; temp = _up.clone(); temp.multiplyEq(up); curPos.plusEq(temp); temp = _front.clone(); temp.multiplyEq(-back); curPos.plusEq(temp); this.position = curPos; head(); _prevPos.copyFrom(_ride.position); } } forked from: レインボーロード! forked from: nengafl