forked from: Lorenz Attractor - forked from: nengafl
こうですか!
Lorenz Attractor
@author Hiiragi
ビギナーの人が楽しめるのがルールということなので、考えてみたんですが、
Flashを始めて最初に衝撃を受けたのが、このきれいな模様を描いていく作品でした。
あまりの綺麗さに、ずっと見とれていた記憶があります。今でもそうですけど。
50 - 52行目の定数の値を弄ると動きが変わりますので
よかったら、ForkするなりDownloadするなりで試してみてください。
最近いろいろ凹み気味なので、初心を忘れないためにも、挑戦してみました。
なお、参考サイトをかなり参考にしました。(高校数学サボってた人なので数式判らん)
計算式は弄りようがないので、ほぼそのままです。
本当はcopyPixelsの第4引数以降のアルファを適用して、
奥に行くほどにアルファ値を下げるとかしたかったのですが、うまくいきませんでした・・・。
参考
http://www.procreo.jp/labo/labo08.html
http://ton-up.net/blog/archives/92
/**
* Copyright uwi ( http://wonderfl.net/user/uwi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/cWPY
*/
// forked from Hiiragi's Lorenz Attractor - forked from: nengafl
// forked from nengafl's nengafl
package
{
import net.hires.debug.Stats;
import org.papervision3d.view.BasicView;
import flash.events.MouseEvent;
import flash.events.Event;
import org.papervision3d.core.geom.*;
import org.papervision3d.core.geom.renderables.*;
import org.papervision3d.materials.special.*;
import org.papervision3d.core.math.*;
// こうですか!
/**
* Lorenz Attractor
* @author Hiiragi
*
* ビギナーの人が楽しめるのがルールということなので、考えてみたんですが、
* Flashを始めて最初に衝撃を受けたのが、このきれいな模様を描いていく作品でした。
* あまりの綺麗さに、ずっと見とれていた記憶があります。今でもそうですけど。
* 50 - 52行目の定数の値を弄ると動きが変わりますので
* よかったら、ForkするなりDownloadするなりで試してみてください。
*
* 最近いろいろ凹み気味なので、初心を忘れないためにも、挑戦してみました。
* なお、参考サイトをかなり参考にしました。(高校数学サボってた人なので数式判らん)
* 計算式は弄りようがないので、ほぼそのままです。
*
* 本当はcopyPixelsの第4引数以降のアルファを適用して、
* 奥に行くほどにアルファ値を下げるとかしたかったのですが、うまくいきませんでした・・・。
*
* 参考
* http://www.procreo.jp/labo/labo08.html
* http://ton-up.net/blog/archives/92
*
*/
[SWF(width = 465, height = 465, frameRate = 120, backgroundColor = 0x000000)]
public class Main extends BasicView
{
//公式に使われる定数
private var _p:Number = 10;
private var _r:Number = 28;
private var _b:Number = 8 / 3;
//時間単位
private var _d:Number = 0.01;
//一時的に数値を保持するための変数
private var _dx:Number;
private var _dy:Number;
private var _dz:Number;
//現在の座標を保持する変数
private var _nowX:Number = Math.random();
private var _nowY:Number = Math.random();
private var _nowZ:Number = Math.random();
private var _pool : Array;
private var _particles : Particles;
public function Main():void
{
Wonderfl.capture_delay(20);
super(0, 0, true, false);
graphics.beginFill(0x000000);
graphics.drawRect(0, 0, 465, 465);
graphics.endFill();
_pool = [];
_particles = new Particles("dots");
var p : Particle = getParticle();
p.x = _nowX;
p.y = _nowY;
p.z = _nowZ;
_particles.addParticle(p);
scene.addChild(_particles);
_camera = new SphereCamera(new Number3D(0, 0, 30), 70, new Number3D(0, 0, 1), new Number3D(0, 1, 0));
startRendering();
//debug
this.addChild(new Stats());
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
override protected function onRenderTick(e : Event = null) : void
{
//LorenzAttractorの公式
//http://ja.wikipedia.org/wiki/%E3%83%AD%E3%83%BC%E3%83%AC%E3%83%B3%E3%83%84%E6%96%B9%E7%A8%8B%E5%BC%8F
_dx = _p * (_nowY - _nowX);
_dy = _nowX * (_r - _nowZ) - _nowY;
_dz = _nowX * _nowY - _b * _nowZ;
//現在の座標に適用(3Dを作り方を知らないので、Z軸は結局使ってない)
_nowX += _d * _dx;
_nowY += _d * _dy;
_nowZ += _d * _dz;
var p : Particle = getParticle();
p.x = _nowX;
p.y = _nowY;
p.z = _nowZ;
_particles.addParticle(p);
if(_particles.particles.length > 2000){
var rp : Particle = _particles.particles[0];
_particles.removeParticle(rp);
returnParticle(rp);
}
super.onRenderTick(e);
}
private var _prevX : Number = 0;
private var _prevY : Number = 0;
private function onMouseMove(e : MouseEvent) : void
{
if(!(_camera is SphereCamera))return;
if(e.buttonDown){
// ボタンをおしている状態のときのみカメラを移動
if(_prevX != 0 && _prevY != 0){
var sc : SphereCamera = SphereCamera(_camera);
// 直前との差分だけ移動
sc.move((stage.mouseX - _prevX) * 0.005, (stage.mouseY - _prevY) * 0.005);
}
_prevX = stage.mouseX;
_prevY = stage.mouseY;
}else{
_prevX = 0;
_prevY = 0;
}
}
private var _pm : ParticleMaterial = new ParticleMaterial(0x00ff00, 0.2, ParticleMaterial.SHAPE_CIRCLE);
private function getParticle() : Particle
{
if(_pool.length == 0){
return new Particle(_pm, 1);
}else{
return _pool.pop();
}
}
private function returnParticle(p : Particle) : void
{
_pool.push(p);
}
}
}
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 SphereCamera extends QCamera3D
{
private var _O : DisplayObject3D; // 球の中心
private var _R : Number; // 球の半径
public function SphereCamera(O : Number3D, R : Number, front : Number3D, up : Number3D) : void
{
super(up, front);
_O = new DisplayObject3D();
_O.x = O.x;
_O.y = O.y;
_O.z = O.z;
_R = R;
move();
}
public function move(x : Number = 0, y : Number = 0) : void
{
rotateXY(x, y);
this.x = _front.x * -_R + _O.x;
this.y = _front.y * -_R + _O.y;
this.z = _front.z * -_R + _O.z;
this.lookAt(_O, _up);
}
}