Конвертировать .obj в двоичный формат (VBO)

Я создал Mesh Loader для конвертации .obj файлы в двоичный файл, чтобы я мог загрузить их прямо в мой VertexBuffer без разбора их в первую очередь.
Мой код работал нормально для конкретной модели, которую я использовал для тестирования. Но после тестирования некоторых моделей, которые я скачал из интернета, я заметил, что они не конвертируются полностью.

Вот как я конвертирую файлы .obj (это взято прямо из файла obj2vbo.cpp, предоставленного Microsoft в качестве примера, с некоторыми незначительными изменениями):

ifstream objFile(this->fileName.toStdString().c_str(), ifstream::in);
if (!objFile.is_open()) {
ui.statusBar->showMessage("Could not open obj file!");
return false;
}

vector<XMFLOAT3> positions;
vector<XMFLOAT3> normals;
vector<XMFLOAT2> texcoords;
vector<vector<IndexTriplet>> faces;

unsigned int lineNum = 1;

while (objFile.good()) {
string line;
getline(objFile, line);
istringstream lineStream(line);

if (lineStream.peek() != '#') {
string tag;
lineStream >> tag;

if (
tag.compare("mtllib") == 0 ||
tag.compare("o") == 0 ||
tag.compare("g") == 0 ||
tag.compare("usemtl") == 0 ||
tag.compare("s") == 0
) {
cout << "(" << lineNum << "): Warning: Does not support tag \"" << tag << "\"" << endl;
}
else if (tag.compare("v") == 0) {
XMFLOAT3 pos;
lineStream >> pos.x >> pos.y >> pos.z;
positions.push_back(pos);
}
else if (tag.compare("vn") == 0) {
XMFLOAT3 normal;
lineStream >> normal.x >> normal.y >> normal.z;
normals.push_back(normal);
}
else if (tag.compare("vt") == 0) {
XMFLOAT2 texcoord;
lineStream >> texcoord.x >> texcoord.y;
texcoords.push_back(texcoord);
}
else if (tag.compare("f") == 0) {
vector<IndexTriplet> face;
while (lineStream.good()) {
string tripletString;
lineStream >> tripletString;
if (tripletString.size() > 0) {
istringstream tripletStream(tripletString);

IndexTriplet triplet;
triplet.pos = 0;
triplet.norm = 0;
triplet.tex = 0;

tripletStream >> triplet.pos;
if (tripletStream.get() == '/') {
if (tripletStream.peek() != '/') {
tripletStream >> triplet.tex;
}
if (tripletStream.get() == '/') {
tripletStream >> triplet.norm;
}
}
face.push_back(triplet);
}
}
faces.push_back(face);
}
else if (tag.size() > 0) {
// unsupported tag
}
}
lineNum++;
}

objFile.close();

if (positions.size() == 0 || faces.size() == 0) {
ui.statusBar->showMessage("Error: File contains no geometry!");
return false;
}

// Validate Mesh
for (auto face = faces.begin(); face != faces.end(); face++) {
if (face->size() < 3) {
ui.statusBar->showMessage("Error: Face size < 3 invalid!");
return false;
}
for (auto triplet = face->begin(); triplet != face->end(); triplet++) {
if (triplet->pos > positions.size() || triplet->pos < 1) {
ui.statusBar->showMessage("Error: Position index out of range");
return false;
}
if (triplet->norm > normals.size() || triplet->norm < 1) {
ui.statusBar->showMessage("Error: Normal index out of range");
return false;
}
if (triplet->tex > texcoords.size() || triplet->tex < 1) {
ui.statusBar->showMessage("Error: Texcoord index out of range");
return false;
}
}
}

XMFLOAT3 boxMin = positions[faces[0][0].pos - 1];
XMFLOAT3 boxMax = boxMin;
for (auto face = faces.begin(); face != faces.end(); face++)
{
for (auto triplet = face->begin(); triplet != face->end(); triplet++)
{
XMFLOAT3 pos = positions[triplet->pos - 1];
boxMin.x = min(boxMin.x, pos.x);
boxMin.y = min(boxMin.y, pos.y);
boxMin.z = min(boxMin.z, pos.z);
boxMax.x = max(boxMax.x, pos.x);
boxMax.y = max(boxMax.y, pos.y);
boxMax.z = max(boxMax.z, pos.z);
}
}
XMFLOAT3 boxCenter;
XMStoreFloat3(&boxCenter, ((XMLoadFloat3(&boxMax) + XMLoadFloat3(&boxMin)) / 2.0f));

// If specified in the arguments, normalize geometry to fit within a unit cube

if (true) // Bool variable later...
{
float maxAxis = max(max(boxMax.x - boxMin.x, boxMax.y - boxMin.y), boxMax.z - boxMin.z);
for (auto pos = positions.begin(); pos != positions.end(); pos++)
{
XMStoreFloat3(&(*pos), ((XMLoadFloat3(&(*pos)) - XMLoadFloat3(&boxCenter)) / maxAxis));
}
}// Generate missing normals
for (auto face = faces.begin(); face != faces.end(); face++)
{
XMFLOAT3 normal(0, 0, 0);
bool normalGenerated = false;
for (auto triplet = face->begin(); triplet != face->end(); triplet++)
{
if (!normalGenerated && triplet->norm == 0)
{
for (auto triplet = face->begin(); triplet != face->end(); triplet++)
{
XMFLOAT3 posThis = positions[triplet->pos - 1];
XMFLOAT3 posPrev = positions[(triplet == face->begin() ? (face->end() - 1)->pos : (triplet - 1)->pos) - 1];
XMFLOAT3 posNext = positions[(triplet == face->end() - 1 ? (face->begin())->pos : (triplet + 1)->pos) - 1];
XMStoreFloat3(
&normal,
XMVectorAdd(
XMLoadFloat3(&normal),
XMVector3Cross(XMVectorSubtract(XMLoadFloat3(&posNext), XMLoadFloat3(&posThis)), XMVectorSubtract(XMLoadFloat3(&posPrev), XMLoadFloat3(&posThis)))
)
);
triplet->norm = normals.size() + 1;
}
normals.push_back(normal);
normalGenerated = true;
}
}
}

// Fill in missing texture coordinates with (0, 0)

bool missingTexcoordCreated = false;
unsigned int missingTexcoordIndex = 0;
for (auto face = faces.begin(); face != faces.end(); face++)
{
for (auto triplet = face->begin(); triplet != face->end(); triplet++)
{
if (triplet->tex == 0)
{
if (!missingTexcoordCreated)
{
texcoords.push_back(XMFLOAT2(0.0f, 0.0f));
missingTexcoordIndex = texcoords.size();
missingTexcoordCreated = true;
}
triplet->tex = missingTexcoordIndex;
}
}
}

// Generate unique vertices and convert counter-clockwise faces to clockwise triangles

vector<Vertex> vertices;
vector<unsigned short> indices;
map<IndexTriplet, unsigned short> tripletIndices;
for (auto face = faces.begin(); face != faces.end(); face++)
{
for (auto triplet = face->begin(); triplet != face->end(); triplet++)
{
if (tripletIndices.find(*triplet) == tripletIndices.end())
{
tripletIndices[*triplet] = static_cast<unsigned short>(vertices.size());
Vertex vertex;
vertex.position = positions[triplet->pos - 1];
vertex.normals = normals[triplet->norm - 1];
vertex.uv = texcoords[triplet->tex - 1];
vertices.push_back(vertex);
}
if (triplet >= face->begin() + 2)
{
indices.push_back(tripletIndices[*face->begin()]);
indices.push_back(tripletIndices[*triplet]);
indices.push_back(tripletIndices[*(triplet - 1)]);
}
}
}

// Dump vertex and index data to the output VBO file

ofstream vboFile("binaryMesh.bin", ofstream::out | ofstream::binary);
if (!vboFile.is_open())
{
ui.statusBar->showMessage("Could not open file for writing!");
return false;
}

unsigned int numVertices = vertices.size();
unsigned int numIndices = indices.size();
vboFile.write(reinterpret_cast<char*>(&numVertices), sizeof(unsigned int));
vboFile.write(reinterpret_cast<char*>(&numIndices), sizeof(unsigned int));
vboFile.write(reinterpret_cast<char*>(&vertices[0]), sizeof(Vertex)* vertices.size());
vboFile.write(reinterpret_cast<char*>(&indices[0]), sizeof(unsigned short)* indices.size());

vboFile.close();

И вот как я прочитал это снова:

void createMeshData(_In_ byte* meshData, _Out_ VertexBuffer** vertexBuffer, _Out_ uint32* vertexCount)
{
*vertexCount = *reinterpret_cast<uint32*>(meshData);
BasicVertex* vertices = reinterpret_cast<BasicVertex*>(meshData + sizeof(uint32)* 2);
*vertexBuffer = this->m_renderer->createVertexBuffer(vertices, sizeof(BasicVertex) * (*vertexCount), false);
}

Я уже убедился, что обе структуры BasicVertex а также Vertex подобные. Это пример модели (Hulk) и как она выглядит:

введите описание изображения здесь

Кажется, что не только вершины неправильны, но и координаты текстуры тоже, но это другая проблема ..
Если вам нужна дополнительная информация, пожалуйста, дайте мне знать.
Спасибо за любой совет

1

Решение

Задача ещё не решена.

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector