Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion Meshconvert/MeshOBJ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ HRESULT LoadFromOBJ(const wchar_t* szFilename, std::unique_ptr<Mesh>& inMesh, st
if (FAILED(hr))
return hr;

// These layouts are only used to extract data, so the offsets match WaveFrontReader::Vertex
static const D3D11_INPUT_ELEMENT_DESC s_vboLayout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
Expand All @@ -91,10 +92,33 @@ HRESULT LoadFromOBJ(const wchar_t* szFilename, std::unique_ptr<Mesh>& inMesh, st
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

// Vertex colors are read from a second stream (slot 1) alongside the Vertex data
static const D3D11_INPUT_ELEMENT_DESC s_vboLayoutVC[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

static const D3D11_INPUT_ELEMENT_DESC s_vboLayoutAltVC[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

const D3D11_INPUT_ELEMENT_DESC* layout = s_vboLayout;
size_t nDecl = std::size(s_vboLayout);

if (!wfReader.hasNormals && !wfReader.hasTexcoords)
const bool hasColors = wfReader.hasVertexColors && (wfReader.vertexColors.size() == wfReader.vertices.size());

if (hasColors)
{
layout = (wfReader.hasNormals) ? s_vboLayoutVC : s_vboLayoutAltVC;
nDecl = (wfReader.hasNormals) ? std::size(s_vboLayoutVC) : std::size(s_vboLayoutAltVC);
if (!wfReader.hasTexcoords)
--nDecl;
}
else if (!wfReader.hasNormals && !wfReader.hasTexcoords)
{
nDecl = 1;
}
Expand All @@ -117,6 +141,21 @@ HRESULT LoadFromOBJ(const wchar_t* szFilename, std::unique_ptr<Mesh>& inMesh, st
if (FAILED(hr))
return hr;

std::vector<XMFLOAT4> colors;
if (hasColors)
{
// OBJ vertex colors have no alpha, so use opaque
colors.reserve(wfReader.vertexColors.size());
for (const auto& c : wfReader.vertexColors)
{
colors.emplace_back(c.x, c.y, c.z, 1.f);
}

hr = vbr.AddStream(colors.data(), colors.size(), 1, sizeof(XMFLOAT4));
if (FAILED(hr))
return hr;
}

hr = inMesh->SetVertexData(vbr, wfReader.vertices.size());
if (FAILED(hr))
return hr;
Expand Down
53 changes: 50 additions & 3 deletions Utilities/WaveFrontReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include <cwctype>
#include <fstream>
#include <locale>
#include <sstream>
#include <string>
#include <vector>
#include <unordered_map>
Expand All @@ -75,7 +76,8 @@ namespace DX

WaveFrontReader() noexcept
: hasNormals(false),
hasTexcoords(false)
hasTexcoords(false),
hasVertexColors(false)
{}

HRESULT Load(_In_z_ const wchar_t* szFileName, bool ccw = true, bool loadmtl = true)
Expand Down Expand Up @@ -107,6 +109,7 @@ namespace DX
std::vector<XMFLOAT3> positions;
std::vector<XMFLOAT3> normals;
std::vector<XMFLOAT2> texCoords;
std::vector<XMFLOAT3> positionColors;

VertexCache vertexCache;

Expand Down Expand Up @@ -152,6 +155,32 @@ namespace DX
float x, y, z;
InFile >> x >> y >> z;
positions.emplace_back(XMFLOAT3(x, y, z));

// Some tools (e.g. MeshLab) write a per-vertex color after the position as
// "v x y z r g b". This is not part of the OBJ specification, so only exactly
// three extra values are treated as a color; a single extra value is the
// optional 'w' coordinate and is ignored.
XMFLOAT3 color(1.f, 1.f, 1.f);

std::wstring rest;
std::getline(InFile, rest, L'\n');
InFile.putback(L'\n');

std::wistringstream extra(rest);
extra.imbue(std::locale::classic());

float values[4] = {};
size_t count = 0;
while (count < std::size(values) && extra >> values[count])
++count;

if (count == 3)
{
color = XMFLOAT3(values[0], values[1], values[2]);
hasVertexColors = true;
}

positionColors.emplace_back(color);
}
else if (0 == wcscmp(strCommand.c_str(), L"vt"))
{
Expand Down Expand Up @@ -284,6 +313,12 @@ namespace DX
if (index == uint32_t(-1))
return E_OUTOFMEMORY;

if (index == vertexColors.size())
{
// New vertex: its color comes from the position it was built from
vertexColors.emplace_back(positionColors[vertexIndex]);
}

constexpr uint32_t maxIndex = (sizeof(index_t) == 2) ? UINT16_MAX : UINT32_MAX;
if (index >= maxIndex)
{
Expand Down Expand Up @@ -399,6 +434,11 @@ namespace DX
if (positions.empty())
return E_FAIL;

if (!hasVertexColors)
{
vertexColors.clear();
}

// Cleanup
InFile.close();

Expand Down Expand Up @@ -617,9 +657,11 @@ namespace DX
indices.clear();
attributes.clear();
materials.clear();
vertexColors.clear();
name.clear();
hasNormals = false;
hasTexcoords = false;
hasNormals = false;
hasTexcoords = false;
hasVertexColors = false;

bounds.Center.x = bounds.Center.y = bounds.Center.z = 0.f;
bounds.Extents.x = bounds.Extents.y = bounds.Extents.z = 0.f;
Expand Down Expand Up @@ -739,9 +781,14 @@ namespace DX
std::vector<uint32_t> attributes;
std::vector<Material> materials;

// Per-vertex colors from the non-standard "v x y z r g b" extension, one per entry in
// 'vertices'. Only filled in when hasVertexColors is true.
std::vector<DirectX::XMFLOAT3> vertexColors;

std::wstring name;
bool hasNormals;
bool hasTexcoords;
bool hasVertexColors;

DirectX::BoundingBox bounds;

Expand Down