UVマッピングしたObjファイルを描画する
概要
最終更新日:2020/02/27
UVマッピングを行ったObjファイルの描画方法を書いた記事です。
主に次の項目に該当する方に向けて書いています。
※頂点や法線、マテリアルの読み込みが完了していることを前提に書いているので
まだの方は「頂点と法線読み込み」「マテリアル読み込み」を確認してください。
- objファイルでテクスチャマッピングする描画方法が知りたい
- ポリゴン情報にテクスチャ座標を保存させたい
- なぜ、テクスチャ座標のY軸を反転させるのかを知りたい
- マテリアルでどのテクスチャが使用されているのかを知りたい
サンプル
サンプルはここからダウンロードできます。
環境については以下の内容となっています。
開発環境
VSのバージョン |
VisualStudio 2019 |
DirectXのバージョン |
DirectX11 |
ファイル読み込み
UVマッピングを行ったObjファイルを描画する際のファイル読み込みは
以下のポイントを抑えて行います。
- テクスチャ座標をポリゴンに保存する
- 使用するテクスチャを読み込む
テクスチャ座標をポリゴンに保存する
Objファイルのテクスチャ座標(以下、UV座標)の情報は「vt」キーワードで設定されています。
vtの後ろに続く文字列がUV座標を表しており、この値をポリゴンに保存します。
vtの書式は以下の通りです。
vt U座標 V座標
vt 0.008533 0.983134
次は解析コードです。
else if (buffer[1] == 't')
{
ParseVKeywordTag(textures, &parse_point[1]);
textures[textures.size() - 1].Y = (1.0f - textures[textures.size() - 1].Y);
}
V軸を反転している理由は次の項目で説明します。
UV座標のV値を反転する理由
DirectXではObjファイルを描画する場合、UV座標のV値を反転するために
以下の計算を行っています。
DirectXのUV値 = (ObjファイルのU値, 1.0 - ObjファイルのV値)
この計算をなぜ行っているかというと、Objファイルに展開されたUV値は
原点が左下で設定されているからです。
DirectXは左上原点です。
この違いを修正するために上の計算を行っています。
使用するテクスチャを読み込む
テクスチャを読み込むためにファイル名が必要です。
このファイル名はmtlファイルの「map_Kd」キーワードに設定されています。
map_Kdの後ろに続く文字列がテクスチャのファイル名を表しています。
map_Kd テクスチャ名
map_Kd character.png
以下は解析コードです。
ファイル名を取得してパスを追加し、読み込みを行っています。
XFileやFBXでもそうですが、3Dモデルのテクスチャの読み込みは
自動で行われないので、開発側で行う必要があります。
else if (strstr(buffer, "map_Kd") == buffer)
{
Replace('\n', '\0', buffer);
std::string texture_name = &buffer[strlen("map_Kd") + 1];
m_Materials[current_material_name].TextureName = file_path + texture_name;
std::vector split;
Split('.', (char*)texture_name.c_str(), split);
if (split.size() > 1)
{
m_Materials[current_material_name].TextureKeyWord = split[0];
LoadTexture(split[0], m_Materials[current_material_name].TextureName);
}
}
以上がUVマッピングしたモデル描画の読み込み時に必要な処理でした。
描画方法
UVマッピングしたObjファイルの描画は以下のポイントを抑えて行います。
- InputLayoutにUV座標を追加
- マテリアル単位でテクスチャを設定する
- シェーダーにテクスチャカラー反映計算を追加
InputLayoutにUV座標を追加
テクスチャを描画するには、InputLayoutにUV座標を追加します。
D3D11_INPUT_ELEMENT_DESC vertex_desc[]{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXTURE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
if (FAILED(device->CreateInputLayout(
vertex_desc,
ARRAYSIZE(vertex_desc),
vertex_shader->GetData(),
vertex_shader->GetSize(),
&m_InputLayout)))
{
return false;
}
return true;
マテリアル単位でテクスチャを設定する
テクスチャはマテリアル単位で設定されているので、
マテリアル毎にテクスチャの設定を「SetTexture」を使用して行います。
for (auto index : m_Indices)
{
if (m_Textures.count(m_Materials[index.first].TextureKeyWord) > 0)
{
graphics->SetTexture(m_Textures[m_Materials[index.first].TextureKeyWord]);
}
else
{
graphics->SetTexture(nullptr);
}
}
シェーダーにテクスチャカラー反映計算を追加
テクスチャの設定が完了したら、頂点やピクセルでテクスチャカラーを
反映する処理を追加します。
まずは、頂点シェーダのコードです。
output.texture_pos = input.texture_pos;
次はピクセルシェーダのコードです。
float4 tex_color = Texture.Sample(Sampler, input.texture_pos);
これで、UVマッピングしたObjファイルの描画のために必要な処理の追加は終了です。