I have been working on this .obj loader for a long time (2 weeks) and I have only been working with one model, which is a model of a car. I got bored with the car so i tried a cube and it appeared as a mess of triangles. whats interesting is that the same cube displayed fine before.
void loadObjv2(std::string path, ScreenRatio screenRatio)
{
std::string fileContent = LoadFile(path);
std::vector<Vertex> vertexVec;
std::vector<Face> facesVec;
std::vector<TexCoord> texCoordVec;
std::vector<Normal> normalVec;
std::unordered_map<std::string, Point> faceMap;
std::vector<uint32_t> indicesVec;
std::vector<float> verticesVec;
//parse the obj file
// Use std::istringstream to iterate over lines
std::istringstream iss(fileContent);
std::string line;
size_t verticesSize = 0;
size_t facesSize = 0;
size_t texCoordsSize = 0;
size_t normalsSize = 0;
std::vector<std::string> verticesS;
std::vector<std::string> texCoordsS;
std::vector<std::string> normalsS;
std::vector<std::string> facesS;
//qualify lines for parsing
while (std::getline(iss, line)) {
if (line.data()[0] == 'v' && line.data()[1] == ' ') {
verticesSize++;
verticesS.push_back(line);
}
else if (line.data()[0] == 'f' && line.data()[1] == ' ') {
facesSize++;
facesS.push_back(line);
}
else if (line.data()[0] == 'v' && line.data()[1] == 't') {
texCoordsSize++;
texCoordsS.push_back(line);
}
else if (line.data()[0] == 'v' && line.data()[1] == 'n') {
normalsSize++;
normalsS.push_back(line);
}
}
std::thread t1 = std::thread([&verticesS, &vertexVec]() {
for (std::string& s : verticesS)
{
std::vector<std::string> sv = splitString(s, ' ');
Vertex v = {};
for (int i = 1; i < sv.size(); i++)
{
switch (i)
{
case 1:
v.x = std::stof(sv[i]);
break;
case 2:
v.y = std::stof(sv[i]);
break;
case 3:
v.z = std::stof(sv[i]);
break;
}
}
vertexVec.push_back(v);
}
});
std::thread t2 = std::thread([&facesS, &facesVec]() {
for (std::string& s : facesS)
{
std::vector<std::string> sv = splitString(s, ' ');
Face f = {};
std::vector<std::vector<std::string>> ssv(3);
for (int i = 1; i < sv.size(); i++)
{
switch (i) {
case 1:
ssv[i - 1] = splitString(sv[i], '/');
for (int z = 0; z < ssv[i - 1].size(); z++)
{
switch (z)
{
case 0:
f.vi1 = std::stoi(ssv[i - 1][0]);
break;
case 1:
f.ti1 = std::stoi(ssv[i - 1][1]);
break;
case 2:
f.ni1 = std::stoi(ssv[i - 1][2]);
break;
}
}
break;
case 2:
ssv[i - 1] = splitString(sv[i], '/');
for (int z = 0; z < ssv[i - 1].size(); z++)
{
switch (z)
{
case 0:
f.vi2 = std::stoi(ssv[i - 1][0]);
break;
case 1:
f.ti2 = std::stoi(ssv[i - 1][1]);
break;
case 2:
f.ni2 = std::stoi(ssv[i - 1][2]);
break;
}
}
break;
case 3:
ssv[i - 1] = splitString(sv[i], '/');
for (int z = 0; z < ssv[i - 1].size(); z++)
{
switch (z)
{
case 0:
f.vi3 = std::stoi(ssv[i - 1][0]);
break;
case 1:
f.ti3 = std::stoi(ssv[i - 1][1]);
break;
case 2:
f.ni3 = std::stoi(ssv[i - 1][2]);
break;
}
}
break;
}
}
facesVec.push_back(f);
}
});
std::thread t3 = std::thread([&normalsS, &normalVec]() {
for (std::string& s : normalsS)
{
std::vector<std::string> sv = splitString(s, ' ');
Normal n = {};
for (int i = 1; i < 4; i++)
{
switch (i)
{
case 1:
n.x = std::stof(sv[i]);
break;
case 2:
n.y = std::stof(sv[i]);
break;
case 3:
n.z = std::stof(sv[i]);
break;
}
}
normalVec.push_back(n);
}
});
std::thread t4 = std::thread([&texCoordsS, &texCoordVec]() {
for (std::string& s : texCoordsS)
{
std::vector<std::string> sv = splitString(s, ' ');
TexCoord t = {};
for (int i = 1; i < 3; i++)
{
switch (i)
{
case 1:
t.x = std::stof(sv[i]);
break;
case 2:
t.y = std::stof(sv[i]);
break;
}
}
texCoordVec.push_back(t);
}
});
t1.join();
t2.join();
t3.join();
t4.join();
uint32_t index = 0;
for (const Face& f : facesVec)
{
std::array<Point, 3> points;
points[0] = Point(f.vi1, f.ti1, f.ni1);
points[1] = Point(f.vi2, f.ti2, f.ni2);
points[2] = Point(f.vi3, f.ti3, f.ni3);
for (int i = 0; i < points.size(); i++)
{
if (faceMap.find(points[i].to_string()) == faceMap.end())
{
points[i].index = index;
faceMap.insert(std::make_pair(points[i].to_string(), points[i]));
index++;
}
auto it = faceMap.find(points[i].to_string());
indicesRender.push_back(it->second.index);
}
}
verticesRender.resize(faceMap.size() * 11);
uint64_t count = 1;
for (auto& f : faceMap)
{
verticesRender[f.second.index * 11 + 0] = vertexVec[f.second.vi - 1].x;
verticesRender[f.second.index * 11 + 1] = vertexVec[f.second.vi - 1].y;
verticesRender[f.second.index * 11 + 2] = vertexVec[f.second.vi - 1].z;
verticesRender[f.second.index * 11 + 3] = 0.4f * count;
verticesRender[f.second.index * 11 + 4] = 0.2f * count;
verticesRender[f.second.index * 11 + 5] = 0.3f * count;
if (count >= 3) count = 0;
verticesRender[f.second.index * 11 + 6] = texCoordVec[f.second.ti - 1].x;
verticesRender[f.second.index * 11 + 7] = texCoordVec[f.second.ti - 1].y;
verticesRender[f.second.index * 11 + 8] = normalVec[f.second.ni - 1].x;
verticesRender[f.second.index * 11 + 9] = normalVec[f.second.ni - 1].y;
verticesRender[f.second.index * 11 + 10] = normalVec[f.second.ni - 1].z;
count++;
}
}
I know that the code is extremely unclean and unpotimized but this is something I'm still working on.
files:
car: https://drive.google.com/file/d/1SJiDVCNNSnCJ3BF8diR5h7266r1Zf4ee/view?usp=sharing
cube: https://drive.google.com/file/d/1HhCLxhTqwc2wXsDNN1leb70zI4SODX4b/view?usp=sharing
when I pass the data to render it using vulkan with no back culling it appears as a mess of triangles that fit in the shape of the model.
The car.obj renders fine but cube.obj renders as this mess.
this is a part of a class and the indicesRender and verticesRender are a part of it.