Skip to content

Commit

Permalink
Added a quick and dirty OBJ exporter for the Model class
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRealMJP committed Oct 9, 2023
1 parent 4141105 commit 1a6d90c
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 0 deletions.
125 changes: 125 additions & 0 deletions Shadows/SampleFramework11/Model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ void Mesh::Initialize(ID3D11Device* device, SDKMesh& sdkMesh, uint32 meshIdx, bo
indices.resize(indexSize * numIndices, 0);
memcpy(indices.data(), sdkMesh.GetRawIndicesAt(ibIdx), indexSize * numIndices);

name = sdkMeshData.Name;

if(generateTangents)
GenerateTangentFrame();

Expand Down Expand Up @@ -603,6 +605,7 @@ void Model::CreateFromSDKMeshFile(ID3D11Device* device, LPCWSTR fileName, const
material.SpecularPower = mat->Power;
material.DiffuseMapName = AnsiToWString(mat->DiffuseTexture);
material.NormalMapName = AnsiToWString(mat->NormalTexture);
material.Name = mat->Name;

// Add the normal map prefix
if (normalMapSuffix && material.DiffuseMapName.length() > 0
Expand Down Expand Up @@ -855,4 +858,126 @@ void Model::ReadFromFile(const wchar* path, ID3D11Device* device)
Win32Call(CloseHandle(fileHandle));
}

static uint32 VertexElemIndex(const std::vector<D3D11_INPUT_ELEMENT_DESC>& inputElements, const char* semanticName, uint32 semanticIndex)
{
for(uint32 elemIdx = 0; elemIdx < inputElements.size(); ++elemIdx)
{
const D3D11_INPUT_ELEMENT_DESC& elem = inputElements[elemIdx];
if(strcmp(semanticName, elem.SemanticName) == 0 && elem.SemanticIndex == semanticIndex)
return elemIdx;
}

return uint32(-1);
}

void Model::SaveAsOBJ(const wchar* path)
{
{
// Save the .mtl file
std::wstring mtlPath = GetFilePathWithoutExtension(path) + L".mtl";
std::string mtlContents;
for(const MeshMaterial& material : meshMaterials)
{
mtlContents += MakeString("newmtl %s\n", material.Name.c_str());
mtlContents += "illum 4\n";
mtlContents += MakeString("Kd %f %f %f\n", material.DiffuseAlbedo.x, material.DiffuseAlbedo.y, material.DiffuseAlbedo.z);
mtlContents += MakeString("Ka %f %f %f\n", material.AmbientAlbedo.x, material.AmbientAlbedo.y, material.AmbientAlbedo.z);
mtlContents += "Tf 1.00 1.00 1.00\n";
mtlContents += MakeString("map_Kd %ls\n", material.DiffuseMapName.c_str());
if(material.NormalMapName != L"default-normalmap.dds")
mtlContents += MakeString("bump %ls\n", material.NormalMapName.c_str());
mtlContents += "Ni 1.00\n";
mtlContents += MakeString("Ks %f %f %f\n", material.SpecularAlbedo.x, material.SpecularAlbedo.y, material.SpecularAlbedo.z);
mtlContents += MakeString("Ns %f\n", material.SpecularPower);
}

WriteStringAsFile(mtlPath.c_str(), mtlContents);
}

{
std::string objContents;
objContents += "mtllib " + WStringToAnsi(GetFileNameWithoutExtension(path).c_str()) + ".mtl\n";

// Write out the vertex data first
for(const Mesh& mesh : meshes)
{
const uint32 posIdx = VertexElemIndex(mesh.inputElements, "POSITION", 0);
Assert_(posIdx != uint32(-1));

const D3D11_INPUT_ELEMENT_DESC& posElem = mesh.inputElements[posIdx];
Assert_(posElem.Format == DXGI_FORMAT_R32G32B32_FLOAT);

for(uint32 vtxIdx = 0; vtxIdx < mesh.numVertices; ++vtxIdx)
{
const Float3* pos = (const Float3*)&mesh.vertices[vtxIdx * mesh.vertexStride + posElem.AlignedByteOffset];
objContents += MakeString("v %f %f %f\n", pos->x, pos->y, pos->z);
}
}

for(const Mesh& mesh : meshes)
{
const uint32 uvIdx = VertexElemIndex(mesh.inputElements, "TEXCOORD", 0);
Assert_(uvIdx != uint32(-1));

const D3D11_INPUT_ELEMENT_DESC& uvElem = mesh.inputElements[uvIdx];
Assert_(uvElem.Format == DXGI_FORMAT_R32G32_FLOAT);

for(uint32 vtxIdx = 0; vtxIdx < mesh.numVertices; ++vtxIdx)
{
const Float2* uv = (const Float2*)&mesh.vertices[vtxIdx * mesh.vertexStride + uvElem.AlignedByteOffset];
objContents += MakeString("vt %f %f\n", uv->x, 1.0f - uv->y);
}
}

for(const Mesh& mesh : meshes)
{
const uint32 nmlIdx = VertexElemIndex(mesh.inputElements, "NORMAL", 0);
Assert_(nmlIdx != uint32(-1));

const D3D11_INPUT_ELEMENT_DESC& nmlElem = mesh.inputElements[nmlIdx];
Assert_(nmlElem.Format == DXGI_FORMAT_R32G32B32_FLOAT);

for(uint32 vtxIdx = 0; vtxIdx < mesh.numVertices; ++vtxIdx)
{
const Float3* nml = (const Float3*)&mesh.vertices[vtxIdx * mesh.vertexStride + nmlElem.AlignedByteOffset];
objContents += MakeString("vn %f %f %f\n", nml->x, nml->y, nml->z);
}
}

// Write out submesh material + faces
uint32 indexOffset = 0;
for(const Mesh& mesh : meshes)
{
for(uint32 meshPartIdx = 0; meshPartIdx < mesh.meshParts.size(); ++meshPartIdx)
{
const MeshPart& meshPart = mesh.meshParts[meshPartIdx];
objContents += MakeString("g %s_%u\n", mesh.name.c_str(), meshPartIdx);
objContents += MakeString("usemtl %s\n", meshMaterials[meshPart.MaterialIdx].Name.c_str());

const uint16* indices16 = (const uint16*)(mesh.indices.data() + (meshPart.IndexStart * 2));
const uint32* indices32 = (const uint32*)(mesh.indices.data() + (meshPart.IndexStart * 4));

Assert_(meshPart.IndexCount % 3 == 0);
const uint32 numTris = meshPart.IndexCount / 3;
for(uint32 triIdx = 0; triIdx < numTris; ++triIdx)
{
const uint32 idx0 = mesh.indexType == Mesh::Index16Bit ? indices16[triIdx * 3 + 0] : indices32[triIdx * 3 + 0];
const uint32 idx1 = mesh.indexType == Mesh::Index16Bit ? indices16[triIdx * 3 + 1] : indices32[triIdx * 3 + 1];
const uint32 idx2 = mesh.indexType == Mesh::Index16Bit ? indices16[triIdx * 3 + 2] : indices32[triIdx * 3 + 2];

const uint32 finalIdx0 = idx0 + indexOffset + 1;
const uint32 finalIdx1 = idx1 + indexOffset + 1;
const uint32 finalIdx2 = idx2 + indexOffset + 1;

objContents += MakeString("f %u/%u/%u %u/%u/%u %u/%u/%u\n", finalIdx0, finalIdx0, finalIdx0, finalIdx1, finalIdx1, finalIdx1, finalIdx2, finalIdx2, finalIdx2);
}
}

indexOffset += mesh.numVertices;
}

WriteStringAsFile(path, objContents);
}
}

}
5 changes: 5 additions & 0 deletions Shadows/SampleFramework11/Model.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct MeshMaterial
std::wstring NormalMapName;
ID3D11ShaderResourceViewPtr DiffuseMap;
ID3D11ShaderResourceViewPtr NormalMap;
std::string Name;

MeshMaterial() : SpecularPower(1.0f), Alpha(1.0f)
{
Expand Down Expand Up @@ -123,6 +124,8 @@ class Mesh

std::vector<uint8> vertices;
std::vector<uint8> indices;

std::string name;
};

class Model
Expand All @@ -148,6 +151,8 @@ class Model
void WriteToFile(const wchar* path, ID3D11Device* device, ID3D11DeviceContext* context);
void ReadFromFile(const wchar* path, ID3D11Device* device);

void SaveAsOBJ(const wchar* path);

// Accessors
std::vector<MeshMaterial>& Materials() { return meshMaterials; };
const std::vector<MeshMaterial>& Materials() const { return meshMaterials; };
Expand Down
18 changes: 18 additions & 0 deletions Shadows/SampleFramework11/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@
namespace SampleFramework11
{

std::wstring MakeString(const wchar* format, ...)
{
wchar buffer[1024 * 8] = { 0 };
va_list args;
va_start(args, format);
vswprintf_s(buffer, ArraySize_(buffer), format, args);
return std::wstring(buffer);
}

std::string MakeString(const char* format, ...)
{
char buffer[1024 * 8] = { 0 };
va_list args;
va_start(args, format);
vsprintf_s(buffer, ArraySize_(buffer), format, args);
return std::string(buffer);
}

// Converts from cartesian to barycentric coordinates
XMFLOAT3 CartesianToBarycentric(float x, float y, const XMFLOAT2& pos1, const XMFLOAT2& pos2, const XMFLOAT2& pos3)
{
Expand Down
5 changes: 5 additions & 0 deletions Shadows/SampleFramework11/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
namespace SampleFramework11
{

#define ArraySize_(x) ((sizeof(x) / sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))

// Returns a size suitable for creating a constant buffer, by rounding up
// to the next multiple of 16
inline UINT CBSize(UINT size)
Expand Down Expand Up @@ -100,6 +102,9 @@ template<typename T> inline std::string ToAnsiString(const T& val)
return stream.str();
}

std::wstring MakeString(const wchar* format, ...);
std::string MakeString(const char* format, ...);

// Outputs a string to the debugger output
inline void DebugPrint(const std::wstring& str)
{
Expand Down
2 changes: 2 additions & 0 deletions Shadows/Shadows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ void ShadowsApp::Initialize()
models[i].CreateFromSDKMeshFile(device, path.c_str());
}

// models[0].SaveAsOBJ(L"..\\Content\\Models\\Powerplant\\Powerplant.obj");

wstring characterPath(L"..\\Content\\Models\\Soldier\\Soldier.sdkmesh");
characterMesh.CreateFromSDKMeshFile(device, characterPath.c_str());

Expand Down

0 comments on commit 1a6d90c

Please sign in to comment.