[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 件のコメント:
コメントを投稿