トップページ > 過去ログ > 記事閲覧
自作シェーダの使用について
名前:PO! 日時: 2010/03/05 11:18

こんにちは。PO!と申します。 最近DxLib(C#版)を使って2Dゲームを作成しようとしています。 ちょっと描画手順で分からないことがあったので質問させてください。 DxLibのレンダリング結果にポストエフェクト(ブルーム、2Dブラーなど)を使用したいと 思っているのですが、DxLibで自作シェーダを使うための手順などはありますでしょうか?

Page: 1 |

Re: 自作シェーダの使用について ( No.1 )
名前:管理人 日時:2010/03/05 23:45

すいません、現時点では自作シェーダを使う手段はありません 本格的なHDRやブラー処理ができるようなシェーダー使用環境を整備するのは時間がかかりますが、 エフェクト的なブルームや2Dブラーをシェーダーを使用して行う程度の機能でしたら1・2週間で作れるかもしれません ただ、シェーダを使用するとなりますとソフトを実行する側でも シェーダが使えないといけませんので、実行環境は少なくなって しまいますがその点は大丈夫でしょうか?
Re: 自作シェーダの使用について ( No.2 )
名前:PO! 日時:2010/03/06 04:00

返答ありがとうございます。 個人的には2Dのシェーダエフェクトが付けれればありがたいのですが、 結構大変そうですし、同じような要望が少ないようでしたら とりあえず後回しにして頂いていいかと(;´Д`) (DLLを作成した経験がほとんど無くて、LPDIRECT3DDEVICE9が 取得できれば後はシェーダ処理するDLLを自作すればなんとかなるかな という程度に思ってました。そう単純なものでもなさそうですね…… もし実装するとなるとどんな組み込み方になるんでしょう?) 実行環境が狭まることに付いては個人的には問題なしです。 ちなみにシェーダを使うならSM3.0くらいかなと思ってます。
Re: 自作シェーダの使用について ( No.3 )
名前:管理人 日時:

ご返答ありがとうございます > DLLを作成した経験がほとんど無くて、LPDIRECT3DDEVICE9が > 取得できれば後はシェーダ処理するDLLを自作すればなんとかなるかな > という程度に思ってました。 シェーダーにまつわる処理を全てPO!さんの側で組まれるのでしたら確かに仰る通りですが、 良い機会ですのでちょっとしたシェーダー機能を実装してみました もしかしたら機能的にPO!さんが希望される処理を実現できないかもしれませんが、 その際は更に自由度の高い機能にするか、LPDIRECT3DDEVICE9 を返す関数を追加します というわけで、とりあえずこちらをどうぞ http://homepage2.nifty.com/natupaji/DxLib/DxLibDotNet.zip // C#用 追加した関数は以下の通りです // シェーダーバージョン取得 int GetValidShaderVersion( void ) ; // 使用できるシェーダーのバージョンを取得する( 0=使えない 200=シェーダーモデル2.0が使用可能 300=シェーダーモデル3.0が使用可能 ) // シェーダー読み込み、削除系 int LoadVertexShader( const char *FileName ) ; // 頂点シェーダーバイナリをファイルから読み込み頂点シェーダーハンドルを作成する( 戻り値 -1:エラー -1以外:シェーダーハンドル ) int LoadPixelShader( const char *FileName ) ; // ピクセルシェーダーバイナリをファイルから読み込みピクセルシェーダーハンドルを作成する( 戻り値 -1:エラー -1以外:シェーダーハンドル ) int LoadVertexShaderFromMem( void *ImageAddress, int ImageSize ) ; // メモリ空間上に存在する頂点シェーダーバイナリから頂点シェーダーハンドルを作成する( 戻り値 -1:エラー -1以外:シェーダーハンドル ) int LoadPixelShaderFromMem( void *ImageAddress, int ImageSize ) ; // メモリ空間上に存在するピクセルシェーダーバイナリからピクセルシェーダーハンドルを作成する( 戻り値 -1:エラー -1以外:シェーダーハンドル ) int DeleteShader( int ShaderHandle ) ; // シェーダーハンドルの削除 int InitShader( void ) ; // シェーダーハンドルを全て削除する // 定数を外部から設定するための関数 int GetConstIndexToShader( const char *ConstantName, int ShaderHandle ) ; // 指定の名前を持つ定数の番
( No.を取得する

int SetVSConstF( int ConstantIndex, FLOAT4 Param ) ; // 頂点シェーダーの float 型定数を設定する
int SetVSConstFMtx( int ConstantIndex, MATRIX Param ) ; // 頂点シェーダーの float 型定数に行列を設定する
int SetVSConstI( int ConstantIndex, INT4 Param ) ; // 頂点シェーダーの int 型定数を設定する
int SetVSConstB( int ConstantIndex, BOOL Param ) ; // 頂点シェーダーの BOOL 型定数を設定する
int SetVSConstFArray( int ConstantIndex, FLOAT4 *ParamArray, int ParamNum ) ; // 頂点シェーダーの float 型定数を設定する( 配列を使って連番インデックスに一度に設定 )
int SetVSConstFMtxArray( int ConstantIndex, MATRIX *ParamArray, int ParamNum ) ; // 頂点シェーダーの float 型定数に行列を設定する( 配列を使って連番インデックスに一度に設定 )
int SetVSConstIArray( int ConstantIndex, INT4 *ParamArray, int ParamNum ) ; // 頂点シェーダーの int 型定数を設定する( 配列を使って連番インデックスに一度に設定 )
int SetVSConstBArray( int ConstantIndex, BOOL *ParamArray, int ParamNum ) ; // 頂点シェーダーの BOOL 型定数を設定する( 配列を使って連番インデックスに一度に設定 )

int SetPSConstF( int ConstantIndex, FLOAT4 Param ) ; // ピクセルシェーダーの float 型定数を設定する
int SetPSConstFMtx( int ConstantIndex, MATRIX Param ) ; // ピクセルシェーダーの float 型定数に行列を設定する
int SetPSConstI( int ConstantIndex, INT4 Param ) ; // ピクセルシェーダーの int 型定数を設定する
int SetPSConstB( int ConstantIndex, BOOL Param ) ; // ピクセルシェーダーの BOOL 型定数を設定する
int SetPSConstFArray( int ConstantIndex, FLOAT4 *ParamArray, int ParamNum ) ; // ピクセルシェーダーの float 型定数を設定する( 配列を使って連番インデックスに一度に設定 )
int SetPSConstFMtxArray( int ConstantIndex, MATRIX *ParamArray, int ParamNum ) ; // ピクセルシェーダーの float 型定数に行列を設定する( 配列を使って連番インデックスに一度に設定 )
int SetPSConstIArray( int ConstantIndex, INT4 *ParamArray, int ParamNum ) ; // ピクセルシェーダーの int 型定数を設定する( 配列を使って連番インデックスに一度に設定 )
int )
名前: 日時:

( No.SetPSConstBArray( int ConstantIndex, BOOL *ParamArray, int ParamNum ) ; // ピクセルシェーダーの BOOL 型定数を設定する( 配列を使って連番インデックスに一度に設定 )

// シェーダーで使用するテクスチャの設定
int SetUseTextureToShader( int StageIndex, int GraphHandle ) ; // シェーダー描画で使用するグラフィックを設定する

// 使用する頂点シェーダーとピクセルシェーダーの設定
int SetUseVertexShader( int ShaderHandle ) ; // シェーダー描画に使用する頂点シェーダーを設定する( -1を渡すと解除 )
int SetUsePixelShader( int ShaderHandle ) ; // シェーダー描画に使用するピクセルシェーダーを設定する( -1を渡すと解除 )

// シェーダーを使った描画
int DrawPrimitive2DToShader( VERTEX2DSHADER *Vertex, int VertexNum, int PrimitiveType ) ; // シェーダーを使って2Dプリミティブを描画する( ピクセルシェーダーのみが使用されます )
int DrawPrimitive3DToShader( VERTEX3DSHADER *Vertex, int VertexNum, int PrimitiveType ) ; // シェーダーを使って3Dプリミティブを描画する
int DrawPrimitiveIndexed2DToShader( VERTEX2DSHADER *Vertex, int VertexNum, unsigned short *Indices, int IndexNum, int PrimitiveType ) ; // シェーダーを使って2Dプリミティブを描画する(インデックス)( ピクセルシェーダーのみが使用されます )
int DrawPrimitiveIndexed3DToShader( VERTEX3DSHADER *Vertex, int VertexNum, unsigned short *Indices, int IndexNum, int PrimitiveType ) ; // シェーダーを使って3Dプリミティブを描画する(インデックス)


数が多いですが、殆どは定数を外部から設定するための関数です
ピクセルシェーダーを読み込んでそのシェーダーを使って画面左端に描画するサンプルプログラムは
以下のようになります

#include "DxLib.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
int grhandle, pshandle ;
VERTEX2DSHADER Vert[ 6 ] ;

// ウインドウモードで起動
ChangeWindowMode( TRUE );

// DXライブラリの初期化
if( DxLib_Init() < 0 ) return -1;

// 画像の読み込み
grhandle = LoadGraph( "Test1.bm )
名前: 日時:

( No.p" );

// ピクセルシェーダーバイナリコードの読み込み
pshandle = LoadPixelShader( "SamplePS.pso" ) ;

// 頂点データの準備
Vert[ 0 ].pos = VGet( 0.0f, 0.0f, 0.0f ) ;
Vert[ 1 ].pos = VGet( 128.0f, 0.0f, 0.0f ) ;
Vert[ 2 ].pos = VGet( 0.0f, 512.0f, 0.0f ) ;
Vert[ 3 ].pos = VGet( 128.0f, 512.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 = 1.0f ;
Vert[ 1 ].rhw = 1.0f ;
Vert[ 2 ].rhw = 1.0f ;
Vert[ 3 ].rhw = 1.0f ;
Vert[ 4 ] = Vert[ 2 ] ;
Vert[ 5 ] = Vert[ 1 ] ;

// 使用するテクスチャをセット
SetUseTextureToShader( 0, grhandle ) ;

// 使用するピクセルシェーダーをセット
SetUsePixelShader( pshandle ) ;

// 描画
DrawPrimitive2DToShader( Vert, 6, DX_PRIMTYPE_TRIANGLELIST ) ;

// キー入力待ち
WaitKey() ;

// DXライブラリの後始末
DxLib_End();

// ソフトの終了
return 0;
}

読み込んでいる SamplePS.pso は HLSL で書かれたピクセルシェーダーコードをコンパイルしたもので、
HLSL コード( SamplePS.fx )は以下のようになっています

// ピクセルシェーダーの入力
// 頂点シェーダーを介さない場合は以下の入力で固定です
struct PS_INPUT
{
float4 Diffuse : COLOR0 ;
float4 Specular : COLOR1 ;
float2 TexCoords0 : TEXCOORD0 ;
float2 TexCoords1 : TEXCOORD1 ;
} ;

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

sampler sampler0 : register( s0 ) ;

PS_OUTPUT main( PS_INPUT psin )
{< )
名前: 日時:

2010/03/15 23:35 ( No.br> PS_OUTPUT psout ;
float4 texc ;

// テクスチャカラーの読み出し
texc = tex2D( sampler0, psin.TexCoords0 ) ;

// テクスチャの青と赤を入れ替えて出力
psout.Output.r = texc.b ;
psout.Output.g = texc.g ;
psout.Output.b = texc.r ;
psout.Output.a = texc.a ;

return psout ;
}

( ちなみに HLSL のファイルを直接読み込む機能はありません
今のところプログラムを実行する側で d3dx9_28.dll 等の DirectX9.0c から 10.0 までの間に
乱発された中途半端なバージョンの DirectX がインストールされていなくても実行できるようにしたかったので・・・ )

頂点データの準備がちょっと面倒なので、簡素に記述できる関数を用意すべきか考えているのですが、
とりあえず現在はシェーダーを使って描画する手段はこの頂点データを用意する関数しかありません、すいません

あと、こちらにコンパイルしたものをアップしました

https://dxlib.xsrv.jp/file/PixelShaderTest.zip

中に簡易的なシェーダーコンパイラ( ShaderCompiler.exe )も付属しています、コンソールアプリケーションで、
内容的には DirectX SDK に付属してくる fxc.exe の劣化版です

この簡易コンパイラを使用して SamplePS.fx をコンパイルするためのバッチファイル( SamplePSCompile.bat )を
同梱しておきましたが、基本的には

// シェーダーモデル 3.0 の頂点シェーダーコードをコンパイルする場合
ShaderCompiler.exe /Tvs_3_0 ファイル名

// シェーダーモデル 3.0 のピクセルシェーダーコードをコンパイルする場合
ShaderCompiler.exe /Tps_3_0 ファイル名

という感じになります
( fxc.exe がお手元にありましたらそちらを使われた方が良いと思います )

と、PO!さんがどの程度の知識をお持ちなのかわからないのでどの位ご説明すれば良いのかわからないのですが、
ここまでの情報で使い方をご理解いただけますでしょうか? )
名前:61.124.50.106 日時:   <3JYxgQ6Cafwa6>

Re: 自作シェーダの使用について ( No.4 )
名前:PO! 日時:

対応ありがとうございます!まさか対応いただけるとは。 C#でもサンプルが動作するのを確認できました。ヽ(´∀`)ノ 配列ってC#-DLL間でも渡せるんですね。←まるで分かってない > ここまでの情報で使い方をご理解いただけますでしょうか? これだけ分かれば十分使用できます。ありがとうございました。 しかし使ってみて少し問題が出てきました。 作ったのは単純なスターボウエフェクトのプログラムです。 加算合成が上手くうごいていないのでカオスな描画状態ですが 一応お送り致します。 ↓ 試しに作ったプロジェクト(すいませんファイルが直リンできませんでしたorz) ttp://stgarea.web.fc2.com/dxlib.html --------------------- 問題点一覧 1.レンダリングターゲットが使えない? ポストエフェクトは大抵描画結果に対してシェーダを適用するものなので、 一時的に描画先をテクスチャ変えて描画するのが常套手段だと思うのですが、 これに相当する機能が良く分かりませんでしたorz 2.描画結果取得が重いー 要するに現在の描画結果が入力データに使えればいいので、代わりに GetDrawScreenGraph()を使ってみましたが、これは毎フレーム使うには厳しい 重さです。(実行に使ったノートPCのせいかもしれませんが(´Д`)) 3.加算合成への対応 スターボウやブルームのたぐいは描画結果を加算するタイプのエフェクトなの で、描画にSetDrawBlendMode()が使えないと厳しいです。 (試しに作ったプログラムが上手く動いていない原因です) 4.エフェクトファイルが使いたい(マルチパスレンダリングも使いたい) スターボウのような一部分が異なるピクセルシェーダを何回も実行するような シェーダの場合、ピクセルシェーダをエフェクトファイル内で条件分岐させて コンパイルする方法をよくやります。できればこれが使いたいです。 (DirectXサンプルのSkinnedMeshのエフェクトファイルみたいな感じです) これは同じファイルを何個か作れば対応できるものなのでそこまで問題とい う訳でもありません。もしかしたらテクニック内にマルチパスでシェーダを 記述した方が軽いかも?(←適当言ってる 5.シェーダ定数がうまく使えない これは私が勘違いしている可能性が高いです。シェーダファイ

Page: 1 |