2010/8/10 Na-7
2010/11/20 Na-7
 

技術資料一覧に戻る

 

SoftimageモデルのXNA向けマテリアル設定を改善する

注意 この資料は、筆者が自らの経験を記録したものであり、他人に勧めるものではありません。

この資料を参考として行った行為がいかなる結果になろうとも、筆者は責任を負いませんので予めご承知おきください。

 

◎目次

◎概要
◎使用ツール
◎サンプルコード(XNAViewer本体改修コード)
◎補足事項

 

 

 

◎概要

SoftimageモデルをXNAで動かすには、XNA向けマテリアル設定(DirectX9シェーダへの変更)作業が不可欠である。しかしこの作業は手間がかかる上に問題が生じる可能性 がある。

・個々のクラスタ/マテリアル毎に、DirectXシェーダを設定する必要があるので、マテリアル数が多いと手間がかかる

・DirectXシェーダ設定後は、(通常のSoftimage画面では)モデルが一色になる。表示画面を「リアルタイムシェーダ>DirectX9」にすると本来は表示されるはずだが、筆者及び幾つかのPC環境では画面が乱れたりSoftimageが強制終了するなど不具合が生じて表示できないことがある。この場合は、(Softimageでは)一色モデルで編集するしかないため、作業が大変やりにくくなる。

本稿では、XNAでマテリアルを一括設定するサンプルコードを紹介する。

これによりSoftimageでのXNA向けマテリアル設定変更作業が一切不要となり、上記の手間や問題が回避できる。クラスタ数やマテリアル数が多いモデルほど、作業工数削減効果が期待できる。

但し、1つのモデル内で多数のシェーダを使用する場合は不向きである。その場合はSoftimageで従来通り作業を行うと、従来通り表示される。

 

 

◎使用ツール

ツール名 入手元
XNA3.1(XNA GameStudio 3.1:ゲーム開発用フレームワーク) http://msdn.microsoft.com/ja-jp/xna/default.aspx
Softimage(旧名称XSI:Softimage Mod Tool 7.5:三次元CG製作用ソフトウェア) http://www.softimage.com/products/modtool/

 

 

◎サンプルコード(XNAViewer本体改修コード)

XNAViewer本体の LoadContent() 内の最後尾に下記コードを追加する。

// XNA向けシェーダ未設定モデルはBasicEffectとして渡されるので、これをカスタムエフェクトに差し替える改修

// エフェクトファイル(Phong.fxやLambert.fxなど)をXNAコンテンツファイルとして追加しておくこと
// 適用するエフェクトファイルを切り替える場合はコメントを書き換えること
Effect orgEffect = content.Load<Effect>("Content/Effects/Phong");
//Effect orgEffect = content.Load<Effect>("Content/Effects/Lambert");

// Softimageのデフォルト設定用画像ファイル(default_surface_mapなど)をXNAコンテンツファイルとして追加しておくこと
Texture2D albedoMap = content.Load<Texture2D>("Content/Textures/default_surface_map");
Texture2D ambientMap = content.Load<Texture2D>("Content/Textures/default_ambocc_map");
Texture2D normalMap = content.Load<Texture2D>("Content/Textures/default_normal_map");

foreach (ModelAsset m in Models)
{
   
foreach (ModelMesh mesh in m.CrosswalkModel.Meshes)
    {
       
foreach (ModelMeshPart part in mesh.MeshParts)
        {
           
// エフェクトのクローンを作成する
           
Effect myEffect = orgEffect.Clone(graphics.GraphicsDevice);

           
// エフェクトパラメータの引き継ぎ
           
foreach (EffectParameter parameter in part.Effect.Parameters)
            {
               
if (parameter.Name == "BasicTexture")
                {
                   
Texture2D texture = parameter.GetValueTexture2D();
                   
if (texture == null)
                        texture = albedoMap;
                    myEffect.Parameters[
"AlbedoMap"].SetValue(texture);
                    myEffect.Parameters[
"AmbientMap"].SetValue(ambientMap);
                    myEffect.Parameters[
"NormalMap"].SetValue(normalMap);
                }

               
if (parameter.Name == "AlbedoMap")
                    myEffect.Parameters[
"AlbedoMap"].SetValue(parameter.GetValueTexture2D());
               
if (parameter.Name == "AmbientMap")
                    myEffect.Parameters[
"AmbientMap"].SetValue(parameter.GetValueTexture2D());
               
if (parameter.Name == "NormalMap")
                    myEffect.Parameters[
"NormalMap"].SetValue(parameter.GetValueTexture2D());

               
if (parameter.Name == "Alpha")
                   
// HLSL側にグローバル変数が存在するかチェックし、OKの場合セットする(HLSL側にセマンティクス必須)
                    if (myEffect.Parameters.GetParameterBySemantic("Alpha") != null)
                        myEffect.Parameters[
"Alpha"].SetValue(parameter.GetValueSingle());

               
if (parameter.Name == "AmbientLightColor")
                    myEffect.Parameters[
"AmbientColor"].SetValue(parameter.GetValueVector3());

               
if (parameter.Name == "DiffuseColor")
                    myEffect.Parameters[
"DiffuseColor"].SetValue(parameter.GetValueVector3());

               
if (parameter.Name == "SpecularColor")
                   
// HLSL側にグローバル変数が存在するかチェックし、OKの場合セットする(HLSL側にセマンティクス必須)
                   
if (myEffect.Parameters.GetParameterBySemantic("SpecularColor") != null)
                        myEffect.Parameters[
"SpecularColor"].SetValue(parameter.GetValueVector3());

               
if (parameter.Name == "SpecularPower")
                   
// HLSL側にグローバル変数が存在するかチェックし、OKの場合セットする(HLSL側にセマンティクス必須)
                   
if (myEffect.Parameters.GetParameterBySemantic("SpecularPower") != null)
                        myEffect.Parameters[
"SpecularPower"].SetValue(parameter.GetValueSingle());

               
if (parameter.Name == "World")
                    myEffect.Parameters[
"Model"].SetValue(parameter.GetValueMatrix());
               
if (parameter.Name == "View")
                    myEffect.Parameters[
"View"].SetValue(parameter.GetValueMatrix());
               
if (parameter.Name == "Projection")
                    myEffect.Parameters[
"Projection"].SetValue(parameter.GetValueMatrix());

               
if (parameter.Name == "lightpos0")
                    myEffect.Parameters[
"lightpos0"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol0")
                    myEffect.Parameters[
"lightcol0"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos1")
                    myEffect.Parameters[
"lightpos1"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol1")
                    myEffect.Parameters[
"lightcol1"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos2")
                    myEffect.Parameters[
"lightpos2"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol2")
                    myEffect.Parameters[
"lightcol2"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos3")
                    myEffect.Parameters[
"lightpos3"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol3")
                    myEffect.Parameters[
"lightcol3"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos4")
                    myEffect.Parameters[
"lightpos4"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol4")
                    myEffect.Parameters[
"lightcol4"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos5")
                    myEffect.Parameters[
"lightpos5"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol5")
                    myEffect.Parameters[
"lightcol5"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos6")
                    myEffect.Parameters[
"lightpos6"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol6")
                    myEffect.Parameters[
"lightcol6"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos7")
                    myEffect.Parameters[
"lightpos7"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol7")
                    myEffect.Parameters[
"lightcol7"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos8")
                    myEffect.Parameters[
"lightpos8"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol8")
                    myEffect.Parameters[
"lightcol8"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightpos9")
                    myEffect.Parameters[
"lightpos9"].SetValue(parameter.GetValueVector4());
               
if (parameter.Name == "lightcol9")
                    myEffect.Parameters[
"lightcol9"].SetValue(parameter.GetValueVector4());
            }
           
// エフェクトを差し替える
           
part.Effect = myEffect;
        }
    }
}

 

 

◎補足事項

・自作エフェクトファイルも使用可能(但しエフェクトパラメータを増やす場合はコードを追加すること)

・HLSL側に存在しないエフェクトパラメータをSetValue()するとエラーになるので、これを回避するためHLSL側にセマンティクス必須とした
 →例:Phong.fxの一部を以下のように改修すること

// セマンティクス追加
float3 SpecularColor : SpecularColor
<
string SasUiControl = "ColorPicker";
string SasUiLabel = "Specular";
> = {1.0f, 1.0f, 1.0f};

// セマンティクス追加
float SpecularPower : SpecularPower
<
string SasUiControl = "Slider";
string SasUiLabel = "Specular Power";
float SasUiMin = 1;
float SasUiMax = 200;
> = 20.0f;
 

Alphaはオリジナルのエフェクトファイルには存在しない
 →必要に応じて追加すること

 

inserted by FC2 system