Microsoft Visual C++ 2010 Express
 Microsoft DirectX SDK (June 2010)
 Direct3D 11.0
 COLLADA 1.4.1
 XMLLite

■Direct3D 11.0 自作 COLLADA ローダー Top Next
関連ページ:なし


今回は、既存の FBX ローダーで使用している FBX SDK のバージョンアップに伴い、せっかくなのでローダーを作り直します。 で基本方針から見直しまして、 SDK がバージョンアップするたびに対応するなど面倒くさくてやってられないので、SDK の類は使用しないことにします。 そのためローダーを自作することにしたわけですが、SDKを使用せずに、楽な方法で実装する方法を検討したところ、 独自フォーマットの FBX よりかは、一般的に使用されているXMLフォーマットを採用しているCOLLADAのほうが楽にできるはずだと判断し COLLADA のローダーを自作することにしました。


まず COLLADA ローダーの実装方法ですが、実は XMLLiteというXML パーサーがあって、これを使用すれば割と簡単にXML文書のデータアクセスが可能となります。 しかし XMLLite は DOM ではなくSAX を採用しているため、文書の構造を自由にたどれません。したがってその辺を実装する必要があります。
次にXML文書の解析ですが、この辺はぶっちゃけ未完成です(笑)。最低限必要な機能しか実装してません。不足している機能についてはCOLLADA ― Digital Asset Schema リリース1.4.1を参照して自分で実装してください。

ちなみにエクスポーターには Autodesk 3ds Max を使用しました。LightWave3D は 11 にバージョンアップしたようですが、使い方が悪いからか相変わらず法線ベクトルが出力できません。 Blender でもやってみましたがこちらも使い方が悪いのか( というより使い方がよくわからん )テクスチャーのファイル名が出力されませんでした。 趣味のために Autodesk 3ds Max を購入するのは割に合わないし、この辺の問題を考慮すると FBX 使った方がよくなってくるんだよな。


次にシェーダーリソースビューの作成方法ですが、とりあえずこれまでどおり Direct3D エクステンションを使用することにしました。 DirectXTex texture processing libraryというオープンソースのライブラリがあるのでそれを使用する手もありますが 外部ライブラリはあまり使用したくないので、今回は見送ることにして Direct3D 11.1 がリリースされた時にでも検討しようかと思います。
なお DirectX SDK のサンプルにも DDSファイル を読み込む関数のサンプルがありますが、こちらは内部的に DXUT を使用しているので使う意味がありません。

ではソースを見ていきます。


MeshLoader.h メッシュローダーの抽象クラスのヘッダファイル。
ColladaLoader.h COLLADA用ローダークラスのヘッダファイル。
ColladaLoader.cpp COLLADA用ローダークラスのソースファイル。
D3DMeshData.h Direct3D描画時に使用するリソースを保持するクラスのヘッダファイル。
D3DMeshData.cpp Direct3D描画時に使用するリソースを保持するクラスのソースファイル。
D3DMeshDataCreater.h ローダーから作成したメッシューデータをもとにDirect3D用のリソースを作成するクラスのヘッダファイル。
D3DMeshDataCreater.cpp ローダーから作成したメッシューデータをもとにDirect3D用のリソースを作成するクラスのソースファイル。
Exception.h 例外処理用のクラス。
Plane_2013.xml おまけサンプルのxmlファイル。

---MeshLoader.h---  ↑


#ifndef MESH_LOADER_H
#define MESH_LOADER_H

#include <tchar.h>
#include <vector>
#include <string>

class IMeshLoader
{
public:
   // 頂点エレメントの格納方法の種類の一覧
   typedef enum _GEOMETRY_TYPE
   {
      UNKNOWN   = 0,
      POLYGONS  = 1,
      POLYLIST  = 2,
      TRIANGLES = 3,
      TRIFANS   = 4,
      TRISTRIPS = 5,
   }GEOMETRY_TYPE;

   // COLLADAから取得したデータを格納する構造体
   typedef struct _DATAARRAY
   {
      // 頂点エレメントごとにデータを格納するための構造体
      typedef struct _VERTEX_ELEMENT
      {
         // 頂点エレメントの種類
         std::wstring Semantic;
         // 頂点エレメントで必要となるデータ数。例えば頂点座標の場合 x, y, z で 3 。
         UINT Stride;
         // 実データ。Stride数分使用する。
         typedef struct _VECTOR
         {
            float vector[3];
         }VECTOR;
         // 1つの頂点エレメント内のデータ配列
         std::vector<VECTOR> Vector;
         // インデックスデータを示す
         std::vector<UINT> Index;
      }VERTEX_ELEMENT;

      // ジオメトリ名
      std::wstring InstanceGeometryName;
      // 頂点エレメントの格納方法の種類
      GEOMETRY_TYPE GeometryType;
      // 1ポリゴンの頂点数を示す配列。
      std::vector<UINT> VCount;
      // 頂点エレメントごとのデータ配列
      std::vector<VERTEX_ELEMENT> VertexElement;
      // マテリアル名
      std::wstring InstanceMaterialName;
      // テクスチャーへのパス。とりあえず1つのみとする。
      std::wstring ImageFileName;
      // サンプラーステートはとりあえず考慮しない
   }DATAARRAY;

public:
   std::vector<DATAARRAY> m_DataArray;

public:
   inline IMeshLoader(){};
   inline virtual ~IMeshLoader(){ Invalidate(); };
   inline virtual void Invalidate(){ m_DataArray.clear(); };
   // このメンバ関数は FBX, COLLADA ローダーを実装するクラス側で実体化する
   virtual void LoadMesh( const TCHAR* pFileName ) = 0;
};

#endif

このクラスは FBX, COLLADA のメッシュデータのローダーを実装するための抽象クラスです。 FBX と COLLADA の切り替える必要が生じた場合、ソースの修正箇所を少なくするために使用します。

---ColladaLoader.h---  ↑

#ifndef COLLADA_LOADER_H
#define COLLADA_LOADER_H

// 非標準の拡張機能が使用されています: enum 'enum' が限定名で使用されます。このワーニングを抑制する。
#pragma warning(disable: 4482)

// XMLLiteを使うため
#include <xmllite.h>
#pragma comment(lib, "xmllite.lib")

#include "MeshLoader.h"

class CColladaLoader : public IMeshLoader
{
private:
   // IXmlReaderの内部文字コードがWCHARっぽいので合わせる
   typedef struct _XMLPATHARRAY
   {
      LPCWSTR pTagName;            // タグ名
      LPCWSTR pAttribute;          // 属性名
      LPCWSTR pAttributeValue;     // 属性値
   }XMLPATHARRAY;

   IXmlReader* m_pReader;
   IStream* m_pStream;

   // xml を読み込む開始位置を先頭に移動する
   void SetSeekTop() const;

   // 属性値を取得する
   const bool GetAttributeValue( const LPCWSTR pAttribute, std::wstring* pValue ) const;
   // テキストを取得する
   const bool GetText( std::wstring* pValue ) const;

   // 現在の階層のタグ名および属性値が検索条件と一致するかを判定する
   const bool FindTagOrAttribute( const XMLPATHARRAY* pXmlPath, const LPCWSTR pwszLocalName )const;

   // ノード検索
   const std::vector<std::wstring> GetElementsByNodeName( const XMLPATHARRAY* pXmlPath, UINT XmlPathArrayCount ) const;

   // target や url 属性値の頭の#を取り除く
   void GetID( std::wstring* Target ) const;

   // 文字列をばらす
   void Split( const std::vector<std::wstring>* pInStr, const wchar_t Delimiter, std::vector<std::wstring>* pOutStr ) const;

   // inputタグの属性値を取得
   const bool GetInputData( const std::vector<std::wstring>* pSemanticArray
                          , const std::vector<std::wstring>* pSourceArray
                          , const std::vector<std::wstring>* pOffsetArray
                          , const LPCWSTR pSearchSemantic
                          , std::wstring* pSource
                          , UINT* pOffset ) const;

   // ジオメトリの種類を取得
   const int CheckGeometryType( const std::wstring* pInstanceGeometry ) const;

   // Polylistデータを取得
   void GetPolylist( const std::wstring* pInstanceGeometry );

public:
   CColladaLoader();
   virtual ~CColladaLoader();
   void Invalidate();
   void LoadMesh( const TCHAR* pFileName );
};

#endif

---ColladaLoader.cpp---  ↑

#include <tchar.h>
#include <vector>
#include <string>
#include <shlwapi.h>
#include "Exception.h"
#include "ColladaLoader.h"

// ****************************************************************************************************************
// COLLADA ― Digital Asset Schema リリース1.4.1
// ****************************************************************************************************************

#pragma comment( lib, "Shlwapi.lib" )

CColladaLoader::CColladaLoader()
{
   m_pReader = nullptr;
   m_pStream = nullptr;
}

void CColladaLoader::Invalidate()
{
   if( m_pReader )
   {
      m_pReader->Release();
      m_pReader = nullptr;
   }
   if( m_pStream )
   {
      m_pStream->Release();
      m_pStream = nullptr;
   }
   IMeshLoader::Invalidate();
}

CColladaLoader::~CColladaLoader()
{
   Invalidate();
}

// xml を読み込む開始位置を先頭に移動する
void CColladaLoader::SetSeekTop() const
{
   LARGE_INTEGER li = { 0, 0 };
   if( FAILED( m_pStream->Seek( li, tagSTREAM_SEEK::STREAM_SEEK_SET, nullptr ) ) )
      throw( CException( _T("CColladaLoader::SetSeekTop()でエラーが発生しました。"), _T("IStream::Seek()でエラーが発生しました。"), _T("") ) );

   if( FAILED( m_pReader->SetInput( m_pStream ) ) )
      throw( CException( _T("CColladaLoader::SetSeekTop()でエラーが発生しました。"), _T("IxmlReader::SetInput()でエラーが発生しました。"), _T("") ) );
}

// 属性値を取得する
const bool CColladaLoader::GetAttributeValue( const LPCWSTR pAttribute, std::wstring* pValue ) const
{
   bool Find = false;
   HRESULT hr;
   LPCWSTR pwszValue = nullptr;

   pValue->clear();

   // 属性を検索
   hr = m_pReader->MoveToAttributeByName( pAttribute, nullptr );
   switch( hr )
   {
   // 属性なし
   case S_FALSE:
      goto EXIT;
      break;
   case E_FAIL:
      throw( CException( _T("CColladaLoader::GetAttributeValue()でエラーが発生しました。"), _T("IXmlReader::MoveToAttributeByName()でエラーが発生しました。"), _T("") ) );
      break;
   }

   if( pValue != nullptr )
   {
      // 属性値を取得
      if( FAILED( m_pReader->GetValue( &pwszValue, nullptr ) ) )
         throw( CException( _T("CColladaLoader::GetAttributeValue()でエラーが発生しました。"), _T("IXmlReader::GetValue()でエラーが発生しました。"), _T("") ) );

      pValue->append( pwszValue );
   }

   Find = true;

EXIT:
   return Find;
}

// テキストを取得する
const bool CColladaLoader::GetText( std::wstring* pValue ) const
{
   bool Find = false;
   LPCWSTR pwszValue = nullptr;
   XmlNodeType nodeType;
   pValue->clear();

   // 読み込み
   while( m_pReader->Read( &nodeType ) == S_OK )
   {
      switch( nodeType )
      {
      case XmlNodeType::XmlNodeType_Text:
         // 値を取得する
         if( FAILED( m_pReader->GetValue( &pwszValue, nullptr ) ) )
            throw( CException( _T("CColladaLoader::GetText()でエラーが発生しました。"), _T("IXmlReader::GetValue()でエラーが発生しました。"), _T("") ) );

         pValue->append( pwszValue );
         Find = true;
         goto EXIT;
         break;

      case XmlNodeType::XmlNodeType_EndElement:
         goto EXIT;
         break;
      }
   }

EXIT:
   return Find;
}

const bool CColladaLoader::FindTagOrAttribute( const XMLPATHARRAY* pXmlPath, const LPCWSTR pwszLocalName )const
{
   bool Find = false;
   std::wstring pValue;

   if( wcscmp( pXmlPath->pTagName, pwszLocalName ) == 0 )
   {
      // 検索条件に属性が指定されていない
      if( pXmlPath->pAttribute == nullptr )
      {
         Find = true;
         goto EXIT;
      }

      // 検索条件に属性が指定されている
      else
      {
         // 属性名で検索してみつかった
         if( GetAttributeValue( pXmlPath->pAttribute, &pValue ) == true )
         {
            // 検索条件に属性値がある
            if( pXmlPath->pAttributeValue != nullptr )
            {
               // 属性値が一致した
               if( wcscmp( pXmlPath->pAttributeValue, pValue.data() ) == 0 )
               {
                  Find = true;
                  goto EXIT;
               }
            }
            // 検索条件に属性値がない
            else
            {
               Find = true;
               goto EXIT;
            }
         }
      }
   }

EXIT:
   return Find;
}

// ノード検索
const std::vector<std::wstring> CColladaLoader::GetElementsByNodeName( const XMLPATHARRAY* pXmlPath, UINT XmlPathArrayCount ) const
{
   std::vector<std::wstring> RetValue;

   XmlNodeType nodeType;
   LPCWSTR pwszLocalName = nullptr;
   std::wstring pValue;
   UINT Depth = 0;
   int Level = -1;

   // シークを先頭に移動
   SetSeekTop();

   // 読み込み
   while( m_pReader->Read( &nodeType ) == S_OK )
   {
      switch( nodeType )
      {
      case XmlNodeType::XmlNodeType_Element:
         // 要素名を取得
         if( FAILED( m_pReader->GetLocalName( &pwszLocalName, nullptr ) ) )
            throw( CException( _T("CColladaLoader::getElementsByNodeName()でエラーが発生しました。"), _T("IXmlReader::GetLocalName()でエラーが発生しました。"), _T("") ) );

         // 階層を取得
         if( FAILED( m_pReader->GetDepth( &Depth ) ) )
            throw( CException( _T("CColladaLoader::getElementsByNodeName()でエラーが発生しました。"), _T("IXmlReader::GetDepth()でエラーが発生しました。"), _T("") ) );

         // 階層がXMLPATHARRAYの要素数を越えている場合は、確実に対象外なのでスキップする
         if( Depth >= XmlPathArrayCount )
            continue;

         // 検索してみつかった場合
         if( FindTagOrAttribute( &pXmlPath[Depth], pwszLocalName ) == true )
         {
            // レベルが上のほうにあるときはもどす
            if( Level + 1 >= static_cast<int>( Depth ) )
            {
               Level = static_cast<int>( Depth );  // レベルアップ

               // 検索条件が最後の階層のとき
               if( Depth + 1 == XmlPathArrayCount )
               {
                  // テキストを出力する場合 
                  if( pXmlPath[Depth].pAttribute == nullptr ||                                              // 検索条件に属性名が指定されていないとき
                      pXmlPath[Depth].pAttribute != nullptr && pXmlPath[Depth].pAttributeValue != nullptr ) // 検索条件に属性名と属性値が指定されているとき
                  {
                     // テキストを取得する
                     if( GetText( &pValue ) == true )
                     {
                        // 値を出力する
                        RetValue.push_back( pValue.data() );
                     }
                  }
                  // 属性値を出力する場合
                  else if( pXmlPath[Depth].pAttribute != nullptr && pXmlPath[Depth].pAttributeValue == nullptr )
                  {
                     if( GetAttributeValue( pXmlPath->pAttribute, &pValue ) == true )
                     {
                        RetValue.push_back( pValue.data() );
                     }
                  }
                  else
                     throw( CException( _T("CColladaLoader::getElementsByNodeName()でエラーが発生しました。"), _T("pXmlPathの検索条件が不正です。"), _T("") ) );
               }
            }
         }
         // 検索対象の要素名が見つからない
         else
         {
            if( Level >= static_cast<int>( Depth ) )
               Level =  static_cast<int>( Depth ) - 1;   // レベルダウン
         }
         break;
      }
   }

   return RetValue;
}

// target や url 属性値の頭の#を取り除く
void CColladaLoader::GetID( std::wstring* Target ) const
{
   if( Target->length() > 0 )
   {
      if( Target->find( '#', 0 ) == 0 )
         Target->erase( 0, 1 );
   }
}

//文字列を分割する
void CColladaLoader::Split( const std::vector<std::wstring>* pInStr, const wchar_t Delimiter, std::vector<std::wstring>* pOutStr ) const
{
   UINT index1 = 0;
   UINT index2 = 0;
   
   for( UINT i=0; i<pInStr->size(); i++ )
   {
      index1 = index2 = 0;
      while( index2 != std::wstring::npos )
      {
         index2 = (*pInStr)[i].find( Delimiter, index1 );

         if( index2 != std::wstring::npos )
         {
            std::wstring str = (*pInStr)[i].substr( index1, index2 - index1 ).data();
            if( str.length() > 0 )
               pOutStr->push_back( str.data() );
         }
         else
         {
            std::wstring str = (*pInStr)[i].substr( index1 ).data();
            if( str.length() > 0 )
               pOutStr->push_back( str.data() );
         }

         index1 = index2 + 1;
      }
   }
}

const int CColladaLoader::CheckGeometryType( const std::wstring* pInstanceGeometry ) const
{
   std::wstring InstanceGeometryName = *pInstanceGeometry;
   // 頭の#を取り除く
   GetID( &InstanceGeometryName );

   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_geometries", nullptr, nullptr },
                                       { L"geometry", L"id", InstanceGeometryName.data() },
                                       { L"mesh", nullptr, nullptr },
                                       { L"polylist", L"count", nullptr },
                                    };
      std::vector<std::wstring> check = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
      if( check.size() == 1 )
         return GEOMETRY_TYPE::POLYLIST;
   }

   return GEOMETRY_TYPE::UNKNOWN;
}

// inputタグの属性値を取得
const bool CColladaLoader::GetInputData( const std::vector<std::wstring>* pSemanticArray
                                       , const std::vector<std::wstring>* pSourceArray
                                       , const std::vector<std::wstring>* pOffsetArray
                                       , const LPCWSTR pSearchSemantic
                                       , std::wstring* pSource
                                       , UINT* pOffset ) const
{
   bool find = false;

   UINT index = 0;
   for( UINT i=0; i<pSemanticArray->size(); i++ )
   {
      if( wcscmp( (*pSemanticArray)[i].data(), pSearchSemantic ) == 0 )
      {
         pSource->clear();
         pSource->append( (*pSourceArray)[index].data() );
         GetID( pSource );

         *pOffset = _wtoi( (*pOffsetArray)[index].data() );

         find = true;
         break;
      }

      index++;
   }

   return find;
}

// Polylist
void CColladaLoader::GetPolylist( const std::wstring* pInstanceGeometry )
{
   DATAARRAY polylist;

   polylist.InstanceGeometryName = *pInstanceGeometry;
   // 頭の#を取り除く
   GetID( &polylist.InstanceGeometryName );

   // ***************************************************************************************
   // ジオメトリ種別を設定
   // ***************************************************************************************
   polylist.GeometryType = GEOMETRY_TYPE::POLYLIST;

   // ***************************************************************************************
   // semanticを取得
   // ***************************************************************************************
   std::vector<std::wstring> inputSemantic;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_geometries", nullptr, nullptr },
                                       { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                       { L"mesh", nullptr, nullptr },
                                       { L"polylist", nullptr, nullptr },
                                       { L"input", L"semantic", nullptr },
                                    };
      inputSemantic = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   if( inputSemantic.size() == 0 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("semantic属性が見つかりません。"), _T("") ) );

   // ***************************************************************************************
   // sourceを取得
   // ***************************************************************************************
   std::vector<std::wstring> inputSource;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_geometries", nullptr, nullptr },
                                       { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                       { L"mesh", nullptr, nullptr },
                                       { L"polylist", nullptr, nullptr },
                                       { L"input", L"source", nullptr },
                                    };
      inputSource = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   if( inputSource.size() == 0 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("source属性が見つかりません。"), _T("") ) );

   // 頭の#を取り除く
   for( UINT i=0; i<inputSource.size(); i++ )
      GetID( &inputSource[i] );

   // ***************************************************************************************
   // offset を取得
   // ***************************************************************************************
   std::vector<std::wstring> inputOffset;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_geometries", nullptr, nullptr },
                                       { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                       { L"mesh", nullptr, nullptr },
                                       { L"polylist", nullptr, nullptr },
                                       { L"input", L"offset", nullptr },
                                    };
      inputOffset = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   if( inputSemantic.size() == 0 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("offset属性が見つかりません。"), _T("") ) );

   if( inputSemantic.size() != inputSource.size() )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("semanticとsourceの要素数が一致しません。"), _T("") ) );

   if( inputSemantic.size() != inputOffset.size() )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("semanticとoffsetの要素数が一致しません。"), _T("") ) );

   // ***************************************************************************************
   // vcountデータを daeファイル から取得
   // ***************************************************************************************
   std::vector<std::wstring> vcount;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_geometries", nullptr, nullptr },
                                       { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                       { L"mesh", nullptr, nullptr },
                                       { L"polylist", nullptr, nullptr },
                                       { L"vcount", nullptr, nullptr },
                                    };
      vcount = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   if( vcount.size() != 1 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("vcountの要素数が不正です。"), _T("") ) );

   // ' ' でばらす
   {
      std::vector<std::wstring> temp1, temp2;
      Split( &vcount, ' ', &temp1 );
      Split( &temp1, '\n', &temp2 );
      for( UINT i=0; i<temp2.size(); i++ )
         polylist.VCount.push_back( _wtoi( temp2[i].data() ) );
   }

   // ***************************************************************************************
   // pデータを daeファイル から取得
   // ***************************************************************************************
   std::vector<std::wstring> p;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_geometries", nullptr, nullptr },
                                       { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                       { L"mesh", nullptr, nullptr },
                                       { L"polylist", nullptr, nullptr },
                                       { L"p", nullptr, nullptr },
                                    };
      p = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   if( p.size() != 1 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("pの要素数が不正です。"), _T("") ) );

   // ' 'と'\n' でばらす
   std::vector<UINT> uIndex;
   {
      std::vector<std::wstring> temp1, temp2;
      Split( &p, ' ', &temp1 );
      Split( &temp1, '\n', &temp2 );
      for( UINT i=0; i<temp2.size(); i++ )
         uIndex.push_back( _wtoi( temp2[i].data() ) );
   }
   
   UINT SemanticSize = inputSemantic.size();
   
   // ***************************************************************************************
   // 頂点エレメントを取得
   // ***************************************************************************************
   for( UINT i=0; i<SemanticSize; i++ )
   {
      std::wstring source;
      UINT offset;
      std::vector<std::wstring> float_array, stride;
      DATAARRAY::VERTEX_ELEMENT element;

      // source、offsetを取得
      if( GetInputData( &inputSemantic, &inputSource, &inputOffset, inputSemantic[i].data(), &source, &offset ) == false )
         throw( CException( _T("CColladaLoader::GetInputData()でエラーが発生しました。"), _T("要素が見つかりません。"), _T("") ) );

      // ***************************************************************************************
      // sourceの値を取得
      // ***************************************************************************************

      // "VERTEX"のときのsourceの内容を取得する
      if( wcscmp( inputSemantic[i].data(), L"VERTEX" ) == 0 )
      {
         std::vector<std::wstring> sourceArray;
         {
            source = inputSource[i];
            GetID( &source );

            XMLPATHARRAY XmlPathArray[] = { 
                                             { L"COLLADA", nullptr, nullptr },
                                             { L"library_geometries", nullptr, nullptr },
                                             { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                             { L"mesh", nullptr, nullptr },
                                             { L"vertices", L"id", source.data() },
                                             { L"input", L"source", nullptr },    // ここはsemantic="POSITION"のみだという前提
                                          };
            sourceArray = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
         }
         if( sourceArray.size() != 1 )
            throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("vertices要素のinput要素の数が不正です。"), _T("") ) );

         source = sourceArray[0];
         GetID( &source );
      }
      // "VERTEX"以外のときのsourceの内容を取得する
      else
      {
         source = inputSource[i];
         GetID( &source );
      }

      // ***************************************************************************************
      // データ配列を取得
      // ***************************************************************************************
      {
         XMLPATHARRAY XmlPathArray[] = { 
                                          { L"COLLADA", nullptr, nullptr },
                                          { L"library_geometries", nullptr, nullptr },
                                          { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                          { L"mesh", nullptr, nullptr },
                                          { L"source", L"id", source.data() },
                                          { L"float_array", nullptr, nullptr },
                                       };
         float_array = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
      }
      if( float_array.size() != 1 )
         throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("float_array要素の数が不正です。"), _T("") ) );

      // ' 'と'\n' でばらす
      std::vector<float> VectorArray;
      {
         std::vector<std::wstring> temp1, temp2;
         Split( &float_array, ' ', &temp1 );
         Split( &temp1, '\n', &temp2 );
         for( UINT j=0; j<temp2.size(); j++ )
            VectorArray.push_back( static_cast<float>( _wtof( temp2[j].data() ) ) );
      }

      element.Semantic = inputSemantic[i];

      size_t veccount = VectorArray.size();
      DATAARRAY::VERTEX_ELEMENT::VECTOR VectorElement;

      // ***************************************************************************************
      // stride取得
      // ***************************************************************************************
      {
         XMLPATHARRAY XmlPathArray[] = { 
                                          { L"COLLADA", nullptr, nullptr },
                                          { L"library_geometries", nullptr, nullptr },
                                          { L"geometry", L"id", polylist.InstanceGeometryName.data() },
                                          { L"mesh", nullptr, nullptr },
                                          { L"source", L"id", source.data() },
                                          { L"technique_common", nullptr, nullptr },
                                          { L"accessor", L"stride", nullptr },
                                       };
         stride = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
      }
      if( stride.size() != 1 )
         throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("stride要素の数が不正です。"), _T("") ) );

      element.Stride = _wtoi( stride[0].data() );

      for( UINT i=0; i<veccount; i+=element.Stride )
      {
         for( UINT j=0; j<element.Stride; j++ )
            VectorElement.vector[j] = VectorArray[i+j];

         element.Vector.push_back( VectorElement );
      }
      
      // ***************************************************************************************
      // インデックスデータをセット
      // ***************************************************************************************
      for( UINT j=offset; j<uIndex.size(); j+=SemanticSize )
      {
         element.Index.push_back( uIndex[j] );
      }

      polylist.VertexElement.push_back( element );
   }

   // ***************************************************************************************
   // マテリアルインスタンス名を取得
   // ***************************************************************************************
   std::vector<std::wstring> instance_material;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_visual_scenes", nullptr, nullptr },
                                       { L"visual_scene", nullptr, nullptr },
                                       { L"node", nullptr, nullptr },
                                       { L"instance_geometry", L"url", pInstanceGeometry->data() },
                                       { L"bind_material", nullptr, nullptr },
                                       { L"technique_common", nullptr, nullptr },
                                       { L"instance_material", L"target", nullptr },
                                    };
      instance_material = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   // とりあえず1個のみとする
   if( instance_material.size() != 1 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("instance_material要素の数が不正です。"), _T("") ) );

   polylist.InstanceMaterialName = instance_material[0];

   // 頭の#を取り除く
   GetID( &instance_material[0] );

   // ***************************************************************************************
   // インスタンスエフェクト名を取得
   // ***************************************************************************************
   std::vector<std::wstring> instance_effect;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_materials", nullptr, nullptr },
                                       { L"material", L"id", instance_material[0].data() },
                                       { L"instance_effect", L"url", nullptr },
                                    };
      instance_effect = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   // とりあえず1個のみとする
   if( instance_effect.size() != 1 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("instance_effect要素の数が不正です。"), _T("") ) );

   // 頭の#を取り除く
   GetID( &instance_effect[0] );

   // ***************************************************************************************
   // ライブラリエフェクトからテクスチャーIDを取得
   // ***************************************************************************************
   std::vector<std::wstring> library_effects_texture;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_effects", nullptr, nullptr },
                                       { L"effect", L"id", instance_effect[0].data() },
                                       { L"profile_COMMON", nullptr, nullptr },
                                       { L"technique", nullptr, nullptr },
                                       { L"phong", nullptr, nullptr },       // とりあえず phong 固定
                                       { L"diffuse", nullptr, nullptr },     // diffuse のテクスチャーを対象とする
                                       { L"texture", L"texture", nullptr },
                                    };
      library_effects_texture = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   // とりあえず1個のみとする
   if( library_effects_texture.size() != 1 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("library_effectsからテクスチャーIDを取得できません"), _T("") ) );

   // ***************************************************************************************
   // ライブラリイメージ名を取得
   // ***************************************************************************************
   std::vector<std::wstring> library_images;
   {
      XMLPATHARRAY XmlPathArray[] = { 
                                       { L"COLLADA", nullptr, nullptr },
                                       { L"library_images", nullptr, nullptr },
                                       { L"image", L"id", library_effects_texture[0].data() },
                                       { L"init_from", nullptr, nullptr },
                                    };
      library_images = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
   }
   // とりあえず1個のみとする
   if( library_images.size() != 1 )
      throw( CException( _T("CColladaLoader::GetPolylist()でエラーが発生しました。"), _T("library_images要素の数が不正です。"), _T("") ) );

   // ***************************************************************************************
   // テクスチャーファイル名を格納
   // ***************************************************************************************
   polylist.ImageFileName = library_images[0];

   // データ格納
   m_DataArray.push_back( polylist );
}

void CColladaLoader::LoadMesh( const TCHAR* pFileName )
{
   const std::wstring Version = L"1.4.1";

   // メモリ開放
   Invalidate();

   if( FAILED( ::CreateXmlReader( __uuidof(IXmlReader), reinterpret_cast<void**>(&m_pReader), 0 ) ) )
      throw( CException( _T("CColladaLoader::LoadMesh()でエラーが発生しました。"), _T("xmlファイルの読み込みに失敗しました。"), _T("") ) );

   if( FAILED( ::SHCreateStreamOnFile( pFileName, STGM_READ, &m_pStream ) ) )
      throw( CException( _T("CColladaLoader::LoadMesh()でエラーが発生しました。"), _T("ファイルが見つかりません。"), _T("") ) );

   if( FAILED( m_pReader->SetInput( m_pStream ) ) )
      throw( CException( _T("CColladaLoader::LoadMesh()でエラーが発生しました。"), _T("IXmlReader::SetInput()でエラーが発生しました。"), _T("") ) );

   try
   {
      // ***************************************************************************************
      // バージョンチェック
      // ***************************************************************************************
      std::vector<std::wstring> VersionData;
      {
         XMLPATHARRAY XmlPathArray[] = { 
                                          { L"COLLADA", L"version", nullptr },
                                       };
         VersionData = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
      }

      if( VersionData.empty() == true )
         throw( CException( _T("CColladaLoader::LoadMesh()でエラーが発生しました。"), _T("COLLADAのバージョンを取得できません。"), _T("") ) );

      if( wcscmp( VersionData[0].data(), Version.data() ) != 0 )
         throw( CException( _T("CColladaLoader::LoadMesh()でエラーが発生しました。"), _T("COLLADAのバージョンが不正です。"), _T("") ) );

      // ***************************************************************************************
      // ジオメトリインスタンス名を取得
      // ***************************************************************************************
      std::vector<std::wstring> instance_geometry;
      {
         XMLPATHARRAY XmlPathArray[] = { 
                                          { L"COLLADA", nullptr, nullptr },
                                          { L"library_visual_scenes", nullptr, nullptr },
                                          { L"visual_scene", nullptr, nullptr },
                                          { L"node", nullptr, nullptr },
                                          { L"instance_geometry", L"url", nullptr },
                                       };
         instance_geometry = GetElementsByNodeName( XmlPathArray, _countof( XmlPathArray ) );
      }

      // ***************************************************************************************
      // ジオメトリ情報を取得
      // ***************************************************************************************
      for( UINT i=0; i<instance_geometry.size(); i++ )
      {
         int type = CheckGeometryType( &instance_geometry[i] );

         switch( type )
         {
         case GEOMETRY_TYPE::POLYLIST:
            GetPolylist( &instance_geometry[i] );
            break;
         default:
            throw( CException( _T("CColladaLoader::LoadMesh()でエラーが発生しました。"), _T("未対応のジオメトリタイプが指定されました。"), _T("") ) );
            break;
         }
      }
   }
   catch( CException ex )
   {
      throw( ex );
   }
}

このクラスはCOLLADAフォーマットのXMLファイルを解析して一時バッファ領域( IMeshLoader::m_DataArray )に格納します。 IMeshLoader::m_DataArray が FBX でもそのまま使用できるかは検証してません。

---D3DMeshData.h---  ↑

#ifndef D3DMESHDATA_H
#define D3DMESHDATA_H

#include "DX11User.h"

// メッシュ情報クラス
class CD3DMeshData
{
public:
   // 頂点情報構造体
   typedef struct _VERTEX
   {
      D3DVECTOR  Vertex; // 頂点データ
      D3DVECTOR  Normal; // 法線ベクトル
      D3DVECTOR  UV;     // テクセル
   }VERTEX;

   // マテリアル構造体
   typedef struct _MATERIAL
   {
      std::wstring InstanceMaterialName;  // テクスチャーの種別名

      std::wstring ImageFileName;         // 実行ファイルからテクスチャーまでの相対パス
      ID3D11ShaderResourceView* pSRView;  // シェーダーリソースビュー

      ID3D11SamplerState* pSamplerState;  // サンプラーステート
   }MATERIAL;

   typedef struct _MESH
   {
      std::wstring InstanceGeometryName; // メッシュ名

      VERTEX* pVertex;                   // 頂点エレメントの生データ
      UINT VertexCount;                  // 頂点数
      ID3D11Buffer* pVertexBuffer;       // 頂点バッファ

      UINT* pIndex;                      // インデックスの生データ
      UINT IndexCount;                   // インデックス数
      ID3D11Buffer* pIndexBuffer;        // インデックスバッファ

      MATERIAL Material;                 // マテリアル
   }MESH;

private:
   MESH* m_pMeshArray;
   UINT m_MeshCount;

public:
   CD3DMeshData();
   virtual ~CD3DMeshData();
   void Invalidate();
   
   inline UINT GetVertexBufferStrideSize()
   {
      return sizeof( CD3DMeshData::VERTEX );
   };
   inline UINT GetMeshCount()
   {
      return m_MeshCount;
   };
   inline void CreateMeshArray( UINT MeshCount )
   {
      SAFE_DELETE_ARRAY( m_pMeshArray );
      m_MeshCount = MeshCount;
      m_pMeshArray = new CD3DMeshData::MESH[m_MeshCount];
   };
   inline MESH* GetMeshArray( UINT Index )
   {
      if( Index < m_MeshCount )
         return &m_pMeshArray[Index];
      return nullptr;
   };
   void GetVertexBuffer( UINT Index, ID3D11Buffer** ppVertexBuffer, UINT* pVertexCount ) const;
   void GetIndexBuffer( UINT Index, ID3D11Buffer** ppIndexBuffer, UINT* pIndexCount ) const;
   void GetMaterial( UINT Index, ID3D11ShaderResourceView** ppSRView, ID3D11SamplerState** ppSamplerState )const; 
};

#endif

---D3DMeshData.cpp---  ↑

#include "Exception.h"
#include "D3DMeshData.h"

CD3DMeshData::CD3DMeshData()
{
   m_pMeshArray = nullptr;
   m_MeshCount = 0;
}

CD3DMeshData::~CD3DMeshData()
{
   Invalidate();
}

void CD3DMeshData::Invalidate()
{
   for( size_t i=0; i<m_MeshCount; i++ )
   {
      SAFE_DELETE_ARRAY( m_pMeshArray[i].pVertex );
      SAFE_RELEASE( m_pMeshArray[i].pVertexBuffer );

      SAFE_DELETE_ARRAY( m_pMeshArray[i].pIndex );
      SAFE_RELEASE( m_pMeshArray[i].pIndexBuffer );

      SAFE_RELEASE( m_pMeshArray[i].Material.pSRView );
      SAFE_RELEASE( m_pMeshArray[i].Material.pSamplerState );
   }
   SAFE_DELETE_ARRAY( m_pMeshArray );
   m_MeshCount = 0;
}

void CD3DMeshData::GetVertexBuffer( UINT Index, ID3D11Buffer** ppVertexBuffer, UINT* pVertexCount )const
{
   if( Index > m_MeshCount )
      throw( CException( _T("CD3DMeshData::GetVertexBuffer()でエラーが発生しました。"), _T("Indexが不正です。"), _T("") ) );

   *ppVertexBuffer = m_pMeshArray[Index].pVertexBuffer;
   *pVertexCount = m_pMeshArray[Index].VertexCount;
}

void CD3DMeshData::GetIndexBuffer( UINT Index, ID3D11Buffer** ppIndexBuffer, UINT* pIndexCount ) const
{
   if( Index > m_MeshCount )
      throw( CException( _T("CD3DMeshData::GetVertexBuffer()でエラーが発生しました。"), _T("Indexが不正です。"), _T("") ) );

   *ppIndexBuffer = m_pMeshArray[Index].pIndexBuffer;
   *pIndexCount = m_pMeshArray[Index].IndexCount;
}

void CD3DMeshData::GetMaterial( UINT Index, ID3D11ShaderResourceView** ppSRView, ID3D11SamplerState** ppSamplerState ) const
{
   if( Index > m_MeshCount )
      throw( CException( _T("CD3DMeshData::GetShaderResourceView()でエラーが発生しました。"), _T("Indexが不正です。"), _T("") ) );

   *ppSRView = m_pMeshArray[Index].Material.pSRView;
   *ppSamplerState = m_pMeshArray[Index].Material.pSamplerState;
}

Direct3D の描画に必要となる各種データが格納されているクラスです。

---D3DMeshDataCreater.h---  ↑

#ifndef COLLADA_LOADER_D3D_H
#define COLLADA_LOADER_D3D_H

#include "MeshLoader.h"

class CD3DMeshDataCreater
{
private:
   void SetVertexElement( UINT Stride, const float pInVertexElement[3], D3DVECTOR* pOutVertexElement );

   // Polylist形式の頂点エレメントデータを Direct3D 用のデータ構造にコンバートする。
   void PolylistConvertToD3D( IMeshLoader::DATAARRAY* pDataArray, CD3DMeshData::MESH* pMesh );
   // 頂点バッファとインデックスバッファを作成する
   void CreateVertexAndIndexBuffer( ID3D11Device* pD3DDevice, CD3DMeshData::MESH* pMesh );
   // シェーダーリソースビューとサンプラーを作成する
   void CreateMaterial( ID3D11Device* pD3DDevice, IMeshLoader::DATAARRAY* pDataArray, CD3DMeshData::MESH* pMesh );

   // メッシュローダー
   IMeshLoader* m_pMeshLoader;
   
public:
   CD3DMeshDataCreater();
   virtual ~CD3DMeshDataCreater();
   void Invalidate();
   // メッシュのロードを行い、CD3DMeshData()クラス内にDirect3Dの描画に必要となるリソースを作成する
   void LoadMesh( ID3D11Device* pD3DDevice, const TCHAR* pFileName, CD3DMeshData** ppMeshData );
};

#endif

---D3DMeshDataCreater.cpp---  ↑

#include <string>
#include "DX11User.h"
#include "Exception.h"
#include "ColladaLoader.h"
#include "D3DMeshData.h"
#include "D3DMeshDataCreater.h"

CD3DMeshDataCreater::CD3DMeshDataCreater()
{
   // ローダーをFBX用に変更するときはここを修正する
   m_pMeshLoader = new CColladaLoader();
}

void CD3DMeshDataCreater::Invalidate()
{
   SAFE_DELETE( m_pMeshLoader );
}

CD3DMeshDataCreater::~CD3DMeshDataCreater()
{
   Invalidate();
}

void CD3DMeshDataCreater::SetVertexElement( UINT Stride, const float pInVertexElement[3], D3DVECTOR* pOutVertexElement )
{
   if( Stride >= 1 )
      pOutVertexElement->x = pInVertexElement[0]; // x
   if( Stride >= 2 )
      pOutVertexElement->y = pInVertexElement[1]; // y
   if( Stride >= 3 )
      pOutVertexElement->z = pInVertexElement[2]; // z
}

void CD3DMeshDataCreater::PolylistConvertToD3D( IMeshLoader::DATAARRAY* pDataArray, CD3DMeshData::MESH* pMesh )
{
   UINT Index = 0, IndexP = 0;
   UINT VcountCnt = pDataArray->VCount.size(), VertexElementCnt = pDataArray->VertexElement.size();

   pMesh->VertexCount = 0;

   // Stride数のチェック
   for( UINT i=0; i<VertexElementCnt; i++ )
   {
      if( wcscmp( pDataArray->VertexElement[i].Semantic.data(), L"VERTEX" ) == 0 )
      {
         if( pDataArray->VertexElement[i].Stride != 3 )
            throw( CException( _T("CD3DMeshDataCreater::PolylistConvertToD3D()でエラーが発生しました。"), _T("VERTEXのStrideが不正です。"), _T("") ) );
      }
      else if( wcscmp( pDataArray->VertexElement[i].Semantic.data(), L"NORMAL" ) == 0 )
      {
         if( pDataArray->VertexElement[i].Stride != 3 )
            throw( CException( _T("CD3DMeshDataCreater::PolylistConvertToD3D()でエラーが発生しました。"), _T("NORMALのStrideが不正です。"), _T("") ) );
      }
      else if( wcscmp( pDataArray->VertexElement[i].Semantic.data(), L"TEXCOORD" ) == 0 )
      {
         if( pDataArray->VertexElement[i].Stride != 2 )
            throw( CException( _T("CD3DMeshDataCreater::PolylistConvertToD3D()でエラーが発生しました。"), _T("TEXCOORDのStrideが不正です。"), _T("") ) );
      }
   }

   // 総頂点数を取得
   for( UINT i=0; i<VcountCnt; i++ )
   {
      // 三角ポリゴンの場合
      if( pDataArray->VCount[i] == 3 )
         pMesh->VertexCount += 3;
      // 四角ポリゴンの場合、三角ポリゴン2個に展開する
      else if( pDataArray->VCount[i] == 4 )
         pMesh->VertexCount += 6;
      // 以外はエラー
      else
         throw( CException( _T("CD3DMeshDataCreater::PolylistConvertToD3D()でエラーが発生しました。"), _T("四角ポリゴンより大きいポリゴンが見つかりました。"), _T("") ) );
   }

   // とりあえず頂点数とインデックス数を同じにしておく
   pMesh->IndexCount = pMesh->VertexCount;

   // 頂点数の領域確保
   pMesh->pVertex = new CD3DMeshData::VERTEX[ pMesh->VertexCount ];
   pMesh->pIndex = new UINT[ pMesh->IndexCount ];

   UINT ind;

   for( UINT i=0; i<VcountCnt; i++ )
   {
      // 三角ポリゴンの場合
      if( pDataArray->VCount[i] == 3 )
      {
         for( UINT j=0; j<VertexElementCnt; j++ )
         {
            // 頂点の場合
            if( wcscmp( pDataArray->VertexElement[j].Semantic.data(), L"VERTEX" ) == 0 )
            {
               for( UINT k=0; k<3; k++ )
               {
                  ind = pDataArray->VertexElement[j].Index[IndexP + k];
                  SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + k].Vertex ) );
               }
            }

            // 法線の場合
            else if( wcscmp( pDataArray->VertexElement[j].Semantic.data(), L"NORMAL" ) == 0 )
            {
               for( UINT k=0; k<3; k++ )
               {
                  ind = pDataArray->VertexElement[j].Index[IndexP + k];
                  SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + k].Normal ) );
               }
            }

            // テクセルの場合
            else if( wcscmp( pDataArray->VertexElement[j].Semantic.data(), L"TEXCOORD" ) == 0 )
            {
               for( UINT k=0; k<3; k++ )
               {
                  ind = pDataArray->VertexElement[j].Index[IndexP + k];
                  SetVertexElement( 2, pDataArray->VertexElement[j].Vector[ind].vector, (D3DVECTOR*)&( pMesh->pVertex[Index + k].UV ) );
               }
            }
         }

         pMesh->pIndex[Index + 0] = Index + 0;
         pMesh->pIndex[Index + 1] = Index + 2;
         pMesh->pIndex[Index + 2] = Index + 1;

         // インデックスの更新
         Index += 3;
         IndexP += pDataArray->VCount[i];
      }

      // 四角ポリゴンの場合
      else if( pDataArray->VCount[i] == 4 )
      {
         for( UINT j=0; j<VertexElementCnt; j++ )
         {
            // 頂点の場合
            if( wcscmp( pDataArray->VertexElement[j].Semantic.data(), L"VERTEX" ) == 0 )
            {
               // 三角ポリゴン1つめ
               for( UINT k=0; k<3; k++ )
               {
                  ind = pDataArray->VertexElement[j].Index[IndexP + k];
                  SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + k].Vertex ) );
               }

               // 三角ポリゴン2つめ
               ind = pDataArray->VertexElement[j].Index[IndexP + 2];
               SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + 3].Vertex ) );

               ind = pDataArray->VertexElement[j].Index[IndexP + 3];
               SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + 4].Vertex ) );

               ind = pDataArray->VertexElement[j].Index[IndexP + 0];
               SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + 5].Vertex ) );
            }

            // 法線の場合
            else if( wcscmp( pDataArray->VertexElement[j].Semantic.data(), L"NORMAL" ) == 0 )
            {
               // 三角ポリゴン1つめ
               for( UINT k=0; k<3; k++ )
               {
                  ind = pDataArray->VertexElement[j].Index[IndexP + k];
                  SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + k].Normal ) );
               }

               // 三角ポリゴン2つめ
               ind = pDataArray->VertexElement[j].Index[IndexP + 2];
               SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + 3].Normal ) );

               ind = pDataArray->VertexElement[j].Index[IndexP + 3];
               SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + 4].Normal ) );

               ind = pDataArray->VertexElement[j].Index[IndexP + 0];
               SetVertexElement( 3, pDataArray->VertexElement[j].Vector[ind].vector, &( pMesh->pVertex[Index + 5].Normal ) );
            }

            // テクセルの場合
            else if( wcscmp( pDataArray->VertexElement[j].Semantic.data(), L"TEXCOORD" ) == 0 )
            {
               // 三角ポリゴン1つめ
               for( UINT k=0; k<3; k++ )
               {
                  ind = pDataArray->VertexElement[j].Index[IndexP + k];
                  SetVertexElement( 2, pDataArray->VertexElement[j].Vector[ind].vector, (D3DVECTOR*)&( pMesh->pVertex[Index + k].UV ) );
               }

               // 三角ポリゴン2つめ
               ind = pDataArray->VertexElement[j].Index[IndexP + 2];
               SetVertexElement( 2, pDataArray->VertexElement[j].Vector[ind].vector, (D3DVECTOR*)&( pMesh->pVertex[Index + 3].UV ) );

               ind = pDataArray->VertexElement[j].Index[IndexP + 3];
               SetVertexElement( 2, pDataArray->VertexElement[j].Vector[ind].vector, (D3DVECTOR*)&( pMesh->pVertex[Index + 4].UV ) );

               ind = pDataArray->VertexElement[j].Index[IndexP + 0];
               SetVertexElement( 2, pDataArray->VertexElement[j].Vector[ind].vector, (D3DVECTOR*)&( pMesh->pVertex[Index + 5].UV ) );
            }
         }

         pMesh->pIndex[Index + 0] = Index + 0;
         pMesh->pIndex[Index + 1] = Index + 2;
         pMesh->pIndex[Index + 2] = Index + 1;

         pMesh->pIndex[Index + 3] = Index + 3;
         pMesh->pIndex[Index + 4] = Index + 5;
         pMesh->pIndex[Index + 5] = Index + 4;

         // インデックスの更新
         Index += 6; // 三角ポリゴン2個分
         IndexP += pDataArray->VCount[i];
      }
   }
   // テクセルは y 方向にたいして、逆転する
   for( UINT i=0; i<pMesh->VertexCount; i++ )
   {
      pMesh->pVertex[i].UV.y *= -1.0f;
   }

   // メッシュ名を登録
   pMesh->InstanceGeometryName = pDataArray->InstanceGeometryName;
}

void CD3DMeshDataCreater::CreateVertexAndIndexBuffer( ID3D11Device* pD3DDevice, CD3DMeshData::MESH* pMesh )
{
   // 頂点バッファを作成

   D3D11_BUFFER_DESC BufferDesc;
   D3D11_SUBRESOURCE_DATA resource;

   // 初期値を設定する
   resource.pSysMem = pMesh->pVertex;
   resource.SysMemPitch = 0;
   resource.SysMemSlicePitch = 0;

   // バッファの設定
   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( CD3DMeshData::VERTEX ) * pMesh->VertexCount; // バッファサイズ
   BufferDesc.Usage                 = D3D11_USAGE_DEFAULT;                                   // リソース使用法を特定する
   BufferDesc.BindFlags             = D3D11_BIND_VERTEX_BUFFER;                              // バッファの種類
   BufferDesc.CPUAccessFlags        = 0;                                                     // CPU アクセス
   BufferDesc.MiscFlags             = 0;                                                     // その他のフラグも設定しない

   if( FAILED( pD3DDevice->CreateBuffer( &BufferDesc, &resource, &pMesh->pVertexBuffer ) ) )
      throw( CException( _T("CD3DMeshDataCreater::CreateVertexAndIndexBuffer()でエラーが発生しました。"), _T("頂点バッファの作成に失敗しました。"), _T("") ) );

   // インデックスバッファを作成する

   // 初期値を設定する
   resource.pSysMem = pMesh->pIndex;
   resource.SysMemPitch = 0;
   resource.SysMemSlicePitch = 0;

   // バッファの設定
   ::ZeroMemory( &BufferDesc, sizeof( BufferDesc ) );
   BufferDesc.ByteWidth             = sizeof( UINT ) * pMesh->IndexCount; // バッファサイズ
   BufferDesc.Usage                 = D3D11_USAGE_DEFAULT;                // リソース使用法を特定する
   BufferDesc.BindFlags             = D3D11_BIND_INDEX_BUFFER;            // バッファの種類
   BufferDesc.CPUAccessFlags        = 0;                                  // CPU アクセス
   BufferDesc.MiscFlags             = 0;                                  // その他のフラグも設定しない

   if( FAILED( pD3DDevice->CreateBuffer( &BufferDesc, &resource, &pMesh->pIndexBuffer ) ) )
      throw( CException( _T("CD3DMeshDataCreater::CreateVertexAndIndexBuffer()でエラーが発生しました。"), _T("インデックスバッファの作成に失敗しました。"), _T("") ) );
}

void CD3DMeshDataCreater::CreateMaterial( ID3D11Device* pD3DDevice, IMeshLoader::DATAARRAY* pDataArray, CD3DMeshData::MESH* pMesh )
{
   // マテリアル情報を格納する

   pMesh->Material.InstanceMaterialName = pDataArray->InstanceMaterialName;
   pMesh->Material.ImageFileName = pDataArray->ImageFileName;

   pMesh->Material.pSamplerState = nullptr;
   pMesh->Material.pSRView = nullptr;

   // テクスチャーの読み込み
   if( pDataArray->ImageFileName.length() > 0 )
   {
      // シェーダーリソースビューを作成する
      D3DX11_IMAGE_LOAD_INFO info;
      ::ZeroMemory( &info, sizeof( D3DX11_IMAGE_LOAD_INFO ) );
      info.Width = D3DX11_DEFAULT; 
      info.Height = D3DX11_DEFAULT; 
      info.Depth = D3DX11_DEFAULT; 
      info.FirstMipLevel = D3DX11_DEFAULT;
      info.MipLevels = 0;                           // ミップマップ数。0 または D3DX11_DEFAULT を使用するとすべてのミップマップ チェーンを作成する。
      info.Usage = D3D11_USAGE_DEFAULT; 
      info.BindFlags = D3D11_BIND_SHADER_RESOURCE;
      info.CpuAccessFlags = 0;
      info.MiscFlags = 0;
      info.Format = DXGI_FORMAT_FROM_FILE;
      info.Filter = D3DX11_FILTER_POINT;            // テクスチャー読み込み時に使用するフィルター
      info.MipFilter = D3DX11_FILTER_POINT;         // ミップマップ作成時に使用するフィルター
      info.pSrcInfo = NULL;
      if( FAILED( D3DX11CreateShaderResourceViewFromFileW( pD3DDevice, pDataArray->ImageFileName.data(), &info, nullptr, &(pMesh->Material.pSRView), nullptr ) ) )
         throw( CException( _T("CD3DMeshDataCreater::CreateMaterial()でエラーが発生しました。"), _T("シェーダーリソースビューの作成に失敗しました。"), _T("") ) );

      D3D11_SAMPLER_DESC samplerDesc;
      samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;  // サンプリング時に使用するフィルタ。
      samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある u テクスチャー座標の描画方法
      samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある v テクスチャー座標
      samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;     // 0 〜 1 の範囲外にある w テクスチャー座標
      samplerDesc.MipLODBias = 0;                            // 計算されたミップマップ レベルからのバイアス
      samplerDesc.MaxAnisotropy = 1;                         // サンプリングに異方性補間を使用している場合の限界値。有効な値は 1 〜 16 。
      samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;  // 比較オプション。
      samplerDesc.BorderColor[0] = 0;                        // 境界色
      samplerDesc.BorderColor[1] = 0;
      samplerDesc.BorderColor[2] = 0;
      samplerDesc.BorderColor[3] = 0;
      samplerDesc.MinLOD = 0;                                // アクセス可能なミップマップの下限値
      samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;                // アクセス可能なミップマップの上限値
      if( FAILED( pD3DDevice->CreateSamplerState( &samplerDesc, &(pMesh->Material.pSamplerState) ) ) )
         throw( CException( _T("CD3DMeshDataCreater::CreateMaterial()でエラーが発生しました。"), _T("サンプラーステートの作成に失敗しました。"), _T("") ) );
   }
}

void CD3DMeshDataCreater::LoadMesh( ID3D11Device* pD3DDevice, const TCHAR* pFileName, CD3DMeshData** ppMeshData )
{
   try
   {
      // メッシュを読み込み一時バッファに格納する
      m_pMeshLoader->LoadMesh( pFileName );

      // CD3DMeshData() は外部でメモリ管理を行う
      *ppMeshData = new CD3DMeshData();

      (*ppMeshData)->CreateMeshArray( m_pMeshLoader->m_DataArray.size() );

      for( UINT i=0; i<m_pMeshLoader->m_DataArray.size(); i++ )
      {
         // 頂点エレメントを処理
         switch( m_pMeshLoader->m_DataArray[i].GeometryType )
         {
         case IMeshLoader::GEOMETRY_TYPE::POLYLIST:
            PolylistConvertToD3D( &m_pMeshLoader->m_DataArray[i], (*ppMeshData)->GetMeshArray(i) );
            break;
         default:
            throw( CException( _T("CD3DMeshDataCreater::LoadMesh()でエラーが発生しました。"), _T("未対応のジオメトリ種別が選択されました。"), _T("") ) );
            break;
         }

         // 頂点バッファとインデックスバッファを作成する
         CreateVertexAndIndexBuffer( pD3DDevice, (*ppMeshData)->GetMeshArray(i) );

         // マテリアルを処理
         CreateMaterial( pD3DDevice, &m_pMeshLoader->m_DataArray[i], (*ppMeshData)->GetMeshArray(i) );
      }
   }
   catch( CException ex )
   {
      throw( ex );
   }
}

このクラスは、CColladaLoaderクラスで作成したデータをもとに Direct3D で描画する際に必要となる各種バッファ、シェーダーリソースビュー、サンプラーステートを作成します。
頂点の要素数はインデックスの要素数と同じにしていますが、メモリの使用量を減らすためにも、同じ頂点はまとめるべきでしょう。

またサンプラーステートについてはとりあえず固定で作成していますが、<sampler2D>タグ内のデータを読み込むことで動的な処理が可能なはずです。 サンプルで作成したxmlファイルに<sampler2D>タグが含まれていないため、実装できませんでしたが。

とりあえず今回はこんな感じになりましたが、まだまだ改良の余地があると思います。必要に応じて今後も修正していくと思います。


web拍手 by FC2

Top Next

inserted by FC2 system