fc2ブログ

ニャログ :大航海時代のデータと航海日記

大航海時代のデータと航海日記です

stage3D transparent mapping demo with sample code ( stage3Dで透過マッピング サンプル)

Flash Player 11 から新たに加わった GPUを使用しての描画
その Stage3Dで 透過マッピング (透明マッピング)の デモを作ってみたので
サンプルコードと共に公開
Transparent mapping demonstration in stage3D. (with sample code.)


   ※フラッシュプレーヤーが最新ではない と表示される方へ
     このデモは FlashPlayer11 でないと見れません (たぶん)
     ただし このデモを見るためだけに プレーヤーを更新する必要はないと思います
     更新してから見ても なんだ こんなのか と思うハズ
     ただ セキュリティ的には最新版の方がいいハズです
     PC環境によっては更新しない方がいい場合もあるから一概にはなんとも言えませんねぇ



Stage3D での 透過マッピング デモ

png形式の画像ファイルの透明な所 が モデルも切り抜かれている

簡易的な髪の毛の表現や 鉄格子や スポーツのネット の表現
洋服のレースなどが表現できるハズ


サンプルコード TransparentMapping_Main.as

透過マッピングdemo用PNG
透過マッピングdemo用PNG


公開されている 3D描画のライブラリで 透過マッピングが正しく行えるものが見当たらなかったので
なんとか自分で実現できないかと Stage3Dのサンプルを見て回ったけど
結局透過マッピングが出来ているデモに出会えませんでした

Flash Playerのバグなのか
それとも Stage3D ライブラリのバグなのか
3Dライブラリで未実装なだけなのか 知りたくて
いろいろ試していたら とりあえず実現できたので公開してみます (問題点も もちろんあるけど)

早く Alternativa3D とか minko とかの 3Dライブラリにも実装されるといいなぁ




まとめ

・drawTriangles()で描く順序を正しく行えば 現状のFlashPlayerのバージョンでも
  透過マッピングを実現することは可能
・そのためには インデックスバッファの順番が重要 (triangles:Vector<uint>)
・ただ今回のような1つのオブジェクトだけではないことが多いと思うので
  複数のオブジェクトがある場合は背面のオブジェクトから描画するように
  インデックスバッファの順序をソートしなおさないとならない (たぶん)
・透過した部分が若干黒いのが 細かいけど気になる


 (↓つづき で ダメな例も)


NGパターン1  透過マッピングなし / 両面表示



画像が透明な部分が黒色表示されてしまっている


再現するには ↓この行をコメントアウト
//renderContext.setBlendFactors( Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA );




NGパターン2  透過マッピングなし / 片面表示 (外側の面だけ)



もっと悪いパターン
面の裏側が透明なので一瞬何が何やらわからない
ただ不要な部分まで両面表示すると速度に影響すると考えられる

再現するには ↓この行をコメントアウト
//triangles = triangles.concat().reverse();
//triangles = triangles.concat(triangles.concat().reverse());

//renderContext.setBlendFactors( Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA );



NGパターン3  透過マッピング / 両面表示 / 面の表示順が正しくない


画像の透明部分は透明になったけど
面の表示順がおかしくよくわからない表示になってしまったパターン
ちょっと気持ち悪い 3D酔いしそう
よく見ると外側の面を描いた後に 内側の面を上書きしている
意図的にやれば面白い効果が出せるかも

再現するには ↓この行をコメントアウト
//triangles = triangles.concat().reverse();



ジブン用メモ

・頂点インデックスバッファ
  ・頂点座標 (+ 頂点カラー or 頂点UV座標)
  ・頂点同士は面インデックスで指定することで面になる
・面インデックスバッファ
  ・面情報 頂点座標3つで1つの面にする
  ・なので3つで1面
  ・どうゆう理屈かわからないが指定の仕方で表面と裏面になる 1,2,3 が表なら 1,3,2 や 3,2,1 は裏

・カメラ・オブジェクト1・オブジェクト2 のように分かれていると思ったがそうでもないっぽい
  ・指定する場所がないので オブジェクト1も2も同じデータに保持しているっぽい
  ・でその全体のデータをどこから見るかどんな風に見るか、をマトリックス変換で求めてカメラぽくしてるっぽい
  ・なのでオブジェクト単位に移動回転は、それ用に作らないとダメっぽい
  ・座標変換した結果、奥行き(Z座標)はなくなる?? のでZバッファとかいう概念がある?? のかな?
  ・座標変換途中は、奥行き(Z座標)を保持している気がするので、完全平面化する直前にZ座標を見て面インデックスをソートさせれば複数オブジェクトの透明マッピングをしてもダイジョブなのではないか?
  ・っていうかそもそも透明マッピングじゃない場合もオブジェクトの重なりはあるわけで実はその辺、ちゃんとやってるンでは?
  ・とするとオブジェクト毎にインデックス順がしっかりしていれば実はダイジョウブかも?



ActionScript 3.0

package
{
//参考元: Adobe Flash Platform 用 ActionScript® 3.0 リファレンスガイド
//参考元: http://help.adobe.com/ja_JP/FlashPlatform/reference/actionscript/3/flash/display3D/Context3D.html
//参考元: の Context3DExample.as を元に変更してあります
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;

import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTriangleFace;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

import flash.display3D.textures.Texture;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DBlendFactor;


public class Main extends Sprite
{
[Embed(source="demo.png")]
static private const EmbedTexture:Class;

public const viewWidth:Number = 600;
public const viewHeight:Number = 400;
public const zNear:Number = 1;
public const zFar:Number = 500;

public const fov:Number = 45;

private var stage3D:Stage3D;
private var renderContext:Context3D;
private var indexList:IndexBuffer3D;
private var vertexes:VertexBuffer3D;

private var projection:PerspectiveMatrix3D = new PerspectiveMatrix3D();
private var model:Matrix3D = new Matrix3D();
private var view:Matrix3D = new Matrix3D();
private var finalTransform:Matrix3D = new Matrix3D();

//For rotating the cube
private const pivot:Vector3D = new Vector3D();

private const VERTEX_SHADER:String =
"m44 op, va0, vc0 \n" + // 4x4 matrix transform
"mov v0, va1"; //copy color to varying variable v0

private const FRAGMENT_SHADER:String =
//"mov oc, v0"; //Set the output color to the value interpolated from the three triangle vertices
"mov ft0 v0\n" + "tex ft0, ft0, fs0<2d,clamp,linear>\n" + "mov oc ft0\n";

private var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var programPair:Program3D;

public function Main()
{
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.align = StageAlign.TOP_LEFT;
//this.stage.nativeWindow.activate(); //AIR only

stage3D = this.stage.stage3Ds[0];
stage3D.x = 10;
stage3D.y = 10;

//Add event listener before requesting the context
stage3D.addEventListener( Event.CONTEXT3D_CREATE, contextCreated );
stage3D.addEventListener( ErrorEvent.ERROR, contextCreationError );
stage3D.requestContext3D( Context3DRenderMode.AUTO );

//Compile shaders
vertexAssembly.assemble( Context3DProgramType.VERTEX, VERTEX_SHADER, false );
fragmentAssembly.assemble( Context3DProgramType.FRAGMENT, FRAGMENT_SHADER, false );
}

//Note, context3DCreate event can happen at any time, such as when the hardware resources are taken by another process
private function contextCreated( event:Event ):void
{
renderContext = Stage3D( event.target ).context3D;
trace( "3D driver: " + renderContext.driverInfo );
setupScene();
}

private function setupScene():void
{
renderContext.enableErrorChecking = true; //Can slow rendering - only turn on when developing/testing
renderContext.configureBackBuffer( viewWidth, viewHeight, 2, false );
renderContext.setCulling( Context3DTriangleFace.BACK );

//Create vertex index list for the triangles forming a cube
var triangles:Vector. = Vector.( //※ブログからだと<uint>が見えない場合あり
[
2,1,0, //front face
3,2,0,
4,7,5, //left face
7,6,5,
8,11,9, //back face
9,11,10,
12,15,13, //right face
13,15,14,
16,19,17, //bottom face
17,19,18,
/*
20,23,21, //top face
21,23,22
*/
]
);

//double side face 両面化
triangles = triangles.concat().reverse(); //面を裏返す (内側の面)
triangles = triangles.concat(triangles.concat().reverse()); //内側の面の集合の後に 外側の面 (元の面) を足す

indexList = renderContext.createIndexBuffer( triangles.length );
indexList.uploadFromVector( triangles, 0, triangles.length );

//Create vertexes - cube faces do not share vertexes
const dataPerVertex:int = 5;
var vertexData:Vector. = Vector.( //※ブログからだと<Number>が見えない場合あり
[
// x,y,z u,v format
0,0,0, 0,0, //front face
0,1,0, 0,.374,
1,1,0, .374,.374,
1,0,0, .374,0,

0,1,1, .749,.374, //left face
0,1,0, .749,0,
0,0,0, .376,0,
0,0,1, .376,.374,

0,0,1, 0,.376, //back face
1,0,1, .374,.376,
1,1,1, .374,.749,
0,1,1, 0,.749,

1,1,0, .749,.376, //right face
1,1,1, .749,.749,
1,0,1, .376,.749,
1,0,0, .376,.376,

0,0,0, .751,0, //bottom face
1,0,0, 1,0,
1,0,1, 1,.374,
0,0,1, .751,.374,

0,1,1, 0,1, //top face
1,1,1, 1,1,
1,1,0, 1,0,
0,1,0, 0,0,
]
);

vertexes = renderContext.createVertexBuffer( vertexData.length/dataPerVertex, dataPerVertex );
vertexes.uploadFromVector( vertexData, 0, vertexData.length/dataPerVertex );

//Upload programs to render context
programPair = renderContext.createProgram();
programPair.upload( vertexAssembly.agalcode, fragmentAssembly.agalcode );
renderContext.setProgram( programPair );

//
//texture
var texture:Texture = renderContext.createTexture(512, 512, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(new EmbedTexture().bitmapData);
renderContext.setTextureAt(0, texture);

//Identify vertex data inputs for vertex program
renderContext.setVertexBufferAt( 0, vertexes, 0, Context3DVertexBufferFormat.FLOAT_3 ); //va0 is position
renderContext.setVertexBufferAt( 1, vertexes, 3, Context3DVertexBufferFormat.FLOAT_2 ); //va1 is UV

//alpha blend for transparent mapping 透明マッピング用 アルファブレンドで drawTriangles()
renderContext.setBlendFactors( Context3DBlendFactor.SOURCE_ALPHA, Context3DBlendFactor.ONE_MINUS_SOURCE_ALPHA ); //alpha

//Set up 3D transforms
projection.perspectiveFieldOfViewRH( fov, viewWidth/viewHeight, zNear, zFar );
view.appendTranslation( 0, 0, -2 ); //Move view back
model.appendTranslation( -.5, -.5, -.5 ); //center cube on origin
this.stage.addEventListener( Event.ENTER_FRAME, render );
}

private function render( event:Event ):void
{
//Rotate model on each frame
model.appendRotation( .12, Vector3D.Z_AXIS, pivot );
model.appendRotation( .31, Vector3D.Y_AXIS, pivot );
model.appendRotation( .5, Vector3D.X_AXIS, pivot );

//view.appendTranslation( 0,0,-.01 );

//Combine transforms
finalTransform.identity();
finalTransform.append( model );
finalTransform.append( view );
finalTransform.append( projection );

//Pass the final transform to the vertex shader as program constant, vc0
renderContext.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 0, finalTransform, true );

//Clear is required before drawTriangles on each frame
renderContext.clear( .7,.3,.3 );

//Draw the 12 triangles that make up the cube
//renderContext.drawTriangles( indexList, 0, 12 );
renderContext.drawTriangles( indexList, 0, -1 );

//Show the frame
renderContext.present();
}

private function contextCreationError( error:ErrorEvent ):void
{
trace( error.errorID + ": " + error.text );
}
}
}



みんなのコメント


          
ナイショ話

※短縮URLおよび転送URL(っぽいもの)を含む場合 コメントできない場合があります
  例) abc.aaa/
  例) 123.gj/

※コメント内にアドレスを記入する際は http://の前に「→ 」をつけてください
  例) → http://www.google.co.jp/

※&#数字; 形式は使えません
  例) &#9829; と入力して ♥ を表示することはできません

※管理者にだけメッセージを送る の場合
  管理者にだけメッセージを送る の場合、誤記を修正しようとしてもできないらしいです
  追記の形で修正してください

※どうしてもエラーが出る場合
  あまり制限をきつくしていないつもりですが・・
  サイトURLを書かない
  半角英数字を書かないなど 工夫してみてください

※記事内容に関連しない 宗教関連および政治関連の書き込みは、ご遠慮ください

ニャログへようこそ
大航海時代オンラインのことを
ちょこちょこ書き込む予定


キャラ:ニャ・カプチーノ (メイン)
サーバ:Zephyros


見かけましたら どぞよろしく☆
FC2のファイル500kB制限がきつい

キャラクターのレアカードを作ろう!



キャラ:ニャ・カフェラッテ
サーバ:Zephyros

キャラクターカード:ニャ・カフェラッテ
意図せずヒロシイツキのポーズ


リンク:
  お好きなところにご自由に♪
コメント:
  あまりお返事しませんがお気軽に☆
トラックバック:
  関連記事ならぜひぜひ!


大航海ブログランキングに参加中!
ニャログ応援ありがとう

応援ありがと~♪
カテゴリ別に読む
迷子になったら 他
 (初心者さんにオススメのサイトの紹介)


記事一覧

ボトルキャップコレクション01
ニャログ内を検索
お役立ち(?)リンク集
大航海 新着(DOL-Ping)
最新記事
月別アーカイブ
最新トラックバック
最新コメント
RSSリンクの表示
© KOEI
(c)2005-2008 KOEI Co., Ltd. All rights reserved.
© TECMO KOEI
(C)2005-2010 TECMO KOEI GAMES CO., LTD. All rights reserved
カテクエ検索