I am writing a raytracer program in C++. Part of this program should be able to read a 3D model from a mesh.obj file.
I am currently having problems with reading the file using std::ifstream
.
I wrote a function read_mesh
, which takes a string parameter that specifies the path to the .obj file, given by a user. The function returns a list of triangle Primitives which are used to render the mesh.
I am using LOG(INFO) << "specific info";
so that I'm able to view what is going on in my program.
This is my function:
std::vector<Primitive> read_mesh(const std::string& path) const
{
LOG(INFO) << "Reading mesh";
LOG(INFO) << "Attempting to open file at " << path;
std::ifstream obj;
obj.exceptions(std::ifstream::failbit | std::ifstream::badbit);
// Open the file from the given path
try {
obj.open(path, ios::in);
}
catch (std::ifstream::failure::exception e) {
LOG(INFO) << "Exception when opening file \n" << e.what();
}
LOG(INFO) << "File opened";
// Initialize list of vertices
std::vector<Point3D> vertices;
// Initialize list of triangles
std::vector<Primitive> triangles;
std::string line;
// Read each line of the .obj file
while (std::getline(obj, line))
{
LOG(INFO) << "New line";
std::istringstream iss(line);
std::string method;
// Extract the type of data from the line
iss >> method;
// Checks if the data on the line represents a vertex
if (method == "v")
{
double x, y, z;
// Extract the x, y and z coordinates from the line
iss >> x >> y >> z;
LOG(INFO) << "New vertex (" << x << ", " << y << ", " << z << ")";
// Create a Point3D from the coordinates
Point3D p(x, y, z);
// Add the point to the list of vertices
vertices.push_back(p);
}
// Checks if the data on the line represents a set of triangles
else if (method == "f")
{
int a, b, c;
char s;
// Read the set of triangles from the polygon line with the index of the vertices seperated by a '/'
while ((iss >> a >> s >> b >> s >> c) && s == '/')
{
LOG(INFO) << "New triangle (v" << a << ", v" << b << ", v" << c << ")";
// Create a triangle from the corresponding vertices (index -1 because they start at 1 in .obj files) and add it to the triangles list
triangles.push_back(triangle(vertices[a - 1], vertices[b - 1], vertices[b - 1]));
}
}
else
{
LOG(INFO) << "Ignored this line";
}
}
if (!std::getline(obj, line))
{
LOG(INFO) << "Reached end of file";
}
obj.close();
LOG(INFO) << "Finished reading mesh, " << triangles.size() << " triangles found";
// Return the list of triangles
return triangles;
}
I can see each line being read correctly, and after the last line, no more lines are being read. But instead of printing "Reached end of file" and "Finished reading mesh, 290 triangles found", the program stops executing.
So I believe the problem is that the program never actually exits the while loop, although it stops printing "New line" and "Reached end of line".
Can anyone help me with finding the problem in this function? Any help is greatly appreciated, thanks!
EDIT:
Here is a sample application that uses the same functionality as the above function:
int main()
{
std::ifstream obj;
obj.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// Enter the path to the example.obj file
obj.open("C:/Users/Bram/Desktop/example-obj.txt", ios::in);
}
catch (std::ifstream::failure::exception e) {
std::cout << "Failed to open file";
return(1);
}
std::cout << "Reading file";
std::string line;
while (std::getline(obj, line))
{
std::cout << "New line";
std::istringstream iss(line);
std::string method;
iss >> method;
if (method == "v")
{
double x, y, z;
iss >> x >> y >> z;
std::cout << "New vertex (" << x << ", " << y << ", " << z << ")";
}
else if (method == "f")
{
int a, b, c;
char s;
while ((iss >> a >> s >> b >> s >> c) && s == '/')
{
std::cout << "New triangle using vertices " << a << ", " << b << ", " << c;
}
}
else
{
std::cout << "Ignored line";
}
}
std::cout << "Finished reading file";
obj.close();
return(0);
}
It reads the following example-obj.txt file that represents one triangle:
# example.obj
v -7.8541 121.3862 17.1093
v 7.1431 113.8654 23.1824
v 15.3955 112.2824 13.7628
f 1/2/3
The program prints the correct vertices and triangles and gives the following error message when executing:
Unhandled exception at 0x75EA08B2 in meshreader.exe: Microsoft C++ exception: std::ios_base::failure at memory location 0x008FF3F0.