forked from: Sea of Clouds - no plane
/**
* Copyright arawn.ocultus ( http://wonderfl.net/user/arawn.ocultus )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/3M4j
*/
// forked from phenix.pink's Sea of Clouds - no plane
// forked from tencho's Sea of Clouds
package {
import flash.display.*;
import flash.events.*;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import net.hires.debug.Stats;
import org.papervision3d.core.geom.renderables.Triangle3D;
import org.papervision3d.core.geom.renderables.Vertex3D;
import org.papervision3d.core.geom.TriangleMesh3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.math.NumberUV;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.Papervision3D;
import org.papervision3d.view.BasicView;
[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")]
public class Clouds extends Sprite {
/**雲の数*/
public const CLOUD_NUM:int = 200;
/**雲画像のパターン数*/
public const PATTERN_NUM:int = 35;
/**雲のサイズ*/
public const CLOUD_SIZE:Rectangle = new Rectangle(0, 0, 400, 200);
/**perlinNoiseに使うとまずいシード値(画像に穴があくかもしれない)*/
public const ERROR_SEEDS:Array = [346, 514, 1155, 1519, 1690, 1977, 2327, 2337, 2399, 2860, 2999, 3099, 4777, 4952, 5673, 6265, 7185, 7259, 7371, 7383, 7717, 7847, 8032, 8350, 8676, 8963, 8997, 9080, 9403, 9615, 9685];
public const PI:Number = Math.PI / 180;
public var loading:LoadingScene;
public var cameraCtrl:CameraController;
public var view:BasicView;
public var horizonTarget:DisplayObject3D;
public var airplane:TriangleMesh3D;
public var canvas1:BitmapData;
public var canvas2:BitmapData;
public var bg:BackGround;
public var ground:Sprite;
public var clouds:Vector.<Cloud> = new Vector.<Cloud>();
public var drawObjects:Vector.<Cloud> = new Vector.<Cloud>();
public var cloudImages:Vector.<BitmapData> = new Vector.<BitmapData>();
public var clearColor:ColorTransform = new ColorTransform(1, 1, 1, 0);
public function Clouds() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
Display.setSize(465, 465);
stage.frameRate = 60;
stage.quality = "low";
Papervision3D.PAPERLOGGER.unregisterLogger(Papervision3D.PAPERLOGGER.traceLogger);
view = new BasicView(Display.width, Display.height, false, false, "Free");
horizonTarget = view.scene.addChild(new DisplayObject3D());
horizonTarget.autoCalcScreenCoords = true;
addChild(Painter.createGradientRect(Display.width, Display.height, [Color.sky1], [1]));
ground = Painter.createGradientRect(Display.width, Display.height, [Color.ground], [1]);
bg = new BackGround();
bg.x = Display.center.x;
bg.mask = addChild(Painter.createGradientRect(Display.width, Display.height, [0x000000], [1]));
canvas1 = new BitmapData(Display.width, Display.height, true, 0x00FFFFFF);
canvas2 = new BitmapData(Display.width, Display.height, true, 0x00FFFFFF);
loading = new LoadingScene();
//色々配置
addChild(ground);
addChild(bg);
addChild(new Bitmap(canvas1));
addChild(view.viewport);
addChild(new Bitmap(canvas2));
addChild(new Stats({bg:0x808080, fps:0xFFFFFF})).blendMode = BlendMode.OVERLAY;
addChild(loading);
//雲生成
for (var i:int = 0; i < CLOUD_NUM; i++) {
var cloud:Cloud = new Cloud();
clouds.push(cloud);
cloud.setPosition(Math.random() * 3500 - 1750, Math.random() * -300 + 9000, Math.random() * 4000 - 2000);
}
//飛行機生成
airplane = createAirplane();
airplane.y = 10000;
airplane.autoCalcScreenCoords = true;
view.scene.addChild(airplane);
//カメラ初期化
cameraCtrl = new CameraController();
cameraCtrl.init(view.scene, view.camera);
//雲画像生成開始
addEventListener(Event.ENTER_FRAME, onLoading);
}
//航空機モデルを生成
private function createAirplane():TriangleMesh3D {
var scale:Number = 0.1;
var vts:Array = [
];
var ids:Array = [
];
var material:MaterialObject3D = new ColorMaterial(Color.planeSkin, 1);
var mesh:TriangleMesh3D = new TriangleMesh3D(material, [], []);
var vertexes:Array = [];
for each (var vt:Array in vts) vertexes.push(new Vertex3D(vt[0]*scale, vt[1]*scale, vt[2]*scale));
for each (var id:Array in ids) mesh.geometry.faces.push(new Triangle3D(mesh, [vertexes[id[0]], vertexes[id[1]], vertexes[id[2]]], null, [new NumberUV(), new NumberUV(), new NumberUV()]));
mesh.geometry.vertices = vertexes;
mesh.geometry.ready = true;
return mesh;
}
//雲画像生成中
private function onLoading(...arg):void {
for (var i:int = 0; i < 3; i++) {
if(cloudImages.length >= PATTERN_NUM){
start();
break;
}
var seed:int = Math.random() * 10000 + 1;
if (ERROR_SEEDS.indexOf(seed) >= 0) seed++;
var ct:Number = (Math.random() < 0.3)? Math.random() * 0.3 : Math.random() * 1.5;
cloudImages.push(Painter.createCloud(CLOUD_SIZE.width, CLOUD_SIZE.height, seed, ct, Color.cloudBase, Color.cloudLight, Color.cloudShadow));
loading.setProgress(cloudImages.length / PATTERN_NUM);
}
}
//レンダリング開始
private function start():void {
removeEventListener(Event.ENTER_FRAME, onLoading);
removeChild(loading);
var index:int = -1;
for each (var cloud:Cloud in clouds) {
index = ++index % cloudImages.length;
cloud.image = cloudImages[index];
}
stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:MouseEvent):void {
cameraCtrl.switchCamera();
});
Time.start();
addEventListener(Event.ENTER_FRAME, onEnter);
onEnter(null);
}
//毎フレーム処理
private function onEnter(e:Event):void {
var c:Cloud;
Time.update();
var time:int = Time.count;
//飛行機を傾ける
// airplane.rotationZ = Math.sin(PI * time / 150) * 30;
//カメラ位置更新
//cameraCtrl.setAirplaneRoll(airplane.rotationZ);
cameraCtrl.update();
//地平線用ダミーモデルをカメラの前方に配置
horizonTarget.position = new Number3D(Math.cos(cameraCtrl.lookDirection) * 10000, 10000, Math.sin(cameraCtrl.lookDirection) * 10000);
//PV3Dレンダリング
view.singleRender();
//雲を動かす
var area:int = 2000;
for each(c in clouds) {
c.z = ((c.startPosition.z + time * 0.42) + area) % (area * 2) - area;
var loop:int = int(((c.startPosition.z + time * 0.42) + area) / (area * 2));
if (c.loop != loop) {
//周回数が変化する度に雲の配置を変化させる
c.loop = loop;
c.x = Math.random() * 3500 - 1750;
c.y = Math.random() * -300 + 10000;
}
cameraCtrl.calculateScreen(c.screen, c.x, c.y, c.z);
}
//背景画像を地平線の高さに移動
// bg.y = horizonTarget.screen.y + Display.center.y;
// bg.rotation = cameraCtrl.roll;
bg.slide(cameraCtrl.lookDirection / (Math.PI * 2));
ground.visible = horizonTarget.screen.y + Display.center.y < Display.height;
//雲画像処理
canvas1.lock();
canvas2.lock();
canvas1.colorTransform(Display.size, clearColor);
canvas2.colorTransform(Display.size, clearColor);
//描画対象の雲を絞り込む
drawObjects.length = 0;
for each(c in clouds) {
if (c.screen.z > 10) {
c.update();
if (c.alpha <= 0) continue;
if (c.screen.x + Display.center.x < -CLOUD_SIZE.width * c.scale / 2) continue;
if (c.screen.x + Display.center.x > Display.width + CLOUD_SIZE.width * c.scale / 2) continue;
drawObjects.push(c);
}
}
drawObjects.sort(function(a:Cloud, b:Cloud):Number { return int(b.screen.z - a.screen.z); } );
//雲描画
for each(c in drawObjects) {
var target:BitmapData = (airplane.screen.z < c.screen.z)? canvas1 : canvas2;
var ct:ColorTransform = new ColorTransform(1, 1, 1, c.alpha, 0, 0, 0, 0);
var mtx:Matrix = new Matrix();
mtx.scale(c.scale, c.scale);
mtx.rotate(PI * view.camera.localRotationZ);
var dx:Number = c.scale * CLOUD_SIZE.width / 2;
var dy:Number = c.scale * CLOUD_SIZE.height / 2;
var cos:Number = Math.cos(PI * cameraCtrl.roll);
var sin:Number = Math.sin(PI * cameraCtrl.roll);
var px:Number = c.screen.x + Display.center.x - cos * dx + sin * dy;
var py:Number = c.screen.y + Display.center.y - sin * dx - cos * dy;
mtx.translate(px, py);
target.draw(c.image, mtx, ct);
}
canvas1.unlock();
canvas2.unlock();
}
}
}
import flash.display.*;
import flash.filters.*;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getTimer;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.core.math.Number3D;
import org.papervision3d.core.proto.CameraObject3D;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.scenes.Scene3D;
/**
* 画面サイズ
*/
class Display {
static public var width:Number;
static public var height:Number;
static public var size:Rectangle;
static public var center:Point;
static public function setSize(width:Number, height:Number):void {
Display.width = width;
Display.height = height;
size = new Rectangle(0, 0, width, height);
center = new Point(width / 2, height / 2);
}
}
/**
* 色
*/
class Color {
/**航空機の色*/
static public var planeSkin:uint = 0xFFFFFF;
/**雲の色*/
static public var cloudBase:uint = 0xD7DDE5;
/**雲のハイライト色*/
static public var cloudLight:uint = 0xFFFFFF;
/**雲の影の色*/
static public var cloudShadow:uint = 0x6D8790;
/**空の色(上)*/
static public var sky1:uint = 0x1F437F;
/**空の色(下)*/
static public var sky2:uint = 0x6290C1;
/**地平線付近の色*/
static public var horizon:uint = 0xA0BCD1;
/**地上の色*/
static public var ground:uint = 0xA1ACA4;
}
/**
* 経過時間
*/
class Time {
static private var _start:int;
static public var count:int;
static public function update():void {
count = getTimer() - _start + 7000;
}
static public function start():void {
_start = getTimer();
}
}
/**
* 雲
*/
class Cloud {
public var x:Number = 0;
public var y:Number = 0;
public var z:Number = 0;
public var screen:Number3D = new Number3D();
public var loop:int;
public var startPosition:Number3D;
public var image:BitmapData;
public var alpha:Number;
public var scale:Number;
public function Cloud() {
}
/**
* 雲の初期位置を設定
*/
public function setPosition(x:Number, y:Number, z:Number):void {
startPosition = new Number3D(x, y, z);
this.x = x;
this.y = y;
this.z = z;
}
/**
* スケールと透明度を更新
*/
public function update():void {
scale = 600 / screen.z;
var perMin:Number = screen.z / 200;
var perMax:Number = 1 - (screen.z - 1500) / 800;
if (perMin > 1) perMin = 1;
if (perMax > 1) perMax = 1;
alpha = perMin * perMax * 2;
}
}
/**
* カメラ操作
*/
class CameraController {
private const RADIAN:Number = Math.PI / 180;
private var _calculateObject:DisplayObject3D = new DisplayObject3D();
private var _lookAtTarget:DisplayObject3D = new DisplayObject3D();
private var _camera:Camera3D;
private var _type:int = 0;
private var _airplaneRoll:Number = 0;
public var roll:Number;
public var angle:Number;
public var rotation:Number;
public var distance:Number;
public var lookDirection:Number;
public function CameraController() {
}
/**
* シーンとカメラを渡して初期化
*/
public function init(scene:Scene3D, camera:CameraObject3D):void {
_camera = camera as Camera3D;
scene.addChild(_calculateObject);
scene.addChild(_lookAtTarget);
}
/**
* (x,y,z)のスクリーン座標を計算してscreenに設定する
*/
public function calculateScreen(screen:Number3D, x:Number, y:Number, z:Number):void {
_calculateObject.x = x;
_calculateObject.y = y;
_calculateObject.z = z;
_calculateObject.view.calculateMultiply(_camera.eye, _calculateObject.transform);
_calculateObject.calculateScreenCoords(_camera);
screen.copyFrom(_calculateObject.screen);
}
/**
* カメラ変更
*/
public function switchCamera():void {
_type = ++_type % 5;
}
/**
* 飛行機の傾きを渡す
*/
public function setAirplaneRoll(roll:Number):void {
_airplaneRoll = roll;
}
/**
* カメラ位置更新
*/
public function update():void {
var time:int = Time.count;
switch(_type) {
case 0:
distance = Math.sin(RADIAN * time / 80) * 200 + 600;
rotation = time / 1000 * 60 * 0.2;
roll = Math.sin(RADIAN * time / 50) * 20;
angle = Math.sin(RADIAN * time / 100) * 100 + 50;
_lookAtTarget.position = new Number3D(0, 10000, 0);
break;
case 1:
distance = 280;
rotation = Math.sin(RADIAN * time / 110) * 20 + 90;
roll = -_airplaneRoll;
angle = Math.sin(RADIAN * time / 90) * 50 + 30;
_lookAtTarget.position = new Number3D(0, 10000, -10000);
break;
case 2:
distance = 500;
rotation = Math.sin(RADIAN * time / 110) * 10;
roll = 0;
angle = Math.sin(RADIAN * -time / 70) * 200;
_lookAtTarget.position = new Number3D(0, 10000, 0);
break;
case 3:
distance = 800;
rotation = -time / 200;
roll = 0;
angle = -400;
_lookAtTarget.position = new Number3D(0, 10000, 0);
break;
case 4:
distance = 40;
rotation = 50;
roll = -_airplaneRoll / 2;
angle = 30 + _airplaneRoll;
_lookAtTarget.position = new Number3D(1000, 10000, -700);
break;
}
_camera.position = new Number3D(Math.cos(RADIAN * rotation) * distance, angle + 10000, Math.sin(RADIAN * rotation) * distance);
_camera.lookAt(_lookAtTarget);
//_camera.roll(roll);
lookDirection = Math.atan2(_lookAtTarget.z - _camera.z, _lookAtTarget.x - _camera.x);
}
}
class Painter {
/**
* 雲画像生成
* @param width 幅
* @param height 高さ
* @param seed ランダムシード値
* @param contrast コントラスト0~
* @param color ベースの色
* @param light 明るい色
* @param shadow 暗い色
*/
static public function createCloud(width:int, height:int, seed:int, contrast:Number = 1, color:uint = 0xFFFFFF, light:uint = 0xFFFFFF, shadow:uint = 0xDDDDDD):BitmapData {
var gradiation:Sprite = new Sprite();
var drawMatrix:Matrix = new Matrix();
drawMatrix.createGradientBox(width, height);
gradiation.graphics.beginGradientFill("radial", [0x000000, 0x000000], [0, 1], [0, 255], drawMatrix);
gradiation.graphics.drawRect(0, 0, width, height);
gradiation.graphics.endFill();
var alphaBmp:BitmapData = new BitmapData(width, height);
alphaBmp.perlinNoise(width / 3, height / 2.5, 5, seed, false, true, 1|2|4, true);
var zoom:Number = 1 + (contrast - 0.1) / (contrast + 0.9);
if (contrast < 0.1) zoom = 1;
if (contrast > 2.0) zoom = 2;
var ctMatrix:Array = [contrast + 1, 0, 0, 0, -128 * contrast, 0, contrast + 1, 0, 0, -128 * contrast, 0, 0, contrast + 1, 0, -128 * contrast, 0, 0, 0, 1, 0];
alphaBmp.draw(gradiation, new Matrix(zoom, 0, 0, zoom, -(zoom - 1) / 2 * width, -(zoom - 1) / 2 * height));
alphaBmp.applyFilter(alphaBmp, alphaBmp.rect, new Point(), new ColorMatrixFilter(ctMatrix));
var image:BitmapData = new BitmapData(width, height, true, 0xFF << 24 | color);
image.copyChannel(alphaBmp, alphaBmp.rect, new Point(), 4, 8);
image.applyFilter(image, image.rect, new Point(), new GlowFilter(light, 1, 4, 4, 1, 3, true));
var bevelSize:Number = Math.min(width, height) / 30;
image.applyFilter(image, image.rect, new Point(), new BevelFilter(bevelSize, 45, light, 1, shadow, 1, bevelSize/5, bevelSize/5, 1, 3));
var image2:BitmapData = new BitmapData(width, height, true, 0);
image2.draw(Painter.createGradientRect(width, height, [light, color, shadow], [1, 0.2, 1], null, 90), null, null, BlendMode.MULTIPLY);
image2.copyChannel(alphaBmp, alphaBmp.rect, new Point(), 4, 8);
image.draw(image2, null, null, BlendMode.MULTIPLY);
alphaBmp.dispose();
return image;
}
/**
* グラデーションスプライト生成
*/
static public function createGradientRect(width:Number, height:Number, colors:Array, alphas:Array, ratios:Array = null, rotation:Number = 0):Sprite {
var i:int, rts:Array = new Array();
if(ratios == null) for (i = 0; i < colors.length; i++) rts.push(int(255 * i / (colors.length - 1)));
else for (i = 0; i < ratios.length; i++) rts[i] = Math.round(ratios[i] * 255);
var sp:Sprite = new Sprite();
var mtx:Matrix = new Matrix();
mtx.createGradientBox(width, height, Math.PI / 180 * rotation, 0, 0);
if (colors.length == 1 && alphas.length == 1) sp.graphics.beginFill(colors[0], alphas[0]);
else sp.graphics.beginGradientFill("linear", colors, alphas, rts, mtx);
sp.graphics.drawRect(0, 0, width, height);
sp.graphics.endFill();
return sp;
}
}
/**
* 遠景画像
*/
class BackGround extends Sprite {
private var _imageWidth:int = 2000;
private var _viewWidth:int = 600;
private var _cloudWidth:int = 120;
private var _cloudHeight:int = 60;
private var _image:BitmapData;
private var _cloudSprite:Sprite;
public function BackGround() {
_viewWidth = Display.width * 1.5;
var sky:Sprite = addChild(Painter.createGradientRect(Display.width*2, Display.height, [Color.sky1, Color.sky2, Color.horizon], [1, 1, 1], [0, 0.9, 1], 90)) as Sprite;
sky.x = -Display.width;
sky.y = -Display.height;
var ground:Sprite = addChild(Painter.createGradientRect(Display.width*2, Display.height, [Color.horizon, Color.ground], [1, 1], null, 90)) as Sprite;
ground.y = -1;
ground.x = -Display.width;
//遠景画像作成
_image = new BitmapData(_imageWidth, _cloudHeight, true, 0x00FFFFFF);
for (var n:int = 0; n < 80; n++) {
var cloud:BitmapData = Painter.createCloud(_cloudWidth, _cloudHeight, n+200, 1, Color.cloudBase, Color.cloudLight, Color.cloudShadow);
_image.copyPixels(cloud, cloud.rect, new Point(Math.random() * (_imageWidth - _cloudWidth), 0), null, null, true);
}
_image.applyFilter(_image, _image.rect, new Point(), new BlurFilter(2, 2, 1));
_cloudSprite = new Sprite();
_cloudSprite.x = -_viewWidth / 2;
_cloudSprite.y = -_cloudHeight / 2;
addChild(_cloudSprite);
}
/**
* 遠景画像をスライドする
*/
public function slide(per:Number):void {
per %= 1;
_cloudSprite.graphics.clear();
_cloudSprite.graphics.beginBitmapFill(_image, new Matrix(1, 0, 0, 1, _imageWidth * per, 0), true, true);
_cloudSprite.graphics.drawRect(0, 0, _viewWidth, _cloudHeight);
}
}
/**
* 画像生成中画面
*/
class LoadingScene extends Sprite {
private var _lineWidth:Number = 200;
private var _loadedLine:Sprite;
public function LoadingScene() {
var bg:Sprite = addChild(Painter.createGradientRect(Display.width, Display.height, [0x000000], [1])) as Sprite;
var baseLine:Sprite = addChild(Painter.createGradientRect(_lineWidth, 2, [0x444444], [1])) as Sprite;
_loadedLine = addChild(Painter.createGradientRect(_lineWidth, 2, [0x7DA3C8], [1])) as Sprite;
baseLine.x = _loadedLine.x = int((Display.width - _lineWidth) / 2);
baseLine.y = _loadedLine.y = int((Display.height - baseLine.height) / 2);
setProgress(0);
}
public function setProgress(per:Number):void {
_loadedLine.width = _lineWidth * per;
}
}