That flower (stage3d)
Thatflower(use stage3d)
まだ高速化は意識してないです。
...
@author okoi
/**
* Copyright okoi ( http://wonderfl.net/user/okoi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/gR7K
*/
/**
* Thatflower(use stage3d)
* まだ高速化は意識してないです。
*/
package
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
import flash.display.Stage3D;
import flash.display3D.Program3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.Context3DBlendFactor;
import flash.display3D.Context3DCompareMode;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.utils.ByteArray;
import flash.geom.Vector3D;
import flash.display.Bitmap;
import flash.display.BitmapData;
[SWF(width="465", height="465", frameRate="60")]
/**
* ...
* @author okoi
*/
public class Main extends Sprite
{
public static const CAPTURE:Boolean = false;
private var _captureBmd:BitmapData;
public static const WIDTH:int = 465;
public static const HEIGHT:int = 465;
private var _stage3D:Stage3D;
private var _context3D:Context3D;
private var _renderProgram:Program3D; // レンダリングプログラム
private var _matProjection:PerspectiveMatrix3D;
private var _camera:Camera;
private var _flower:Flower;
private var _particleList:Vector.<Particle>;
private var _ct:uint = 0;
public function Main():void
{
Wonderfl.disable_capture();
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
_stage3D = stage.stage3Ds[0];
_stage3D.addEventListener( Event.CONTEXT3D_CREATE, Context3DCreateHandler );
_stage3D.requestContext3D( Context3DRenderMode.AUTO );
if ( CAPTURE ) {
_captureBmd = new BitmapData(WIDTH, HEIGHT, true, 0);
addChild( new Bitmap( _captureBmd ) );
}
}
private function Context3DCreateHandler( e:Event ) : void
{
_context3D = _stage3D.context3D;
_context3D.enableErrorChecking = true;
_context3D.configureBackBuffer( WIDTH, HEIGHT, 4, true );
_context3D.setCulling(Context3DTriangleFace.BACK);
_context3D.setBlendFactors( Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA );
_context3D.setDepthTest(false, Context3DCompareMode.ALWAYS);
_renderProgram = _context3D.createProgram();
InitCamera();
InitProjection();
InitShader();
InitFlowerData();
_context3D.clear();
addEventListener( Event.ENTER_FRAME, EnterFrameHandler );
}
private function InitProjection() : void {
_matProjection = new PerspectiveMatrix3D();
_matProjection.perspectiveFieldOfViewLH( 45 * Math.PI / 180, WIDTH / HEIGHT, 0.1, 3000 );
}
/**
* カメラの初期化を行う
*/
private function InitCamera() : void {
_camera = new Camera();
}
private function InitShader() : void {
var agalAssembler:AGALMiniAssembler = new AGALMiniAssembler();
var code:String = "";
var vShader:ByteArray;
var fShader:ByteArray;
code = "m44 op, va0, vc0\n";
code += "mov v0, va1\n";
vShader = agalAssembler.assemble( Context3DProgramType.VERTEX, code );
code = "tex ft0, v0, fs0 <2d,clamp,linear>\n";
code += "mul oc, ft0, fc0\n";
fShader = agalAssembler.assemble( Context3DProgramType.FRAGMENT, code );
_renderProgram.upload( vShader, fShader );
_context3D.setProgram(_renderProgram);
}
private function EnterFrameHandler( e:Event ) : void {
var i:int;
//--------------------------
// カメラの回転
var cameraAngle:Number = ((_ct * 0.1) + 90) % 360;
var cR:Number = Math.sin( ((_ct * 0.2) % 360) * Math.PI / 180 ) * 0; // 酔うかもw
var cameraX:Number = Math.cos( cameraAngle * Math.PI / 180 ) * (5 + cR);
var cameraZ:Number = Math.sin( cameraAngle * Math.PI / 180 ) * (5 + cR);
_camera.InitView( new Vector3D(cameraX, 0, -cameraZ), new Vector3D(0, 0, 0), new Vector3D(0, 1, 0) );
//--------------------------
// パーティクルの移動と描画順ソート処理
for ( i = _particleList.length - 1; i >= 0; i-- ) {
if ( _particleList[i].life > 0 ) {
_particleList[i].Update( _camera );
} else {
_particleList.splice( i, 1 );
}
}
_particleList.sort( SortFlower );
//--------------------------
// ポリゴンレンダリング
_context3D.clear(1,1,1,1);
for ( i = _particleList.length - 1; i >= 0; i-- ){
var mat:Matrix3D = new Matrix3D();
var particle:Particle = _particleList[i];
_context3D.setVertexBufferAt( 0, _flower.vBuf, 0, Context3DVertexBufferFormat.FLOAT_3 ); // va0
_context3D.setVertexBufferAt( 1, _flower.uvBuf, 0, Context3DVertexBufferFormat.FLOAT_2 ); // va1
_context3D.setTextureAt( 0, _flower.texture );
mat.append( particle.matrix ); // ワールド座標変換
mat.append( _camera.matrix ); // ビュー変換変換
mat.append( _matProjection ); // プロジェクション座標変換
var alpha:Number = 0;
if ( particle.lifeRate < 0.1 ) alpha = particle.lifeRate * 10;
else if ( particle.lifeRate < 0.9 ) alpha = 1;
else alpha = (1 - particle.lifeRate) * 10;
_context3D.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 0, mat, true ); // vc0
_context3D.setProgramConstantsFromVector( Context3DProgramType.FRAGMENT, 0, Vector.<Number>([ particle.r, particle.g, particle.b, alpha ]) );
_context3D.drawTriangles( _flower.iBuf );
}
if ( CAPTURE ) {
_context3D.drawToBitmapData( _captureBmd );
}
_context3D.present();
//--------------------------
// パーティクル追加
addFlower();
addFlower();
//
_ct++;
}
private function InitFlowerData() : void {
_flower = new Flower( _context3D );
_particleList = new Vector.<Particle>();
}
private function addFlower() : void {
var particle:Particle = new Particle();
var i:int = 0;
for ( i = 0; i < _particleList.length; i++ ) {
if ( particle.z <= _particleList[i].z ) {
break;
}
}
_particleList.splice( i, 0, particle );
}
private function SortFlower( a:Particle, b:Particle ) : int {
if ( a.viewz == b.viewz ) return 0;
if ( a.viewz > b.viewz ) return 1;
return -1;
}
}
}
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display3D.Context3D;
import flash.display3D.textures.Texture;
import flash.display3D.IndexBuffer3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.Context3DTextureFormat;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
class Camera {
private var _view:Matrix3D;
private var _from:Vector3D;
private var _at:Vector3D;
private var _up:Vector3D;
public function Camera() {
_view = new Matrix3D();
}
/**
* ビュー行列の設定を行う
* PerspectiveMatrix3DのlookAtLH,RHはバグがあるっぽいので自力計算
* @param from
* @param at
* @param up
*/
public function InitView( from:Vector3D, at:Vector3D, up:Vector3D ) : void {
var vz:Vector3D = at.subtract( from );
vz.normalize();
var vx:Vector3D = up.crossProduct( vz );
vx.normalize();
var vy:Vector3D = vz.crossProduct( vx );
vy.normalize();
var vtx:Number = vx.dotProduct( from ) * -1;
var vty:Number = vy.dotProduct( from ) * -1;
var vtz:Number = vz.dotProduct( from ) * -1;
_view.identity();
_view.rawData = Vector.<Number>([
vx.x, vy.x, vz.x, 0,
vx.y, vy.y, vz.y, 0,
vx.z, vy.z, vz.z, 0,
vtx, vty, vtz, 1,
]);
_from = from;
_at = at;
_up = up;
}
public function get matrix():Matrix3D {
return _view;
}
public function get from() : Vector3D {
return _from;
}
public function get at() : Vector3D {
return _at;
}
}
class Flower {
public static const TEX_WIDTH:int = 64;
public static const TEX_HEIGHT:int = 64;
// 各花びらの1枚の専有角度
public static const PETALANGLE:Array = [ 62, 82, 72, 72, 72 ];
// 花びら1枚に対しての各クォーターの専有角度率
public static const QUARTERRATE:Array = [ 0.3, 0.15, 0.25, 0.3 ];
private var _vBuf:VertexBuffer3D;
private var _uvBuf:VertexBuffer3D;
private var _iBuf:IndexBuffer3D;
private var _texture:Texture;
public function Flower( context3d:Context3D ) {
_vBuf = context3d.createVertexBuffer( 4, 3 );
_vBuf.uploadFromVector(
Vector.<Number>([
-0.1, 0.1, 0,
0.1, 0.1, 0,
0.1, -0.1, 0,
-0.1, -0.1, 0,
]),
0,
4
);
_uvBuf = context3d.createVertexBuffer( 4, 2 );
_uvBuf.uploadFromVector(
Vector.<Number>([
0, 0,
1, 0,
1, 1,
0, 1,
]),
0,
4
);
_iBuf = context3d.createIndexBuffer( 3 * 2 );
_iBuf.uploadFromVector(
Vector.<uint>([
0, 1, 2,
2, 3, 0,
]),
0,
3 * 2
);
InitTexture( context3d );
}
private function InitTexture( context3d:Context3D ) : void {
var w:int = TEX_WIDTH;
var h:int = TEX_HEIGHT;
var radius:Number = 25;
var i:int, p:int;
var tmp1:int, tmp2:int;
var t1:Number, t2:int;
var sin45:Number = Math.sin( 45 * Math.PI / 180 );
var shape:Shape = new Shape();
shape.graphics.beginFill( 0xFFFFFF );
// 花びら1枚1枚のパラメータを決定する
var petalAngles:Array = PETALANGLE;
var rOffset:Array = [];
var rOffset2:Array = [];
for ( p = 0; p < 4; p++ ) {
rOffset.push( Math.random() * 0.2 - 0.1 + 0.5 );
rOffset2.push( Math.random() * 0.2 + 0.8 );
}
rOffset.push( Math.random() * 0.2 - 0.1 + 0.5 );
rOffset2.push( Math.random() * 0.2 + 0.8 );
// 各クォーターの専有角度
var quarterRate:Array = QUARTERRATE;
// 花びら1枚1枚描画していく(5枚分)
var startAngle:int = 0;
for ( p = 0; p < 5; p++ ) {
for ( i = 0; i <= petalAngles[p]; i++ ) {
var rad:Number = (startAngle + i) * Math.PI / 180;
// 基本位置
var x:Number = Math.cos( rad ) * radius;
var y:Number = Math.sin( rad ) * radius;
//
var quarter:int;
var quarterStartRate:Number = 0;
var nowrate:Number = i / petalAngles[p];
t1 = 0;
for ( quarter = 0; quarter < 4; quarter++ ) {
t1 += quarterRate[quarter];
if ( nowrate < t1 ) {
break;
}
quarterStartRate += quarterRate[quarter];
}
quarter %= 4;
var r:Number;
var rate:Number = (nowrate - quarterStartRate) / quarterRate[quarter];
rate *= 90; // 1Qで90度分の角度変化を行う
// Q-0
// startY 0
// endY sin45θ
if ( quarter == 0 ) {
rad = (rate) * Math.PI / 180;
r = Math.abs( Math.sin( rad ) ) * sin45;
}
// Q-1
// startY sin45θ
// endY sin90θ
if ( quarter == 1 ) {
rad = (rate + 90) * Math.PI / 180;
//trace( Math.abs( Math.sin( rad ) ) );
r = (1 - Math.abs( Math.sin( rad ) ) ) * (1 - sin45) * 0.4 + sin45;
}
// Q-2
// startY sin90θ
// endY sin45θ
if ( quarter == 2 ) {
rad = rate * Math.PI / 180;
r = (1 - Math.abs( Math.sin( rad ) )) * (1 - sin45) * 0.4 + sin45;
}
// Q-3
// startY sin45θ
// endY 0
if ( quarter == 3 ) {
rad = (rate + 90) * Math.PI / 180;
r = Math.abs( Math.sin( rad ) ) * sin45;
}
//
r += rOffset[p];
x *= r;
y *= r * 0.9;
if ( p == 0 && i == 0 ) shape.graphics.moveTo(x, y);
else shape.graphics.lineTo(x, y);
}
startAngle += petalAngles[p];
}
shape.graphics.endFill();
var bmd:BitmapData = new BitmapData(w, h, true, 0 );
bmd.draw( shape, new Matrix(1, 0, 0, 1, w/2, h/2), null, null, null, true );
_texture = context3d.createTexture( w, h, Context3DTextureFormat.BGRA, false );
_texture.uploadFromBitmapData( bmd );
bmd.dispose();
bmd = null;
}
public function get vBuf():VertexBuffer3D { return _vBuf; }
public function get uvBuf():VertexBuffer3D { return _uvBuf; }
public function get iBuf():IndexBuffer3D { return _iBuf; }
public function get texture():Texture { return _texture; }
}
class Particle {
public var x:Number = 0;
public var y:Number = 0;
public var z:Number = 0;
public var angle:Number = 0;
public var rotationY:Number = 0;
public var vy:Number = 0;
public var r:Number = 1;
public var g:Number = 1;
public var b:Number = 1;
public var life:uint;
public var maxlife:uint;
public var viewz:Number = 0;
public function Particle() {
life = Math.random() * 300 + 400;
maxlife = life;
var temp:Number = Math.random() * 360;
var temp2:Number = Math.random() * 10;
x = Math.cos( temp * Math.PI / 180 ) * temp2;
y = -3;
z = Math.sin( temp * Math.PI / 180 ) * temp2;
vy = 0.01 + Math.random() * 0.001;
temp = int(Math.random() * 5);
switch( temp ) {
case 0: r = 0xF4 / 0xFF; g = 0x7E / 0xFF; b = 0xB9 / 0xFF; break;
case 1: r = 0xFF / 0xFF; g = 0x7D / 0xFF; b = 0x69 / 0xFF; break;
case 2: r = 0xFB / 0xFF; g = 0xD1 / 0xFF; b = 0xDC / 0xFF; break;
case 3: r = 0xF6 / 0xFF; g = 0x5A / 0xFF; b = 0x67 / 0xFF; break;
case 4: r = 0xF9 / 0xFF; g = 0xE1 / 0xFF; b = 0xBE / 0xFF; break;
}
}
public function get matrix() : Matrix3D {
var mat:Matrix3D = new Matrix3D();
mat.appendRotation( angle, new Vector3D(0, 0, 1) );
mat.appendRotation( rotationY, new Vector3D(0, 1, 0) );
mat.appendTranslation( x, y, z );
return mat;
}
public function get lifeRate() : Number {
return life / maxlife;
}
public function Update( camera:Camera ) : void {
angle += 0.4;
angle %= 360;
y += vy;
var mat:Matrix3D = this.matrix;
mat.append( camera.matrix );
viewz = mat.position.z;
//---------------------------------
// 向きをカメラの方に向ける計算
var zvec:Vector3D = new Vector3D( 0, 0, 1 );
var cameraVec:Vector3D = new Vector3D( camera.at.x - camera.from.x, 0, camera.at.z - camera.from.z );
cameraVec.normalize();
var dot:Number = zvec.dotProduct( cameraVec );
var rad:Number = Math.acos( dot / (cameraVec.length * 1/*zvec.length*/) );
var cross:Vector3D = zvec.crossProduct( cameraVec );
if ( cross.y < 0 ) rad *= -1;
rotationY = rad * 180 / Math.PI;
life--;
}
}