// Wavefront OBJファイルの読み込み関数 #include #include #include #include "xnacollision.h" // OBJファイル内のグループ情報 typedef struct WFOBJ_GROUP_ { char name[80]; // グループ名 char mtl[80]; // マテリアル名 int startIndex; // グループの開始インデックス int countIndex; // グループに含まれるインデックス数 } WFOBJ_GROUP; // OBJファイルの読み込み bool LoadWavefrontOBJ( FILE* fileObj, // OBJファイル XMFLOAT3* pVBufferP, // 頂点データ(座標)のポインタ int strideVBufferP, // 頂点データ(座標)の幅 XMFLOAT3* pVBufferN, // 頂点データ(法線ベクトル)のポインタ int strideVBufferN, // 頂点データ(法線ベクトル)の幅 XMFLOAT2* pVBufferT, // 頂点データ(テクスチャ座標)のポインタ int strideVBufferT, // 頂点データ(テクスチャ座標)の幅 int sizeVBuffer, // 頂点バッファに書き込めるデータ数 int &countVBuffer, // 書き込んだ頂点データ数 unsigned int* pIBuffer, // インデックス・バッファのポインタ int sizeIBuffer, // インデックス・バッファに書き込めるデータ数 int &countIBuffer, // 書き込んだインデックス数 WFOBJ_GROUP* pGroup, // グループ情報バッファ int sizeGroup, // グルーブ情報バッファのサイズ int &countGroup, // 書き込んだグループ情報の数 char* pMtlFileName, // マテリアル・ファイル名を受け取るバッファ int sizeMtlFileName) // バッファの大きさ { countVBuffer = countIBuffer = 0; countGroup = 1; pGroup[0].name[0] = pGroup[0].mtl[0] = NULL; pGroup[0].startIndex = pGroup[0].countIndex = 0; pMtlFileName[0] = NULL; static XMFLOAT3 V[0xffff+1]; static XMFLOAT2 VT[0xffff+1]; static XMFLOAT3 VN[0xffff+1]; static unsigned int IDX[0xffff+1][3]; int countV = 0, countVT = 0, countVN = 0, countIDX = 0; // OBJを読み込む while (TRUE) { // 1行単位で読み込む static char buffer[1024], op[4][256]; char* pp = fgets(buffer, sizeof(buffer), fileObj); if (pp == NULL) break; int n; // 座標 n = sscanf_s(buffer, "v %f %f %f", &V[countV].x, &V[countV].y, &V[countV].z); if (n > 0) { ++countV; if (countV > 0xffff) return false; continue; } // テクスチャ座標 n = sscanf_s(buffer, "vt %f %f", &VT[countVT].x, &VT[countVT].y); if (n > 0) { ++countVT; if (countVT > 0xffff) return false; continue; } // 法線ベクトル n = sscanf_s(buffer, "vn %f %f %f", &VN[countVN].x, &VN[countVN].y, &VN[countVN].z); if (n > 0) { ++countVN; if (countVN > 0xffff) return false; continue; } // グループ名 n = sscanf_s(buffer, "g %s", pGroup[countGroup].name, sizeof(pGroup[countGroup].name)); if (n > 0) { pGroup[countGroup].mtl[0] = NULL; pGroup[countGroup].startIndex = countIDX; pGroup[countGroup].countIndex = 0; ++countGroup; if (countGroup >= sizeGroup) return false; continue; } // マテリアル名 n = sscanf_s(buffer, "usemtl %s", pGroup[countGroup - 1].mtl, sizeof(pGroup[countGroup - 1].mtl)); if (n > 0) continue; // マテリアル・ファイル名 n = sscanf_s(buffer, "mtllib %s", pMtlFileName, sizeMtlFileName); if (n > 0) continue; // 面(三角形または四角形と仮定) n = sscanf_s(buffer, "f %s %s %s %s", op[0], sizeof(op[0]), op[1], sizeof(op[1]), op[2], sizeof(op[2]), op[3], sizeof(op[3])); if (n == 0) continue; if (n < 3) return false; int f[4][3]; for (int i=0; i 0xffff) return false; XMVECTOR vec = XMLoadFloat3(&V[f[0][0]-1]) - XMLoadFloat3(&V[f[count+1][0]-1]); if (XMVectorGetX(XMVector3Length(vec)) < 0.00001f) continue; vec = XMLoadFloat3(&V[f[0][0]-1]) - XMLoadFloat3(&V[f[count+2][0]-1]); if (XMVectorGetX(XMVector3Length(vec)) < 0.00001f) continue; vec = XMLoadFloat3(&V[f[count+1][0]-1]) - XMLoadFloat3(&V[f[count+2][0]-1]); if (XMVectorGetX(XMVector3Length(vec)) < 0.00001f) continue; for (int h=0; h<3; ++h) { IDX[countIDX][h] = f[0][h]; IDX[countIDX+1][h] = f[count+1][h]; IDX[countIDX+2][h] = f[count+2][h]; } countIDX += 3; pGroup[countGroup - 1].countIndex += 3; } }; // 近接頂点を結合する for (int i=0; i= 0.0001f) continue; for (int j=0; j= sizeVBuffer) return false; if (num >= countVBuffer) { idx[num][0] = IDX[i][0]; idx[num][1] = IDX[i][1]; idx[num][2] = IDX[i][2]; ++countVBuffer; } pIBuffer[countIBuffer] = num; ++countIBuffer; if (countIBuffer >= sizeIBuffer) return false; } // 頂点バッファを組み立てる for (int i=0; i= countV)) pP->x = pP->y = pP->z = 0.0f; else *pP = V[idx[i][0]]; pP = (XMFLOAT3*)( ((char*)pP) + strideVBufferP ); // テクスチャ座標 if ((idx[i][1] < 0) || (idx[i][1] >= countVT)) pT->x = pT->y = 0.0f; else *pT = VT[idx[i][1]]; pT = (XMFLOAT2*)( ((char*)pT) + strideVBufferT ); // 法線ベクトル if ((idx[i][2] < 0) || (idx[i][2] >= countVN)) pN->x = pN->y = pN->z = 1.0f; else *pN = VN[idx[i][2]]; pN = (XMFLOAT3*)( ((char*)pN) + strideVBufferN ); } return true; } // マテリアル・データ typedef struct WFOBJ_MTL_ { char name[80]; // マテリアル名 float Kd[3]; // ディフューズ色。値は「0」〜「1」。 float Ks[3]; // スペキュラ色。値は「0」〜「1」。 float Ka[3]; // アンビエント(環境)色。値は「0」〜「1」。 float d; // 透明度。値は「0」(透明)〜「1」(不透明)。 float Ns; // 光沢。値は、「0」〜。 float Ni; // 屈折率。値は「1」以上。「1」は屈折なし。 char map_Kd[80]; // ディフューズ・マップ。一般的なテクスチャ。 char map_Ks[80]; // スペキュラ・マップ。 char map_Ka[80]; // 環境マップ。 char map_Bump[80]; // バンプ・マップ。 char map_D[80]; // 透明マップ。 char refl[80]; // 反射マップ。 } WFOBJ_MTL; // MTLファイルの読み込み bool LoadWavefrontMTL( FILE* fileMtl, // MTLファイル WFOBJ_MTL* pMtl, // マテリアルデータを受け取る配列 int sizeMtl, // 配列サイズ int &countMtl) // 読み込んだマテリアルの数 { countMtl = -1; // MTLを読み込む static char buffer[1024]; while (TRUE) { // 1行単位で読み込む char* pp = fgets(buffer, sizeof(buffer), fileMtl); if (pp == NULL) break; int n; // マテリアル名 n = sscanf_s(buffer, "newmtl %s", pMtl[countMtl+1].name, sizeof(pMtl[countMtl+1].name)); if (n > 0) { ++countMtl; if (countMtl >= sizeMtl) return false; for (int i=0; i<3; ++i) { pMtl[countMtl].Kd[i] = 1.0f; pMtl[countMtl].Ks[i] = 1.0f; pMtl[countMtl].Ka[i] = 1.0f; } pMtl[countMtl].d = 1.0f; pMtl[countMtl].Ns = 0.0f; pMtl[countMtl].Ni = 1.0f; pMtl[countMtl].map_Kd[0]= NULL; pMtl[countMtl].map_Ks[0]= NULL; pMtl[countMtl].map_Ka[0]= NULL; pMtl[countMtl].map_Bump[0]= NULL; pMtl[countMtl].map_D[0] = NULL; pMtl[countMtl].refl[0] = NULL; continue; } if (countMtl < 0) continue; // ディフューズ色 n = sscanf_s(buffer, "Kd %f %f %f", &pMtl[countMtl].Kd[0], &pMtl[countMtl].Kd[1], &pMtl[countMtl].Kd[2]); if (n > 0) continue; // スペキュラ色 n = sscanf_s(buffer, "Ks %f %f %f", &pMtl[countMtl].Ks[0], &pMtl[countMtl].Ks[1], &pMtl[countMtl].Ks[2]); if (n > 0) continue; // アンビエント色 n = sscanf_s(buffer, "Ka %f %f %f", &pMtl[countMtl].Ka[0], &pMtl[countMtl].Ka[1], &pMtl[countMtl].Ka[2]); if (n > 0) continue; // 透明度 n = sscanf_s(buffer, "d %f", &pMtl[countMtl].d); if (n > 0) continue; // 光沢 n = sscanf_s(buffer, "Ns %f", &pMtl[countMtl].Ns); if (n > 0) continue; // 屈折率 n = sscanf_s(buffer, "Ni %f", &pMtl[countMtl].Ni); if (n > 0) continue; // ディフューズ・マップ n = sscanf_s(buffer, "map_Kd %s", pMtl[countMtl].map_Kd, sizeof(pMtl[countMtl].map_Kd)); if (n > 0) continue; // バンプ・マップ n = sscanf_s(buffer, "map_Bump %s", pMtl[countMtl].map_Bump, sizeof(pMtl[countMtl].map_Bump)); if (n > 0) continue; // スペキュラ・マップ n = sscanf_s(buffer, "map_Ks %s", pMtl[countMtl].map_Ks, sizeof(pMtl[countMtl].map_Ks)); if (n > 0) continue; // 環境マップ n = sscanf_s(buffer, "map_Ka %s", pMtl[countMtl].map_Ka, sizeof(pMtl[countMtl].map_Ka)); if (n > 0) continue; }; ++countMtl; return true; } // ヘルパークラス class CWavefrontObj { ID3D11Device* m_pD3DDevice; ID3D11DeviceContext* m_pD3DDeviceContext; ID3D11Buffer* m_pVerBuffer; // 頂点バッファのインターフェイス ID3D11Buffer* m_pIdxBuffer; // インデックス・バッファのインターフェイス ID3D11Buffer* m_pIdxAdjBuffer; // インデックス・バッファ(隣接付き)のインターフェイス WFOBJ_GROUP m_Group[256]; // グループ(最大256) int m_countGroup; // グループ数 int m_countVBuffer; int m_countIBuffer; XNA::Sphere m_spherebox; //境界球の情報 bool m_bCrack; // 割れ目 public: CWavefrontObj() : m_pD3DDevice(NULL), m_pD3DDeviceContext(NULL), m_pVerBuffer(NULL), m_pIdxBuffer(NULL), m_countGroup(0), m_countVBuffer(0), m_countIBuffer(0), m_bCrack(true) {} ~CWavefrontObj() { Cleanup(); } // データ ID3D11Buffer* GetVerBuffer() { return m_pVerBuffer; } ID3D11Buffer* GetIdxBuffer() { return m_pIdxBuffer; } WFOBJ_GROUP* GetGroup() { return m_Group; } // データ数 int GetCountVBuffer() { return m_countVBuffer; } int GetCountIBuffer() { return m_countIBuffer; } int GetCountGroup() { return m_countGroup; } // 境界球 XMFLOAT3 GetBoundingSphereCenter() { return m_spherebox.Center; } FLOAT GetBoundingSphereRadius() { return m_spherebox.Radius; } bool IsCrack() { return m_bCrack; } // OBJファイルを読み込み、頂点/インデックス・バッファを作成する // pD3DDevice : 頂点/インデックス・バッファを作成するDirect3D11デバイス // objfilename : OBJファイル名 // mtlfilename : OBJファイルのマテリアルを格納しているMTLファイル名を受け取る配列 // sizemtlfilename : mtlfilename配列のサイズ bool Load(ID3D11Device* pD3DDevice, ID3D11DeviceContext* pD3DDeviceContext, char* objfilename, char* mtlfilename, int sizemtlfilename) { Cleanup(); m_pD3DDevice = pD3DDevice; m_pD3DDeviceContext = pD3DDeviceContext; // ********************************************************** // OBJファイルの読み込み FILE* fileObj; if (fopen_s(&fileObj, objfilename, "rt") != 0) return false; struct verstr { XMFLOAT3 v; XMFLOAT3 n; XMFLOAT2 t; } *pVer = new verstr[0xffff]; unsigned int* pI = new unsigned int[0xffff]; unsigned int* pIAdj = new unsigned int[0xffff]; bool ret = LoadWavefrontOBJ(fileObj, &pVer[0].v, sizeof(verstr), &pVer[0].n, sizeof(verstr), &pVer[0].t, sizeof(verstr), 0xffff, m_countVBuffer, pI, 0xffff, m_countIBuffer, m_Group, _countof(m_Group), m_countGroup, mtlfilename, sizemtlfilename); fclose(fileObj); if ((ret == false) || (m_countVBuffer == 0) || (m_countIBuffer == 0)) { delete[] pVer; delete[] pI; delete[] pIAdj; Cleanup(); return false; } // ********************************************************** // 隣接情報の計算 int countAdj = m_countIBuffer / 3; // プリミティブ数 for (int ic = 0; ic 0); // 割れ目あり // ********************************************************** // 境界球の計算 XNA::ComputeBoundingSphereFromPoints(&m_spherebox, m_countVBuffer, &pVer[0].v, sizeof(verstr)); // ********************************************************** // 頂点バッファの定義 D3D11_BUFFER_DESC verBufferDesc; verBufferDesc.Usage = D3D11_USAGE_DEFAULT; // デフォルト使用法 verBufferDesc.ByteWidth = (sizeof(XMFLOAT3)*2 + sizeof(XMFLOAT2)) * m_countVBuffer; verBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; // 頂点バッファ verBufferDesc.CPUAccessFlags = 0; verBufferDesc.MiscFlags = 0; verBufferDesc.StructureByteStride = 0; // 頂点バッファのサブリソースの定義 D3D11_SUBRESOURCE_DATA verSubData; verSubData.pSysMem = pVer; // バッファ・データの初期値 verSubData.SysMemPitch = 0; verSubData.SysMemSlicePitch = 0; // 頂点バッファの作成 HRESULT hr = m_pD3DDevice->CreateBuffer(&verBufferDesc, &verSubData, &m_pVerBuffer); delete[] pVer; if (FAILED(hr)) { delete[] pI; delete[] pIAdj; Cleanup(); return false; } // ********************************************************** // インデックス・バッファの定義 D3D11_BUFFER_DESC idxBufferDesc; idxBufferDesc.Usage = D3D11_USAGE_DEFAULT; // デフォルト使用法 idxBufferDesc.ByteWidth = sizeof(UINT) * m_countIBuffer; idxBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; // インデックス・バッファ idxBufferDesc.CPUAccessFlags = 0; idxBufferDesc.MiscFlags = 0; idxBufferDesc.StructureByteStride = 0; // インデックス・バッファのサブリソースの定義 D3D11_SUBRESOURCE_DATA idxSubData; idxSubData.pSysMem = pI; // バッファ・データの初期値 idxSubData.SysMemPitch = 0; idxSubData.SysMemSlicePitch = 0; // インデックス・バッファの作成 hr = m_pD3DDevice->CreateBuffer(&idxBufferDesc, &idxSubData, &m_pIdxBuffer); delete[] pI; if (FAILED(hr)) { delete[] pIAdj; Cleanup(); return false; } // ********************************************************** // 隣接付きインデックス・バッファの定義 idxBufferDesc.ByteWidth *= 2; idxSubData.pSysMem = pIAdj; // インデックス・バッファの作成 hr = m_pD3DDevice->CreateBuffer(&idxBufferDesc, &idxSubData, &m_pIdxAdjBuffer); delete[] pIAdj; if (FAILED(hr)) { Cleanup(); return false; } return true; } // IAに頂点バッファとインデックス・バッファを設定 void SetIA(bool bAdj = false) { // IAに頂点バッファを設定 UINT strides[1] = { sizeof(XMFLOAT3) * 2 + sizeof(XMFLOAT2) }; UINT offsets[1] = { 0 }; m_pD3DDeviceContext->IASetVertexBuffers(0, 1, &m_pVerBuffer, strides, offsets); // IAにインデックス・バッファを設定 m_pD3DDeviceContext->IASetIndexBuffer(bAdj ? m_pIdxAdjBuffer : m_pIdxBuffer, DXGI_FORMAT_R32_UINT, 0); // IAにプリミティブの種類を設定 m_pD3DDeviceContext->IASetPrimitiveTopology(bAdj ? D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ : D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); } // 描画 // nameGroup : 描画するグループ名 // numGroup : 描画するグループ番号 // bAdj : 隣接付きデータを描画 void Draw(char* nameGroup, bool bAdj = false) { if (nameGroup == NULL) return; for (int i=0; i=m_countGroup)) return; if (bAdj) m_pD3DDeviceContext->DrawIndexed(m_Group[numGroup].countIndex * 2, m_Group[numGroup].startIndex * 2, 0); else m_pD3DDeviceContext->DrawIndexed(m_Group[numGroup].countIndex, m_Group[numGroup].startIndex, 0); } // インスタンス描画 // numInst : 描画するインスタンス数 // nameGroup : 描画するグループ名 // numGroup : 描画するグループ番号 // bAdj : 隣接付きデータを描画 void DrawInstanced(int numInst, char* nameGroup, bool bAdj = false) { if (nameGroup == NULL) return; for (int i=0; i=m_countGroup)) return; if (bAdj) m_pD3DDeviceContext->DrawIndexedInstanced(m_Group[numGroup].countIndex * 2, numInst, m_Group[numGroup].startIndex * 2, 0, 0); else m_pD3DDeviceContext->DrawIndexedInstanced(m_Group[numGroup].countIndex, numInst, m_Group[numGroup].startIndex, 0, 0); } // 終了処理or初期化 void Cleanup() { m_pD3DDevice = NULL; m_pD3DDeviceContext = NULL; if (m_pVerBuffer != NULL) { m_pVerBuffer->Release(); m_pVerBuffer = NULL; } if (m_pIdxBuffer != NULL) { m_pIdxBuffer->Release(); m_pIdxBuffer = NULL; } if (m_pIdxAdjBuffer != NULL) { m_pIdxAdjBuffer->Release(); m_pIdxAdjBuffer = NULL; } m_countGroup = 0; m_countVBuffer = 0; m_countIBuffer = 0; } }; class CWavefrontMtl { char m_MaterialFileName[80]; char m_texFileName[256][80]; ID3D11ShaderResourceView* m_Texture[256]; int m_countTexture; WFOBJ_MTL m_Material[256]; int m_countMaterial; ID3D11ShaderResourceView* m_DefaultTexture; public: CWavefrontMtl() : m_countTexture(0), m_countMaterial(0), m_DefaultTexture(NULL) { m_MaterialFileName[0] = NULL; } ~CWavefrontMtl() { Cleanup(); } // マテリアル・ファイル名 char* GetMaterialFileName() { return m_MaterialFileName; } // テクスチャのシェーダ・リソース・ビュー(読み込んでいない場合は、NULLを返す) // texName : テクスチャ・ファイル名 ID3D11ShaderResourceView* GetTexture(char* texName) { if (texName == NULL) return NULL; for (int i=0; iRelease(); m_DefaultTexture = NULL; } for (int i=0; iRelease(); m_Texture[i] = NULL; } } m_countTexture = 0; m_countMaterial = 0; } };