2018-07-30

[Flash] Starling DynamicLighting 2

[Flash] Starlingの学習 DynamicLighting 2

環境:

  • Starling 2.1
  • Starling Extension - Dynamic Lighting 2.0
  • Adobe AIR SDK 22
  • FlashDevelop 5.2
  • Windows 7 64bit

[話者] 前回、 [Flash] Starling DynamicLighting で作ったHeight map(ハイトマップ)はどうも作りかたをまちがえていた気がする。もう一度ためすぞ。

[合いの手] 何をまちがえてた?

[話者] 具体的には以下の画像で作ってみた。

前回は真ん中のgray画像をHeight mapとして使った。今回は右側の画像をHeight mapとして使ったんだ。

[合いの手] ちがうことはわかるけど‥‥どういうふうに変えたんだい?

[話者] 前回の画像は光源があるように見える。上から光が当たってて、頭の上は明るいけど、アゴのほうは暗い感じ。

今回は、光源を考えず、高さだけ考えて作ってみたんだ。

How to create a normal map Created by JamesにHeight mapの説明がある。

  • 高さ中央は 50% gray つまり rgb(127,127,127) の色だな。
  • いちばん高いのは white つまり rgb(255,255,255)
  • いちばん低いのは black つまり rgb(0,0,0)

[合いの手] なるほど。

[話者] あと、手書きでHeight map作れないものかと思っていたので、今回は手書きで作っているのだ。 しかし歩くアニメするキャラ「複数」Height mapを手書きで作るのは大変なので、今回は1枚のみ作った。

[合いの手] じゃあ今回はキャラは歩くアニメしないんだね。

[話者] 結果として、こうなった。

実Flash。操作可。ポイントライトをマウスドラッグで移動できる。ダブルクリックで消灯・点灯可能。

[合いの手] うーん、目がキラキラしてる感じは今回のがあるような‥‥。でも、やはり立体感はNormal mapのがあるよ。

そもそもさぁ、このStarling DynamicLightというのは Height mapだとうまく動かないんじゃないの?

[話者] そういう気がしてきた。複雑な曲線的凹凸がある有機物のHeight map手書きで作るというのも無理があったな。

[合いの手] ていうか、Lightingで影を表現したいなら3Dに行くべきじゃないの? 2Dキャラで影を用意するより結果的にラクそうだけど。

[話者] 破綻のない3Dキャラを作るのは大変そうなんだよな。大企業の作る3Dキャラでも笑顔がヘンだったり‥‥。 だから2Dにこだわりたいけど、Normal mapは3Dキャラで生成するとか考えてみよう。

Game.as

package 
{
    import flash.display.Bitmap;
    import starling.animation.Juggler;
    import starling.core.Starling;
    import starling.display.MovieClip;
    import starling.display.Quad;
    import starling.display.Sprite;
    import starling.events.Event;
    import starling.events.Touch;
    import starling.events.TouchEvent;
    import starling.events.TouchPhase;
    import starling.text.TextField;
    import starling.textures.Texture;
    import starling.textures.TextureAtlas;
    import starling.extensions.lighting.LightSource;
    import starling.extensions.lighting.LightStyle;
    
    /**
     * ...
     * @author foo
     */
    public class Game extends Sprite 
    {
        [Embed(source="../assets/character.png")]
        private static const CharacterTexture:Class;

        [Embed(source="../assets/character_n.png")]
        private static const CharacterNormalTexture:Class;

        [Embed(source="../assets/character_h2.png")]
        private static const CharacterHeightTexture:Class;
        
        [Embed(source="../assets/character.xml", mimeType="application/octet-stream")]
        private static const CharacterXml:Class;

        private var stgWidth:int;
        private var stgHeight:int;

        public function Game() 
        {
            if (stage) init()
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            addEventListener(Event.ENTER_FRAME, onGetGpuStyle);
        }
        
        private function onGetGpuStyle(e:Event):void  
        {
            if (Main.frameRate <= 0) return;
            removeEventListener(Event.ENTER_FRAME, onGetGpuStyle);
            
            addItem();
        }
        
        private function addItem():void 
        {
            stgWidth = stage.stageWidth;
            stgHeight = stage.stageHeight;

            addCharcters();
            addLights();
        }
        
        private function addLights():void 
        {
            var ambl:LightSource = LightSource.createAmbientLight();
            ambl.x = stgWidth * 0.5;
            ambl.y = stgHeight * 0.5;
            ambl.z = -50;
            //ambl.showLightBulb = true;
            
            var pla:LightSource = LightSource.createPointLight(0xffff00);
            pla.x = stgWidth * 0.2;
            pla.y = stgHeight * 0.3;
            pla.z = -50;
            pla.showLightBulb = true;
            
            var plb:LightSource = LightSource.createPointLight(0xffff00);
            plb.x = stgWidth * 0.8;
            plb.y = stgHeight * 0.3;
            plb.z = -50;
            plb.showLightBulb = true;
            
            var dirl:LightSource = LightSource.createDirectionalLight();
            dirl.x = stgWidth * 0.5;
            dirl.y = stgHeight * 0.3;
            dirl.z = -150;
            dirl.rotationY = -1.0;
            dirl.showLightBulb = true;
            
            addChild(ambl);
            addChild(pla);
            addChild(plb);
            //addChild(dirl);
        }
        
        private function addCharcters():void 
        {
            var chrTx:Texture = Texture.fromEmbeddedAsset(CharacterTexture);
            var chrNormalTx:Texture = Texture.fromEmbeddedAsset(CharacterNormalTexture);
            var chrHeightTx:Texture = Texture.fromEmbeddedAsset(CharacterHeightTexture);
            var chrXML:XML = XML(new CharacterXml());
            var txAt:TextureAtlas = new TextureAtlas(chrTx, chrXML);
            var normalTxAt:TextureAtlas = new TextureAtlas(chrNormalTx, chrXML);
            var heightTxAt:TextureAtlas = new TextureAtlas(chrHeightTx, chrXML);
            
            var tx:Vector.<Texture> = txAt.getTextures();
            var ntx:Vector.<Texture> = normalTxAt.getTextures();
            var htx:Vector.<Texture> = heightTxAt.getTextures();
            
            var mc1:MovieClip = addCharacter(tx, ntx);
            mc1.scaleX = -1;
            mc1.x = mc1.width + 100;
            mc1.y = 150;
            //var qd:Quad = new Quad(mc1.width, mc1.height, 0xcccccc);
            //qd.x = mc1.x; qd.y = mc1.y;
            //addChild(qd);
            addChild(mc1);
            //Starling.juggler.add(mc1);

            var msg:TextField = new TextField(120, 24, 'NormalMap');
            msg.format.color = 0xFFFFFF;
            msg.x = stgWidth / 2 - 120;;
            msg.y = mc1.y - 48;
            addChild(msg);
            
            var mc2:MovieClip = addCharacter(tx, htx);
            mc2.x = mc2.width - 100;
            mc2.y = 150;
            addChild(mc2);
            //Starling.juggler.add(mc2);
            
            msg = new TextField(120, 24, 'HeightMap');
            msg.format.color = 0xFFFFFF;
            msg.x = stgWidth / 2;
            msg.y = mc2.y - 48;
            addChild(msg);
        }
        
        private function addCharacter(tx:Vector.<Texture>, ntx:Vector.<Texture>):MovieClip
        {
            var mc:MovieClip = new MovieClip(tx, tx.length);
            var styl:LightStyle = new LightStyle(ntx[0]);
            styl.ambientRatio = 0.2;
            styl.diffuseRatio = 0.8;
            styl.specularRatio = 0.2;
            styl.shininess = 16;
            mc.style = styl;
            for (var i:int = 0; i < mc.numFrames; i++) {
                mc.setFrameAction(i, updateStyle);
            }
            return mc;
            
            function updateStyle(mc:MovieClip, frameId:int):void 
            {
                styl.normalTexture = ntx[frameId];
            }
        }
    }
}

0 件のコメント:

コメントを投稿

人気記事