package { /** * Alternativa3D 環境マップのテスト * 画面ドラッグで回転します、 * * Alternativa3D platformのフォーラムで公開されていた、環境マップマテリアルの習作です。 * あくまでAlternativa3Dの環境マップテストです。 * 他意はございません。 * * 画像は最初に3枚読み込みますが、もし表示されなかったらリロードしてください * * LOADで画像はめ込めますけどね・・・ * * @narutohyper */ import alternativ5.engine3d.materials.FillMaterial; import alternativ5.engine3d.materials.TextureMaterial; import alternativ5.engine3d.core.Object3D; import alternativ5.engine3d.core.Mesh; import alternativ5.engine3d.core.Vertex import alternativ5.engine3d.core.Surface import alternativ5.engine3d.events.MouseEvent3D import alternativ5.engine3d.loaders.*; import alternativ5.types.Point3D; import alternativ5.types.Texture; import alternativ5.utils.* import flash.display.*; import flash.net.URLRequest; import flash.events.Event; import flash.events.MouseEvent; import flash.system.LoaderContext; import flash.geom.Point; import flash.geom.Matrix; import flash.system.Security; import flash.text.*; import org.libspark.thread.EnterFrameThreadExecutor; import org.libspark.thread.Thread; [SWF(width = 465, height = 465, frameRate = 60,backgroundColor=0x000000)] public class SimpleDemo extends Sprite { public static const CROSSDOMAIN:String = "http://marubayashi.net/crossdomain.xml"; public var mc1:MovieClip; public var mc2:MovieClip; private var bmd1:BitmapData; private var bmd2:BitmapData; private var bmd3:BitmapData; private var mcm1:TextureMaterial private var mcm2:TextureMaterial private var mcm3:TextureEnvironmentMaterial private var newMesh:Mesh; public function SimpleDemo():void { var dbg:TextField=new TextField() dbg.autoSize=TextFieldAutoSize.LEFT dbg.selectable=false; dbg.mouseEnabled=false; var format:TextFormat=new TextFormat(); format.color=0x666666 format.size=12; format.font='_ゴシック'; dbg.defaultTextFormat=format dbg.x=100; addChild(dbg) var img1:Loader=new Loader(); var img2:Loader=new Loader(); var img3:Loader=new Loader(); Security.loadPolicyFile(CROSSDOMAIN); var context:LoaderContext = new LoaderContext(true); img1.load(new URLRequest('http://marubayashi.net/archive/sample/images/environment/a.jpg'), context); img1.contentLoaderInfo.addEventListener(Event.COMPLETE, img1Complete); function img1Complete (e:Event):void { img1.contentLoaderInfo.removeEventListener(Event.COMPLETE, img1Complete); bmd1=new BitmapData(800,800,false,0x000000) bmd1.perlinNoise(40, 40, 1, 1, true, true, 8, true, null); bmd1.draw(img1.content,new Matrix(1,0,0,1,300,300),null,BlendMode.SCREEN) img2.load(new URLRequest('http://marubayashi.net/archive/sample/images/environment/b.jpg'), context); img2.contentLoaderInfo.addEventListener(Event.COMPLETE, img2Complete); } function img2Complete (e:Event):void { img2.contentLoaderInfo.removeEventListener(Event.COMPLETE, img2Complete); bmd2=new BitmapData(200,200,false,0) bmd2.draw(img2.content) img3.load(new URLRequest('http://marubayashi.net/archive/sample/images/environment/c.jpg'), context); img3.contentLoaderInfo.addEventListener(Event.COMPLETE, img3Complete); } function img3Complete (e:Event):void { img3.contentLoaderInfo.removeEventListener(Event.COMPLETE, img3Complete); bmd3=new BitmapData(200,200,false,0) bmd3.draw(img3.content) } this.addEventListener(Event.ENTER_FRAME, onEnterFrame); function onEnterFrame(e:Event):void { loadCheck() } function loadCheck():void { if (bmd1,bmd2,bmd3) { removeEventListener(Event.ENTER_FRAME, onEnterFrame); removeChild(dbg) init() } else { dbg.text='now loading '; dbg.appendText((img1.contentLoaderInfo.bytesTotal>1000)?Math.round(img1.contentLoaderInfo.bytesLoaded/img1.contentLoaderInfo.bytesTotal*100)+'% ':'-?-'); dbg.appendText((img2.contentLoaderInfo.bytesTotal>1000)?Math.round(img2.contentLoaderInfo.bytesLoaded/img2.contentLoaderInfo.bytesTotal*100)+'% ':'-?-'); dbg.appendText((img3.contentLoaderInfo.bytesTotal>1000)?Math.round(img3.contentLoaderInfo.bytesLoaded/img3.contentLoaderInfo.bytesTotal*100)+'% ':'-?-'); } } } private function init():void { // テンプレートを作成します var template:BasicTemplate = new BasicTemplate(); addChild(template); template.camera.coords=new Point3D(0,0,-1000) // マテリアルを作成します var material1:FillMaterial=new FillMaterial(0xEEEEEE,1,BlendMode.NORMAL,1,0x0000000); var material2:FillMaterial=new FillMaterial(0x666666,1,BlendMode.NORMAL,1,0x0000000); mcm1=new TextureMaterial(new Texture(bmd1),1,false,true) mcm2=new TextureMaterial(new Texture(bmd2),1,false,true) mcm3=new TextureEnvironmentMaterial(new Texture(bmd3), new Texture(bmd1),0.2,1.0,true,true) newMesh=new Mesh(); newMesh.createVertex( 290.00, 375.00, -25.00, 0); newMesh.createVertex( 270.00, 384.00, -25.00, 1); newMesh.createVertex(-270.00, 384.00, -25.00, 2); newMesh.createVertex(-290.00, 375.00, -25.00, 3); newMesh.createVertex(-300.00, 354.00, -25.00, 4); newMesh.createVertex(-300.00, -354.00, -25.00, 5); newMesh.createVertex(-290.00, -375.00, -25.00, 6); newMesh.createVertex(-270.00, -384.00, -25.00, 7); newMesh.createVertex( 270.00, -384.00, -25.00, 8); newMesh.createVertex( 290.00, -375.00, -25.00, 9); newMesh.createVertex( 300.00, -354.00, -25.00,10); newMesh.createVertex( 300.00, 354.00, -25.00,11); newMesh.createVertex( 270.00, 354.00, -25.00,12); newMesh.createVertex(-270.00, 354.00, -25.00,13); newMesh.createVertex(-270.00, -354.00, -25.00,14); newMesh.createVertex( 270.00, -354.00, -25.00,15); newMesh.createVertex( 290.00, 375.00, 5.00,16); newMesh.createVertex( 270.00, 384.00, 5.00,17); newMesh.createVertex(-270.00, 384.00, 5.00,18); newMesh.createVertex(-290.00, 375.00, 5.00,19); newMesh.createVertex(-300.00, 354.00, 5.00,20); newMesh.createVertex(-300.00, -354.00, 5.00,21); newMesh.createVertex(-290.00, -375.00, 5.00,22); newMesh.createVertex(-270.00, -384.00, 5.00,23); newMesh.createVertex( 270.00, -384.00, 5.00,24); newMesh.createVertex( 290.00, -375.00, 5.00,25); newMesh.createVertex( 300.00, -354.00, 5.00,26); newMesh.createVertex( 300.00, 354.00, 5.00,27); newMesh.createVertex( 270.00, 354.00, 25.00,28); newMesh.createVertex(-270.00, 354.00, 25.00,29); newMesh.createVertex(-270.00, -354.00, 25.00,30); newMesh.createVertex( 270.00, -354.00, 25.00,31); newMesh.createVertex( 191.00, 260.00, 59.50,32); newMesh.createVertex(-191.00, 260.00, 59.50,33); newMesh.createVertex(-191.00, -260.00, 59.50,34); newMesh.createVertex( 191.00, -260.00, 59.50,35); newMesh.createVertex( 93.00, 140.00, 73.99,36); newMesh.createVertex( -93.00, 140.00, 73.99,37); newMesh.createVertex( -93.00, -140.00, 73.99,38); newMesh.createVertex( 93.00, -140.00, 73.99,39); var textureW:Number=600; var textureH:Number=768; var facesArray:Array=[] //正面 facesArray=[]; setFaceAndUv([ 1, 0, 3, 2],textureW,textureH,'front_0','xy',true); setFaceAndUv([ 0,11, 4, 3],textureW,textureH,'front_1','xy',true); setFaceAndUv([11,10, 5, 4],textureW,textureH,'front_2','xy',true); setFaceAndUv([10, 9, 6, 5],textureW,textureH,'front_3','xy',true); setFaceAndUv([ 9, 8, 7, 6],textureW,textureH,'front_4','xy',true); newMesh.createSurface(facesArray,'front') //裏 facesArray=[]; setFaceAndUv([37,38,39,36],textureW,textureH,'back_0'); setFaceAndUv([33,37,36,32],textureW,textureH,'back_1'); setFaceAndUv([36,39,35,32],textureW,textureH,'back_2'); setFaceAndUv([38,34,35,39],textureW,textureH,'back_3'); setFaceAndUv([33,34,38,37],textureW,textureH,'back_4'); setFaceAndUv([29,33,32,28],textureW,textureH,'back_5'); setFaceAndUv([32,35,31,28],textureW,textureH,'back_6'); setFaceAndUv([34,30,31,35],textureW,textureH,'back_7'); setFaceAndUv([29,30,34,33],textureW,textureH,'back_8'); setFaceAndUv([18,29,28,17],textureW,textureH,'back_9'); setFaceAndUv([28,31,26,27],textureW,textureH,'back_10'); setFaceAndUv([30,23,24,31],textureW,textureH,'back_11'); setFaceAndUv([20,21,30,29],textureW,textureH,'back_12'); setFaceAndUv([16,17,28],textureW,textureH,'back_13'); setFaceAndUv([16,28,27],textureW,textureH,'back_14'); setFaceAndUv([18,19,29],textureW,textureH,'back_15'); setFaceAndUv([19,20,29],textureW,textureH,'back_16'); setFaceAndUv([30,21,22],textureW,textureH,'back_17'); setFaceAndUv([30,22,23],textureW,textureH,'back_18'); setFaceAndUv([31,24,25],textureW,textureH,'back_19'); setFaceAndUv([31,25,26],textureW,textureH,'back_20'); newMesh.createSurface(facesArray,'back') //Side facesArray=[]; setFaceAndUv([0,1,17,16],textureW,textureH,'side_0','xz'); setFaceAndUv([1,2,18,17],textureW,textureH,'side_1','xz'); setFaceAndUv([2,3,19,18],textureW,textureH,'side_2','xz'); setFaceAndUv([3,4,20,19],textureW,textureH,'side_3','yz'); setFaceAndUv([4,5,21,20],textureW,textureH,'side_4','yz'); setFaceAndUv([5,6,22,21],textureW,textureH,'side_5','yz'); setFaceAndUv([6,7,23,22],textureW,textureH,'side_6','yz'); setFaceAndUv([7,8,24,23],textureW,textureH,'side_7','yz'); setFaceAndUv([8,9,25,24],textureW,textureH,'side_8','yz'); setFaceAndUv([9,10,26,25],textureW,textureH,'side_9','yz'); setFaceAndUv([26,10,11,27],textureW,textureH,'side_10','yz'); setFaceAndUv([27,11,0,16],textureW,textureH,'side_11','yz'); newMesh.createSurface(facesArray,'side') function setFaceAndUv(v:Array,w:Number,h:Number,id:Object,mode:String='xy',reverse:Boolean=false):void { facesArray.push(id) newMesh.createFace(v,id); var pt:Array=[]; for (var i:uint=0;i<v.length;i++) { if (mode=='xz') { pt.push(new Point((newMesh.vertices[v[i]].x+w/2)/w,(newMesh.vertices[v[i]].z+h/2)/h)) } else if (mode=='yz') { pt.push(new Point((newMesh.vertices[v[i]].y+w/2)/w,(newMesh.vertices[v[i]].z+h/2)/h)) } else { pt.push(new Point((newMesh.vertices[v[i]].x+w/2)/w,(newMesh.vertices[v[i]].y+h/2)/h)) } } if (reverse) { newMesh.setUVsToFace(pt[3],pt[2],pt[1],id) } else { newMesh.setUVsToFace(pt[0],pt[1],pt[2],id) } } newMesh.setMaterialToSurface(mcm3,'front'); newMesh.setMaterialToSurface(mcm2,'back'); newMesh.setMaterialToSurface(new FillMaterial(0xE0E0E0),'side'); newMesh.rotationY = 180 * Math.PI / 180; newMesh.rotationZ = 180 * Math.PI / 180; template.scene.root.addChild(newMesh); var me:Sprite=this; var dragFlag:Boolean=false var mouseSX:Number; var mouseSY:Number; var nowRotationX:Number; var nowRotationY:Number; me.stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown) function onDown(e:MouseEvent):void { me.stage.removeEventListener(MouseEvent.MOUSE_DOWN,onDown); me.stage.addEventListener(MouseEvent.MOUSE_UP,onUp); mouseSX=me.mouseX mouseSY=me.mouseY nowRotationX=newMesh.rotationX nowRotationY=newMesh.rotationY dragFlag=true } function onUp(e:MouseEvent):void { me.stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown); me.stage.removeEventListener(MouseEvent.MOUSE_UP,onUp); dragFlag=false } Thread.initialize(new EnterFrameThreadExecutor()); new MainThread(this).start(); template.onPreRender = function():void { if (dragFlag) { newMesh.rotationY=nowRotationY+(mouseSX-mouseX)/-2 * Math.PI / 180; newMesh.rotationX=nowRotationX+(mouseSY-mouseY)/2 * Math.PI / 180; } } } public function drawImage(bmd:BitmapData):void { bmd3.draw(bmd) mcm3=new TextureEnvironmentMaterial(new Texture(bmd3), new Texture(bmd1),0.2,1.0,true,true) newMesh.setMaterialToSurface(mcm3,'front'); } } } import org.libspark.thread.Thread; import flash.events.Event; import flash.events.MouseEvent; import flash.display.SimpleButton; import flash.utils.ByteArray; import flash.net.FileReference; import flash.net.FileReferenceList; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.Rectangle; import flash.display.*; import flash.text.*; import flash.system.Security; class MainThread extends Thread { public static const CROSSDOMAIN:String = "http://assets.wonderfl.net/crossdomain.xml"; private var _base:SimpleDemo; private var _loadButton:Button; private var _saveButton:Button; private var _original:Loader; private var _guide:Guide; private var bmd:BitmapData public function MainThread(base:SimpleDemo) { this._base = base; this._loadButton = this._base.addChild(new Button('LOAD', 60)) as Button; this._loadButton.x = this._loadButton.y = 1; this._saveButton = this._base.addChild(new Button('SAVE', 60)) as Button; this._saveButton.x = 1; this._saveButton.y = this._loadButton.height + 2; this._guide = this._base.addChild(new Guide()) as Guide; this._guide.x = this._guide.y = (465 - 360) >> 1; this.bmd=new BitmapData(200,160,false,0x308CCB) } protected override function run():void { this._event(); } private function _event():void { event(this._loadButton, MouseEvent.CLICK, this._loadImage); event(this._saveButton, MouseEvent.CLICK, this._saveImage); Security.loadPolicyFile(CROSSDOMAIN); } // load image private function _loadImage(e:MouseEvent):void { trace(Button(e.target).label) var file:FileReference = new FileReference(); event(file, Event.SELECT, this._loadFileSelected); event(file, Event.CANCEL, this._loadFileCancel); file.browse(); } private function _loadFileSelected(e:Event):void { var file:FileReference = FileReference(e.target); event(file, Event.COMPLETE, this._fileLoaded); file.load(); } private function _fileLoaded(e:Event):void { if (this._original) { //this._original.parent.removeChild(this._original); this._original.unload(); } this._original = new Loader(); this._original.loadBytes(FileReference(e.target).data); event(this._original.contentLoaderInfo, Event.COMPLETE, this._imageLoaded); } private function _loadFileCancel(e:Event):void { this._event(); } private function _imageLoaded(e:Event):void { var a:Number = 159 / this._original.width; var b:Number = 164 / this._original.height; var mtr:Matrix=new Matrix(a,0,0,b,21,17) this.bmd=new BitmapData(200,200,true,0x00000000) this.bmd.draw(this._original.content,mtr) this._base.drawImage(bmd) this._event(); } // save image private function _saveImage(e:Event):void { var raw:BitmapData = new BitmapData(360, 360, true, 0x0); this._guide.visible = false; raw.draw(this._base, new Matrix(1, 0, 0, 1, -this._guide.x, -this._guide.y), null, null, null, true); this._guide.visible = true; var png:ByteArray = PNGEnc.encode(raw); raw.dispose(); var file:FileReference = new FileReference(); event(file, Event.SELECT, this._saveFileSelected); event(file, Event.CANCEL, this._saveFileSelected); file.save(png, 'noflash.png'); } private function _saveFileSelected(e:Event):void { this._event(); } } class Guide extends Shape { public function Guide() { var g:Graphics = this.graphics; g.lineStyle(1, 0xFF0000, 0.3, true); g.drawRect(0, 0, 360, 360); } } class Button extends SimpleButton { public var label:String public function Button(_label:String, width:int = 0):void { label=_label var up:Sprite = _buildImage(label, 0x0, width); var over:Sprite = _buildImage(label, 0x333333, width); var down:Sprite = _buildImage(label, 0x333333, width); down.y = 1; super(up, over, down, up); } private static function _buildImage(label:String, color:int, width:int = 0):Sprite { var text:TextField = new TextField(); text.defaultTextFormat = new TextFormat('Verdana', 10, 0xffffff, true, null, null, null, null, TextFormatAlign.CENTER); text.autoSize = TextFieldAutoSize.LEFT text.selectable = false; text.text = label; text.x = (width - text.width) >> 1; text.y = 5; var base:Shape = new Shape(); var g:Graphics = base.graphics; g.beginFill(color); g.drawRect(0, 0, width, text.height + 10); g.endFill(); var sp:Sprite = new Sprite(); sp.addChild(base); sp.addChild(text); return sp; } } import alternativ5.engine3d.controllers.CameraController; import alternativ5.engine3d.core.Camera3D; import alternativ5.engine3d.core.Object3D; import alternativ5.engine3d.core.Scene3D; import alternativ5.engine3d.display.View; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; import flash.display.StageScaleMode; import flash.events.Event; /** * BasicTemplate for Alternativa3D * Alternativa3Dを扱いやすくするためのテンプレートです * @author Yasu */ class BasicTemplate extends Sprite{ /** * シーンインスタンスです。 */ public var scene:Scene3D; /** * ビューインスタンスです。 */ public var view:View; /** * カメラインスタンスです。 */ public var camera:Camera3D; /** * カメラコントローラーです。 */ public var cameraContoller:CameraController; private var _viewWidth:int; private var _viewHeight:int; private var _scaleToStage:Boolean; /** * 新しい BasicTemplate インスタンスを作成します。 * @param viewWidth * @param viewHeight * @param scaleToStage */ public function BasicTemplate(viewWidth:int=640, viewHeight:int=480, scaleToStage:Boolean = true) { _viewWidth = viewWidth; _viewHeight = viewHeight; _scaleToStage = scaleToStage; // Creating scene scene = new Scene3D(); scene.splitAnalysis = false; // not analysis for performance scene.root = new Object3D(); // Adding camera camera = new Camera3D(); camera.z = -1000; scene.root.addChild(camera); // camera contoller cameraContoller = new CameraController(this); cameraContoller.camera = camera; // set view view = new View(); view.camera = camera; addChild(view); // stage if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } /** * 初期化されたときに実行されるイベントです。 * 初期化時に実行したい処理をオーバーライドして記述します。 */ protected function atInit():void {} /** * 初期化されたときに実行されるイベントです。 * 初期化時に実行したい処理を記述します。 */ private var _onInit:Function = function():void { }; public function get onInit():Function { return _onInit; } public function set onInit(value:Function):void { _onInit = value; } /** * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。 * レンダリング前に実行したい処理をオーバーライドして記述します。 */ protected function atPreRender():void {} /** * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。 * レンダリング前に実行したい処理を記述します。 */ private var _onPreRender:Function = function():void{}; public function get onPreRender():Function { return _onPreRender; } public function set onPreRender(value:Function):void { _onPreRender = value; } /** * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。 * レンダリング後に実行したい処理をオーバーライドして記述します。 */ protected function atPostRender():void { } /** * Event.ENTER_FRAME 時に実行されるレンダリングのイベントです。 * レンダリング後に実行したい処理を記述します。 */ protected var _onPostRender:Function = function():void{}; public function get onPostRender():Function { return _onPostRender; } public function set onPostRender(value:Function):void { _onPostRender = value; } /** * レンダリングを開始します。 */ public function startRendering():void { addEventListener(Event.ENTER_FRAME, onRenderTick); } /** * レンダリングを停止します。 */ public function stopRendering():void { removeEventListener(Event.ENTER_FRAME, onRenderTick); } /** * シングルレンダリング(レンダリングを一回だけ)を実行します。 */ public function singleRender():void { onRenderTick(); } /** * @private */ private function init(e:Event = null):void { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.HIGH; // resize stage.addEventListener(Event.RESIZE, onResize); onResize(null); // render startRendering(); atInit(); _onInit(); } /** * @private */ private function onRenderTick(e:Event = null):void { atPostRender(); _onPostRender(); scene.calculate(); atPreRender(); _onPreRender(); } /** * @private */ private function onResize(event:Event = null):void { if (_scaleToStage) { view.width = stage.stageWidth; view.height = stage.stageHeight; }else { view.width = _viewWidth; view.height = _viewHeight; } } } import alternativ5.engine3d.alternativa3d; import alternativ5.engine3d.core.Camera3D; import alternativ5.engine3d.core.PolyPrimitive; import alternativ5.engine3d.display.Skin; import alternativ5.engine3d.materials.DrawPoint; import alternativ5.engine3d.materials.Material; import alternativ5.engine3d.materials.TextureMaterial; import alternativ5.engine3d.materials.TextureMaterialPrecision; import alternativ5.types.Matrix3D; import alternativ5.types.Point3D; import alternativ5.types.Texture; import alternativ5.types.alternativatypes; import alternativ5.utils.MathUtils; import flash.display.BlendMode; import flash.display.Graphics; import flash.display.Shape; import flash.geom.Matrix; use namespace alternativatypes; use namespace alternativa3d; class TextureEnvironmentMaterial extends TextureMaterial { private static const reflectionMatrix:Matrix = new Matrix(); private static var shapes:Array = new Array(); private var _reflection:Texture; private var _reflectionBlendMode:String; private var _reflectiveness:Number; private var gfx:Graphics; public function TextureEnvironmentMaterial(texture:Texture = null, reflection:Texture = null, reflectiveness:Number = 1.0, alpha:Number = 1.0, repeat:Boolean = false, smooth:Boolean = false, blendMode:String = BlendMode.NORMAL, precision:Number = TextureMaterialPrecision.MEDIUM, reflectionBlendMode:String = BlendMode.NORMAL) { super(texture, alpha, repeat, smooth, blendMode, -1, 0, precision); _reflection = reflection; _reflectiveness = reflectiveness; _reflectionBlendMode = reflectionBlendMode; } override alternativa3d function canDraw(primitive:PolyPrimitive):Boolean { return _reflection != null || _texture != null; } override alternativa3d function clear(skin:Skin):void { skin.gfx.clear(); var count:int = skin.numChildren; for (var i:int = 0; i < count; i++) { var shape:Shape = skin.removeChildAt(0) as Shape; shape.graphics.clear(); shapes.push(shape); } } /** * @private * @inheritDoc */ override alternativa3d function draw(camera:Camera3D, skin:Skin, length:uint, points:Array):void { if (_reflectiveness < 1) { super.draw(camera, skin, length, points); } if (_reflectiveness > 0) { var gfx:Graphics; if (_reflectiveness < 1) { var shape:Shape = shapes.pop(); if (shape == null) { shape = new Shape(); } skin.addChild(shape); gfx = shape.graphics; shape.alpha = _reflectiveness; shape.blendMode = _reflectionBlendMode; } else { skin.alpha = _reflectiveness; skin.blendMode = _blendMode; gfx = skin.gfx; } var cameraMatrix:Matrix3D = camera.cameraMatrix; var normal:Point3D = skin.primitive.face.globalNormal; var normalInCamX:Number = normal.x*cameraMatrix.a + normal.y*cameraMatrix.b + normal.z*cameraMatrix.c; var normalInCamY:Number = normal.x*cameraMatrix.e + normal.y*cameraMatrix.f + normal.z*cameraMatrix.g; var normalInCamZ:Number = normal.x*cameraMatrix.i + normal.y*cameraMatrix.j + normal.z*cameraMatrix.k; var focalLength:Number = camera.focalLength; var apoint:DrawPoint = points[0]; var bpoint:DrawPoint = points[1]; var cpoint:DrawPoint = points[2]; var ax:Number = apoint.x*focalLength/apoint.z; var ay:Number = apoint.y*focalLength/apoint.z; var bx:Number = bpoint.x*focalLength/bpoint.z; var by:Number = bpoint.y*focalLength/bpoint.z; var cx:Number; var cy:Number; var vx:Number; var vy:Number; var vz:Number; var rx:Number; var ry:Number; var rz:Number; var nx:Number; var ny:Number; var nz:Number; var dot:Number; var len:Number; var aN:Boolean; var bN:Boolean; var cN:Boolean; vx = apoint.x; vy = apoint.y; vz = apoint.z; dot = vx*normalInCamX + vy*normalInCamY + vz*normalInCamZ; rx = vx - 2*dot*normalInCamX; ry = vy - 2*dot*normalInCamY; rz = vz - 2*dot*normalInCamZ; len = Math.sqrt(rx*rx + ry*ry + rz*rz); nx = rx*0.5; ny = ry*0.5; nz = (rz - len)*0.5; len = Math.sqrt(nx*nx + ny*ny + nz*nz); nx /= len; ny /= len; aN = (nz > 0); var au:Number = 0.5 + nx*0.5; var av:Number = 0.5 - ny*0.5; vx = bpoint.x; vy = bpoint.y; vz = bpoint.z; dot = vx*normalInCamX + vy*normalInCamY + vz*normalInCamZ; rx = vx - 2*dot*normalInCamX; ry = vy - 2*dot*normalInCamY; rz = vz - 2*dot*normalInCamZ; len = Math.sqrt(rx*rx + ry*ry + rz*rz); nx = rx*0.5; ny = ry*0.5; nz = (rz - len)*0.5; len = Math.sqrt(nx*nx + ny*ny + nz*nz); nx /= len; ny /= len; bN = (nz > 0); var bu:Number = 0.5 + nx*0.5; var bv:Number = 0.5 - ny*0.5; for (var i:int = 1; i < length; i++) { cpoint = points[i]; cx = cpoint.x*focalLength/cpoint.z; cy = cpoint.y*focalLength/cpoint.z; vx = cpoint.x; vy = cpoint.y; vz = cpoint.z; dot = vx*normalInCamX + vy*normalInCamY + vz*normalInCamZ; rx = vx - 2*dot*normalInCamX; ry = vy - 2*dot*normalInCamY; rz = vz - 2*dot*normalInCamZ; len = Math.sqrt(rx*rx + ry*ry + rz*rz); nx = rx*0.5; ny = ry*0.5; nz = (rz - len)*0.5; len = Math.sqrt(nx*nx + ny*ny + nz*nz); nx /= len; ny /= len; cN = (nz > 0); var cu:Number = 0.5 + nx*0.5; var cv:Number = 0.5 - ny*0.5; var abx:Number = bx - ax; var aby:Number = by - ay; var acx:Number = cx - ax; var acy:Number = cy - ay; var abu:Number = bu - au; var abv:Number = bv - av; var acu:Number = cu - au; var acv:Number = cv - av; var det:Number = abu*acv - abv*acu; var w:Number = _reflection._width; var h:Number = _reflection._height; reflectionMatrix.a = (acv*abx - abv*acx)/det; reflectionMatrix.b = (acv*aby - abv*acy)/det; reflectionMatrix.c = (acu*abx - abu*acx)/det; reflectionMatrix.d = (acu*aby - abu*acy)/det; reflectionMatrix.tx = (av - 1)*reflectionMatrix.c - au*reflectionMatrix.a + ax; reflectionMatrix.ty = (av - 1)*reflectionMatrix.d - au*reflectionMatrix.b + ay; reflectionMatrix.a /= w; reflectionMatrix.b /= w; reflectionMatrix.c /= h; reflectionMatrix.d /= h; gfx.beginBitmapFill(_reflection._bitmapData, reflectionMatrix, true, true); gfx.moveTo(ax, ay); gfx.lineTo(bx, by); gfx.lineTo(cx, cy); bx = cx; by = cy; bu = cu; bv = cv; } } } private function lookAtMatrix(dx:Number, dy:Number, dz:Number):Matrix3D { return Matrix3D.rotationMatrix(Math.atan2(dz, Math.sqrt(dx * dx + dy * dy) - MathUtils.DEG90), 0, -Math.atan2(dx, dy)); } /** * @private */ private function drawTriangle(ax:Number, ay:Number, au:Number, av:Number, bx:Number, by:Number, bu:Number, bv:Number, cx:Number, cy:Number, cu:Number, cv:Number):void { var abx:Number = bx - ax; var aby:Number = by - ay; var acx:Number = cx - ax; var acy:Number = cy - ay; var abu:Number = bu - au; var abv:Number = bv - av; var acu:Number = cu - au; var acv:Number = cv - av; var det:Number = abu*acv - abv*acu; var w:Number = _reflection._width; var h:Number = _reflection._height; reflectionMatrix.a = (acv*abx - abv*acx)/det; reflectionMatrix.b = (acv*aby - abv*acy)/det; reflectionMatrix.c = (acu*abx - abu*acx)/det; reflectionMatrix.d = (acu*aby - abu*acy)/det; reflectionMatrix.tx = (av - 1)*reflectionMatrix.c - au*reflectionMatrix.a + ax; reflectionMatrix.ty = (av - 1)*reflectionMatrix.d - au*reflectionMatrix.b + ay; reflectionMatrix.a /= w; reflectionMatrix.b /= w; reflectionMatrix.c /= h; reflectionMatrix.d /= h; gfx.beginBitmapFill(_reflection._bitmapData, reflectionMatrix, true, true); gfx.moveTo(ax, ay); gfx.lineTo(bx, by); gfx.lineTo(cx, cy); } /** * @inheritDoc */ override public function clone():Material { var res:TextureEnvironmentMaterial = new TextureEnvironmentMaterial(_texture, _reflection, _reflectiveness, _alpha, _repeat, _smooth, _blendMode, _precision); return res; } } // http://www.5etdemi.com/blog/archives/2006/12/as3-png-encoder-faster-better/ class PNGEnc { public static function encode(img:BitmapData, type:uint = 0):ByteArray { // Create output byte array var png:ByteArray = new ByteArray(); // Write PNG signature png.writeUnsignedInt(0x89504e47); png.writeUnsignedInt(0x0D0A1A0A); // Build IHDR chunk var IHDR:ByteArray = new ByteArray(); IHDR.writeInt(img.width); IHDR.writeInt(img.height); if(img.transparent || type == 0) { IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA } else { IHDR.writeUnsignedInt(0x08020000); //24bit RGB } IHDR.writeByte(0); writeChunk(png,0x49484452,IHDR); // Build IDAT chunk var IDAT:ByteArray= new ByteArray(); switch(type) { case 0: writeRaw(img, IDAT); break; case 1: writeSub(img, IDAT); break; } IDAT.compress(); writeChunk(png,0x49444154,IDAT); // Build IEND chunk writeChunk(png,0x49454E44,null); // return PNG return png; } private static function writeRaw(img:BitmapData, IDAT:ByteArray):void { var h:int = img.height; var w:int = img.width; var transparent:Boolean = img.transparent; for(var i:int=0;i < h;i++) { // no filter if ( !transparent ) { var subImage:ByteArray = img.getPixels( new Rectangle(0, i, w, 1)); //Here we overwrite the alpha value of the first pixel //to be the filter 0 flag subImage[0] = 0; IDAT.writeBytes(subImage); //And we add a byte at the end to wrap the alpha values IDAT.writeByte(0xff); } else { IDAT.writeByte(0); var p:uint; for(var j:int=0;j < w;j++) { p = img.getPixel32(j,i); IDAT.writeUnsignedInt( uint(((p&0xFFFFFF) << 8)| (p>>>24))); } } } } private static function writeSub(img:BitmapData, IDAT:ByteArray):void { var r1:uint; var g1:uint; var b1:uint; var a1:uint; var r2:uint; var g2:uint; var b2:uint; var a2:uint; var r3:uint; var g3:uint; var b3:uint; var a3:uint; var p:uint; var h:int = img.height; var w:int = img.width; for(var i:int=0;i < h;i++) { // no filter IDAT.writeByte(1); if ( !img.transparent ) { r1 = 0; g1 = 0; b1 = 0; a1 = 0xff; for(var j:int=0;j < w;j++) { p = img.getPixel(j,i); r2 = p >> 16 & 0xff; g2 = p >> 8 & 0xff; b2 = p & 0xff; r3 = (r2 - r1 + 256) & 0xff; g3 = (g2 - g1 + 256) & 0xff; b3 = (b2 - b1 + 256) & 0xff; IDAT.writeByte(r3); IDAT.writeByte(g3); IDAT.writeByte(b3); r1 = r2; g1 = g2; b1 = b2; a1 = 0; } } else { r1 = 0; g1 = 0; b1 = 0; a1 = 0; for(j=0;j < w;j++) { p = img.getPixel32(j,i); a2 = p >> 24 & 0xff; r2 = p >> 16 & 0xff; g2 = p >> 8 & 0xff; b2 = p & 0xff; r3 = (r2 - r1 + 256) & 0xff; g3 = (g2 - g1 + 256) & 0xff; b3 = (b2 - b1 + 256) & 0xff; a3 = (a2 - a1 + 256) & 0xff; IDAT.writeByte(r3); IDAT.writeByte(g3); IDAT.writeByte(b3); IDAT.writeByte(a3); r1 = r2; g1 = g2; b1 = b2; a1 = a2; } } } } private static var crcTable:Array; private static var crcTableComputed:Boolean = false; private static function writeChunk(png:ByteArray, type:uint, data:ByteArray):void { var c:uint; if (!crcTableComputed) { crcTableComputed = true; crcTable = []; for (var n:uint = 0; n < 256; n++) { c = n; for (var k:uint = 0; k < 8; k++) { if (c & 1) { c = uint(uint(0xedb88320) ^ uint(c >>> 1)); } else { c = uint(c >>> 1); } } crcTable[n] = c; } } var len:uint = 0; if (data != null) { len = data.length; } png.writeUnsignedInt(len); var p:uint = png.position; png.writeUnsignedInt(type); if ( data != null ) { png.writeBytes(data); } var e:uint = png.position; png.position = p; c = 0xffffffff; for (var i:int = 0; i < (e-p); i++) { c = uint(crcTable[ (c ^ png.readUnsignedByte()) & 0xff] ^ (c >>> 8)); } c = uint(c^uint(0xffffffff)); png.position = e; png.writeUnsignedInt(c); } } Alternativa3D TextureEnvironmentMaterial (環境マップ)のテスト