3Dモデルをまるで2Dのフラッシュアニメのように表示したい

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Chalaza

3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#1

投稿記事 by Chalaza » 12年前

3Dモデルをまるで2Dのフラッシュアニメのように表示したいのです。
モデルに影がなくて、マテリアルごとににくっきりした太い輪郭線を描画する感じです。
材質の設定でマテリアルの色を単色にする(影がない)ところまではできたのですが、
DXライブラリのトゥーンレンダリングの輪郭線を使用すると、モデルの内側の線を表示したくない場所にまで輪郭線を描画してしまいます。
モデルの外側だけを輪郭表示できれば、内側はUVマッピング等で輪郭線を描いてしまえばいいのではないかと思うのですが、
モデルの外側だけを縁取るような輪郭表示というのはできないのでしょうか?
それとももっと良い方法があるのでしょうか?

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#2

投稿記事 by chalaza » 12年前

続けてすみません。
もし、外側だけの輪郭表示ができない場合は、モデルの材質(パーツ)ごとに輪郭を付ける方法だけでも知りたいです。
例えば、髪の毛は髪の毛で輪郭を付けて、顔は顔で輪郭を付けたりしたいのです。
そうすると顔と前髪の間とかにも髪の輪郭がついてくれるのではないかと思うのですが…そういうのはできないでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#3

投稿記事 by softya(ソフト屋) » 12年前

組んだこと無いけどZ値を使ってシェーダで輪郭線を書くぐらいしか思いつかないですね。

こういのうです。
「ピクセルシェーダ2.0で実装するZ値差ベースの輪郭線 - 作業記録」
http://d.hatena.ne.jp/kataho/20080116/p1
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#4

投稿記事 by Chalaza » 12年前

すみません、色々調べて頂きありがとうございます。
私も少し輪郭について調べていたら、「3Dモデルを単色(黒とか)で表示して、それを平面の画像にしてそれの輪郭を縁取ってモデルの上に描画する」
のようなやり方があるそうなのですが、それならモデルとの描画順を変えれば思ったような表示ができそうなんです。
その方法について何かやり方など教えていただけないでしょうか?解説サイト等でも結構です。
それが無理でしたら調べて頂いたシェーダの方法も考えてみるとします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#5

投稿記事 by softya(ソフト屋) » 12年前

Chalaza さんが書きました:すみません、色々調べて頂きありがとうございます。
私も少し輪郭について調べていたら、「3Dモデルを単色(黒とか)で表示して、それを平面の画像にしてそれの輪郭を縁取ってモデルの上に描画する」
のようなやり方があるそうなのですが、それならモデルとの描画順を変えれば思ったような表示ができそうなんです。
その方法について何かやり方など教えていただけないでしょうか?解説サイト等でも結構です。
それが無理でしたら調べて頂いたシェーダの方法も考えてみるとします。
Zバッファを応用とかZバッファの画像化で出来そうな気もしますが、色々考えてみないとワナもありそうな気が。

どうやるんだろう。
DXライブラリでも別バッファを作れば3Dモデルを単色での描画自体は簡単です。
「DXライブラリ置き場 リファレンスページ MakeScreen」
http://homepage2.nifty.com/natupaji/DxL ... html#R3N25
ただ、それの輪郭縁取りが遅そうな気が。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#6

投稿記事 by chalaza » 12年前

調べて見たところ、輪郭の縁取りはラプラシアンフィルタを使えば良いと書いてあったのですが、
もっと簡潔に書けないかと考えたところ、
モデルを別のスクリーンに黒で描画して、そのスクリーンを少し拡大したものをマスクにし、
そのマスクを輪郭の色で塗りつぶした上からモデルを描画するというゴリ押し的なものが思いついたのですが、まず、マスクのロードが画像ファイルからしか読み込めなさそうなのです。
新しく作ったスクリーンをマスクにはできないのでしょうか?

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#7

投稿記事 by softya(ソフト屋) » 12年前

chalaza さんが書きました:調べて見たところ、輪郭の縁取りはラプラシアンフィルタを使えば良いと書いてあったのですが、
もっと簡潔に書けないかと考えたところ、
モデルを別のスクリーンに黒で描画して、そのスクリーンを少し拡大したものをマスクにし、
そのマスクを輪郭の色で塗りつぶした上からモデルを描画するというゴリ押し的なものが思いついたのですが、まず、マスクのロードが画像ファイルからしか読み込めなさそうなのです。
新しく作ったスクリーンをマスクにはできないのでしょうか?
描画したものを別の色に塗ること自体はDXライブラリの機能で出来そうです。
と言うかモデルの色を変えて良いはずです。
2D画像にZ値も付けられますし、ビルボード描画しても良いし、3D空間に書く方法は色々とあります。

あとZバッファ系の隠し関数も使えます。
「キャラがダメージを受けた時の点滅について • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/viewtopic.php?t=9714&p=78319

何回かレンダリングすれば、なんとでもなるとは思うんですけどね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

Chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#8

投稿記事 by Chalaza » 12年前

単色のモデルを新しく作ったグラフィックハンドルに描画するところまではできたのですが、
やはり拡大しただけだと複雑な形はうまく縁取りになりませんね…。
やっぱり画像を縁取るしかないようです。
しかしラプラシアンフィルタのことがなかなか詳しい事がわかりません…。
画像の縁を膨張とかできれば楽なのですが…。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#9

投稿記事 by softya(ソフト屋) » 12年前

こことか参考になりません?
「ペチコートさんの大航海時代日記 DXライブラリでV.A.T.S.シェーダ」
http://dolpetticoat.blog.fc2.com/blog-entry-88.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#10

投稿記事 by chalaza » 12年前

情報ありがとうございます。そのサイトの通りにやってみたのですが、
ピクセルシェーダーを作る時のHLSLを使うのが初めてなもので、一応psoファイルは作れたのですが、
ピクセルシェーダーのDXライブラリサンプルプログラムの

コード:

// ピクセルシェーダーの入力
struct PS_INPUT
{
	float2 TexCoords0      : TEXCOORD0 ;
} ;

// ピクセルシェーダーの出力
struct PS_OUTPUT
{
	float4 Color0          : COLOR0 ;
} ;


// C++ 側で設定するテクスチャの定義
sampler  DiffuseMapTexture             : register( s0 ) ;		// ディフューズマップテクスチャ
float4   cfFactorColor                 : register( c5 ) ;		// 不透明度等


// main関数
PS_OUTPUT main( PS_INPUT PSInput )
{
	PS_OUTPUT PSOutput ;
	float4 TextureDiffuseColor ;

	// テクスチャカラーの読み込み
	TextureDiffuseColor = tex2D( DiffuseMapTexture, PSInput.TexCoords0 ) ;

	// 出力カラー = テクスチャカラー
	PSOutput.Color0 = TextureDiffuseColor ;

	// 出力アルファ = テクスチャアルファ * 不透明度
	PSOutput.Color0.a = TextureDiffuseColor.a * cfFactorColor.a ;

	// 出力パラメータを返す
	return PSOutput ;
}

これの『// C++ 側で設定するテクスチャの定義』という部分をどうやってC++側で設定するのかが分からないです。
samplerの値はどうやってC++で定義するのでしょうか?

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#11

投稿記事 by chalaza » 12年前

すみません。コピペしたら改行がおかしくなりました。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#12

投稿記事 by softya(ソフト屋) » 12年前

そうですね。HLSLは私も少し遊んだだけなので、詳しくないんですがDXライブラリのアチコチにに有る解説を読んてみてください。
「DXライブラリ置き場 3D関係関数リファレンスページ」
http://homepage2.nifty.com/natupaji/DxL ... nc_3d.html
ここの プログラマブルシェーダー関係関数を調べてもらうとs0とか説明が出てきます。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#13

投稿記事 by chalaza » 12年前

なんとかテクスチャの定義ができました。
ピクセルシェーダーは参考サイトとほとんど同じように作らせていただき、
ラプラシアンフィルタを使って輪郭を縁取り、その輪郭の部分だけにテクスチャの色を設定するような仕組みにしてみました。
それで、縁取った輪郭の部分をスクリーンハンドルに描画して、
そのスクリーンハンドルを描画した上にモデルを描画することでうまい具合に縁取ってくれたのですが、
そのスクリーンハンドルが透過されないので、背景が真っ黒になってしまいます。
SetDrawAlphaTestで無理やり透過しようとしてもできませんでした。
ピクセルシェーダーのほうのアルファ値を弄れば背景は透過されるのですが、同時にせっかく縁取った輪郭も透過される感じの状態です。

ピクセルシェーダ

コード:

// ピクセルシェーダーの入力
struct PS_INPUT
{
	float2 Tex      	: TEXCOORD0 ;	// テクスチャ
} ;

// ピクセルシェーダーの出力
struct PS_OUTPUT{
	float4 Color0          : COLOR0 ;
} ;

sampler  DiffuseMapTexture       : register( s0 ) ;// ディフューズマップテクスチャ
sampler  DecalTexture       : register( s2 ) ;// 縁取りの色

//ラプラシアンフィルタ
float2 nextXY(float2 uv, float dx, float dy){
   uv.x += dx/256;
   uv.y += dy/256;
   return uv;
}

// main関数
PS_OUTPUT main( PS_INPUT PSInput){

	PS_OUTPUT PSOutput;

	float4 sum;
	float2 Tex = PSInput.Tex;
				
	//ラプラシアンフィルタ
	sum = tex2D(DiffuseMapTexture, nextXY(Tex,-2,-2))
	      + tex2D(DiffuseMapTexture, nextXY(Tex,0,-2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,2,-2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,-2,0))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,2,0))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,-2,2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,0,2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,2,2))
		  + (tex2D(DiffuseMapTexture, Tex) * (-8.0f));
																	
		//縁取りの色と合成できるカラー
		float4 Col = float4( 1.0f,1.0f,1.0f,1.0f );
		//単色で塗りつぶした画面をデフューズテクスチャに
		float4 TextureDiffuseColor = tex2D(DiffuseMapTexture, Tex);
		//輪郭部分にテクスチャを合成
		PSOutput.Color0.rgb = (sum.rgb)* Col * tex2D(DecalTexture, Tex);
		PSOutput.Color0.a=1;//アルファは1(下げると背景は消えるが輪郭も消える)
		
		return PSOutput;
}
C++のDraw関数です。

コード:

//プレイヤー描画
void Player_Draw(Player_t Player){


	//描画先を描画用画面1にセット
	SetDrawScreen( ScreenHandle1) ;
	ClearDrawScreen() ;  //画面クリア

	// モデルの描画にオリジナルシェーダーを使用する設定をONにする
	MV1SetUseOrigShader( TRUE ) ;
	// 使用するピクセルシェーダーをセット
	SetUsePixelShader( PixelShaderHandle ) ;
	//モデル描画
	MV1SetPosition(Player.Model, Player.Modelpos ) ;
	MV1DrawModel(Player.Model) ;
	

	//描画先を描画用画面2にセット
	SetDrawScreen( ScreenHandle2) ;
	ClearDrawScreen() ;  //画面クリア

	// 頂点データ
	Vert[ 0 ].pos = VGet(    0.0f,   0.0f, 0.0f ) ;
	Vert[ 1 ].pos = VGet( 640.0f,   0.0f, 0.0f ) ;
	Vert[ 2 ].pos = VGet(    0.0f, 480.0f, 0.0f ) ;
	Vert[ 3 ].pos = VGet( 640.0f, 480.0f, 0.0f ) ;
	Vert[ 0 ].dif = GetColorU8( 255,255,255,255 ) ;
	Vert[ 0 ].spc = GetColorU8( 0,0,0,0 ) ;
	Vert[ 0 ].u = 0.0f ; Vert[ 0 ].v = 0.0f ;
	Vert[ 1 ].u = 1.0f ; Vert[ 1 ].v = 0.0f ;
	Vert[ 2 ].u = 0.0f ; Vert[ 2 ].v = 1.0f;
	Vert[ 3 ].u = 1.0f ; Vert[ 3 ].v = 1.0f;
	Vert[ 0 ].su = 0.0f ; Vert[ 0 ].sv = 0.0f ;
	Vert[ 1 ].su = 1.0f ; Vert[ 1 ].sv = 0.0f ;
	Vert[ 2 ].su = 0.0f ; Vert[ 2 ].sv = 1.0f;
	Vert[ 3 ].su = 1.0f ; Vert[ 3 ].sv = 1.0f;
	Vert[ 0 ].rhw = Vert[ 1 ].rhw = Vert[ 2 ].rhw = Vert[ 3 ].rhw = 1.0f ;
	Vert[ 4 ] = Vert[ 2 ] ;		Vert[ 5 ] = Vert[ 1 ] ;

	// 使用するピクセルシェーダーをセット
	SetUsePixelShader( PixelShaderHandle2 ) ;
	// 使用するテクスチャをセット
	SetUseTextureToShader( 0, ScreenHandle1 ) ;
	SetUseTextureToShader( 2, Beta1Image ) ;
	
	// 描画
	DrawPrimitive2DToShader( Vert, 6, DX_PRIMTYPE_TRIANGLELIST ) ;

	// 描画先を裏画面に変更
    SetDrawScreen( DX_SCREEN_BACK ) ;

	// モデルの描画にオリジナルシェーダーを使用する設定をOFFにする
	MV1SetUseOrigShader( FALSE ) ;
	//モデルを描画
	MV1DrawModel(Player.Model) ;

	// 縁取り輪郭のグラフィックハンドルを描画
	DrawGraph( 0, 0, ScreenHandle2, TRUE ) ;

	MV1DrawModel(Player.Model) ;
}
どうすれば背景を透過できるのでしょうか?

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#14

投稿記事 by chalaza » 12年前

すみません言い忘れてました。
貼りつけたピクセルシェーダのコードは『PixelShaderHandle2』です。1は単色シェーダなので。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#15

投稿記事 by softya(ソフト屋) » 12年前

すいません。明日調べますのでお待ちください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#16

投稿記事 by chalaza » 12年前

すみません、なんとか自力で透過できました。ピクセルシェーダーのHLSLで透過処理をしてみました。
適当ですがこんなかんじです。

コード:

// ピクセルシェーダーの入力
struct PS_INPUT
{
	float2 Tex      	: TEXCOORD0 ;	// テクスチャ
} ;

// ピクセルシェーダーの出力
struct PS_OUTPUT{
	float4 Color0          : COLOR0 ;
} ;

sampler  DiffuseMapTexture       : register( s0 ) ;// ディフューズマップテクスチャ
sampler  DecalTexture       : register( s2 ) ;// 縁取りの色

//ラプラシアンフィルタ
float2 nextXY(float2 uv, float dx, float dy){
   uv.x += dx/256;
   uv.y += dy/256;
   return uv;
}



// main関数
PS_OUTPUT main( PS_INPUT PSInput){

	PS_OUTPUT PSOutput;

	float4 sum;
	float2 Tex = PSInput.Tex;
				
	//ラプラシアンフィルタ
	sum = tex2D(DiffuseMapTexture, nextXY(Tex,-2,-2))
	      + tex2D(DiffuseMapTexture, nextXY(Tex,0,-2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,2,-2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,-2,0))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,2,0))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,-2,2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,0,2))
		  + tex2D(DiffuseMapTexture, nextXY(Tex,2,2))
		  + (tex2D(DiffuseMapTexture, Tex) * (-8.0f));
																	
		//縁取りの色と合成できるカラー
		float4 Col = float4( 1.0f,1.0f,1.0f,1.0f );
		//単色で塗りつぶした画面をデフューズテクスチャに
		float4 TextureDiffuseColor = tex2D(DiffuseMapTexture, Tex);
		//輪郭部分にテクスチャを合成
		float4 color = tex2D(DiffuseMapTexture, Tex);  
		//輪郭線
		PSOutput.Color0.rgb = (sum.rgb);
		
		//黒だったら透過する、違かったら指定した色に(後でテクスチャに変更)
		if(any(PSOutput.Color0.rgb - float4(0, 0, 0, 1))){
			 PSOutput.Color0.a = 1 ;  
			 PSOutput.Color0.rgb = float4(0.5f,0.3f,0.3f,1.0f);
		}else{           PSOutput.Color0.a = 0; 
		}
		return PSOutput;
}
これでうまい具合に縁取りの背景を透過できたのですが、もうひとつ問題がありまして、
モデルのメッシュごとに縁取りをして、それを自由に並べ変えたいのです。
例えば、顔の縁取りの上に顔があり、その上に髪の縁取りがあり、その上に髪がある。のような感じです。
それがやりたくて、とりあえずfor文で
描画先をグラフィックハンドルに→画面クリア→縁取り描画→描画先を裏画面に→グラフィックハンドルを描画→モデルを描画
これをメッシュの数の分繰り返すようにしたら重くてまともに動けなくなりました。
描画先の変更や画面クリアを繰り返すのが悪いとは思うのですが、あらかじめ縁取りをグラフィックハンドルにすべて描画してから
裏画面で好きな順番に並べ替える方法だと、メッシュの数だけグラフィックハンドルが必要になります。
グラフィックハンドルが大量にあるのも問題だと思うのですが、これで良いのでしょうか?

chalaza

Re: 3Dモデルをまるで2Dのフラッシュアニメのように表示したい

#17

投稿記事 by chalaza » 12年前

やっぱり内側の輪郭はUVマッピングで描くことにします。
外側が綺麗に縁取れたので満足です。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る