forked from: forked from: レインボーロード! forked from: nengafl
PV3Dで簡単に綺麗な図形を作ってみよう!
PV3Dを使うと3Dを超簡単に扱えます。
そこで、PV3Dで簡単に綺麗な図形を作ってみましょう。
簡単な数式とパラメータだけで綺麗な図形が完成!
下で定義してある定数のp, q, a, l, m をいじってみてください。
また、for文の中の数式を書き換えるとさらに形が変わります。
単純に、sin → cos みたいに書き換えてみてもおもしろいかも!
/**
* Copyright s8t1h12akj ( http://wonderfl.net/user/s8t1h12akj )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hlgc
*/
// forked from uwi's forked from: レインボーロード! forked from: nengafl
// 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=5;
private const a:int=50;
private const l:Number=0.5;
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);
}
}