change obj parsing to its own object and start polygon triangulation

This commit is contained in:
2025-01-16 22:10:09 +01:00
parent a07252b059
commit 67eca73d47
7 changed files with 272 additions and 157 deletions

218
srcs/class/ObjParser.cpp Normal file
View File

@ -0,0 +1,218 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* ObjParser.cpp :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tomoron <tomoron@student.42angouleme.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/01/16 15:00:33 by tomoron #+# #+# */
/* Updated: 2025/01/16 22:00:46 by tomoron ### ########.fr */
/* */
/* ************************************************************************** */
#include "RT.hpp"
ObjParser::ObjParser(std::string &filename)
{
_file.open(filename);
if(!_file.is_open())
throw std::runtime_error("OBJ : could not open object file");
}
ObjParser::~ObjParser()
{
_file.close();
}
glm::vec3 ObjParser::getVertex(std::stringstream &line)
{
glm::vec3 res;
if(!(line >> res.x >> res.y >> res.z))
throw std::runtime_error("syntax error in obj file while parsing vertex");
return(res);
}
long int ObjParser::checkVertexIndex(int index, size_t size)
{
if((size_t)index > size || index == 0 || (index < 0 && (size_t)(-index) > size))
throw std::runtime_error("obj file error, invalid vertex index");
if(index < 0)
index = size - index;
return(index - 1);
}
//void ObjParser::isEar(glm::vec3 v1, glm::vec3 v2, glm::vec3 v3, std::vector<glm::vec3> &vertices)
//{
//
//}
void ObjParser::addTriangleFromPolygon(std::vector<glm::vec3> &vertices, Scene &scene)
{
glm::vec3 normal;
glm::vec3 v1, v2 ,v3, v4;
(void)scene;
for (size_t i = 0; i < vertices.size(); i++)
{
v1 = vertices[(i - 1) % vertices.size()];
v2 = vertices[i];
v3 = vertices[(i + 1) % vertices.size()];
v4 = vertices[(i + 2) % vertices.size()];
normal = glm::normalize(glm::cross(v2 - v1, v3 - v1));
std::cout << glm::to_string(normal) << std::endl;
float dot = glm::dot(normal, v4 - v1);
std::cout << dot << std::endl;
//if(isEar(v1, v2 ,v3, vertices))
//{
// vertices.erase(vertices.begin() + i);
// scene.addObject(new Triangle(v1, v2 ,v3));
//}
}
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
}
void ObjParser::addFace(std::stringstream &line, std::vector<glm::vec3> &vertices, int mat, Scene &scene)
{
int vert_index;
std::vector<glm::vec3> face_vertices;
(void)mat;
(void)scene;
while((line >> vert_index))
face_vertices.push_back(vertices[checkVertexIndex(vert_index, vertices.size())]);
if(face_vertices.size() < 3)
throw std::runtime_error("OBJ : face does not have enough vertices");
for(size_t i = 0; i < face_vertices.size(); i++)
std::cout << face_vertices[i].x << " " << face_vertices[i].y << " " << face_vertices[i].z << " | ";
std::cout << std::endl;
// while(face_vertices.size() > 3)
// addTriangleFromPolygon(face_vertices, scene);
if(!line.eof())
throw std::runtime_error("OBJ: an error occured while parsing face");
addTriangle(face_vertices[0], face_vertices[1], face_vertices[2],mat, scene);
}
void ObjParser::addTriangle(glm::vec3 v1, glm::vec3 v2, glm::vec3 v3, int mat, Scene &scene)
{
scene.addObject(new Triangle(v1, v2, v3, mat));
}
void ObjParser::parseMtl(std::stringstream &input_line, std::map<std::string, int> &materials, Scene &scene)
{
std::string filename;
std::ifstream file;
std::string matName;
std::string identifier;
std::string line;
Material *mat;
input_line >> filename;
file.open(filename);
mat = 0;
if(!file.is_open())
throw std::runtime_error("OBJ : could not open material file");
while(getline(file, line))
{
if (line.empty() || line[0] == '#')
continue;
std::stringstream lineStream(line);
lineStream >> identifier;
if(identifier == "newmtl")
{
if(mat)
{
scene.addMaterial(mat);
materials[matName] = scene.getMaterialData().size() - 1;
}
lineStream >> matName;
if(matName.empty())
throw std::runtime_error("OBJ: syntax error in material file, missing material name");
mat = new Material;
memset(mat, 0, sizeof(Material));
mat->metallic = 1.0f;
continue;
}
if(!mat)
throw std::runtime_error("OBJ: error in material file, material name not defined");
if(identifier == "Kd")
{
if(!(lineStream >> mat->color.x >> mat->color.y >> mat->color.z))
throw std::runtime_error("OBJ: syntax error while getting material color");
}
else if(identifier == "Ns")
{
if(!(lineStream >> mat->roughness) || mat->roughness > 1000 || mat->roughness < 0)
throw std::runtime_error("OBJ: syntax error while getting material softness");
mat->roughness /= 1000;
}
else if(identifier == "Ke")
{
float x, y, z;
if(!(lineStream >> x >> y >> z))
throw std::runtime_error("OBJ: syntax error while getting material emission");
mat->emission = (x + y + z) / 3;
}
else if(identifier == "Ni")
{
if(!(lineStream >> mat->refraction))
throw std::runtime_error("OBJ: syntax error while getting material refraction");
}
else
std::cerr << "unsupported material setting : " << identifier << std::endl;
}
if(mat)
{
scene.addMaterial(mat);
materials[matName] = scene.getMaterialData().size() - 1;
}
file.close();
}
void ObjParser::parse(Scene &scene)
{
std::vector<glm::vec3> vertices;
std::string filename;
std::map<std::string, int> matNames;
std::string line;
std::string identifier;
std::ifstream file;
int curMat;
curMat = 0;
while (getline(_file, line))
{
try{
if(line[0] == '#' || line.empty())
continue;
std::stringstream lineStream(line);
identifier = "";
lineStream >> identifier;
if(identifier == "v")
vertices.push_back(getVertex(lineStream));
else if (identifier == "f")
addFace(lineStream, vertices, curMat, scene);
else if (identifier == "mtllib")
parseMtl(lineStream, matNames, scene);
else if (identifier == "usemtl")
{
lineStream >> identifier;
if(matNames.find(identifier) == matNames.end())
throw std::runtime_error("OBJ: invalid material name");
curMat = matNames[identifier];
}
}catch (std::exception &e)
{
std::cerr << line << std::endl;
throw;
}
}
}

View File

@ -6,7 +6,7 @@
/* By: ycontre <ycontre@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/12/26 21:43:51 by TheRed #+# #+# */
/* Updated: 2025/01/15 19:52:51 by ycontre ### ########.fr */
/* Updated: 2025/01/16 15:17:10 by tomoron ### ########.fr */
/* */
/* ************************************************************************** */
@ -95,152 +95,6 @@ void SceneParser::parseCamera(std::stringstream &line)
}
glm::vec3 SceneParser::getVertex(std::stringstream &line)
{
glm::vec3 res;
if(!(line >> res.x >> res.y >> res.z))
throw std::runtime_error("syntax error in obj file while parsing vertex");
return(res);
}
long int SceneParser::getVertexIndex(std::stringstream &line, size_t size)
{
long int index;
if(!(line >> index))
throw std::runtime_error("syntax error in obj file while parsing face");
if((size_t)index > size || index == 0 || (index < 0 && (size_t)(-index) > size))
throw std::runtime_error("obj file error, invalid vertex index");
if(index < 0)
index = size - index;
return(index - 1);
}
Triangle *SceneParser::getFace(std::stringstream &line, std::vector<glm::vec3> &vertices, int mat)
{
glm::vec3 triangle[3];
triangle[0] = vertices[getVertexIndex(line, vertices.size())];
triangle[1] = vertices[getVertexIndex(line, vertices.size())];
triangle[2] = vertices[getVertexIndex(line, vertices.size())];
return (new Triangle(triangle[0], triangle[1], triangle[2], mat));
}
void SceneParser::parseMtl(std::stringstream &input_line, std::map<std::string, int> &materials)
{
std::string filename;
std::ifstream file;
std::string matName;
std::string identifier;
std::string line;
Material *mat;
input_line >> filename;
file.open(filename);
mat = 0;
if(!file.is_open())
throw std::runtime_error("OBJ : could not open material file");
while(getline(file, line))
{
if (line.empty() || line[0] == '#')
continue;
std::stringstream lineStream(line);
lineStream >> identifier;
if(identifier == "newmtl")
{
if(mat)
{
_scene->addMaterial(mat);
materials[matName] = _scene->getMaterialData().size() - 1;
}
lineStream >> matName;
if(matName.empty())
throw std::runtime_error("OBJ: syntax error in material file, missing material name");
mat = new Material;
memset(mat, 0, sizeof(Material));
mat->metallic = 1.0f;
continue;
}
if(!mat)
throw std::runtime_error("OBJ: error in material file, material name not defined");
if(identifier == "Kd")
{
if(!(lineStream >> mat->color.x >> mat->color.y >> mat->color.z))
throw std::runtime_error("OBJ: syntax error while getting material color");
}
else if(identifier == "Ns")
{
if(!(lineStream >> mat->roughness) || mat->roughness > 1000 || mat->roughness < 0)
throw std::runtime_error("OBJ: syntax error while getting material softness");
mat->roughness /= 1000;
}
else if(identifier == "Ke")
{
float x, y, z;
if(!(lineStream >> x >> y >> z))
throw std::runtime_error("OBJ: syntax error while getting material emission");
mat->emission = (x + y + z) / 3;
}
else if(identifier == "Ni")
{
if(!(lineStream >> mat->refraction))
throw std::runtime_error("OBJ: syntax error while getting material refraction");
}
else
std::cerr << "unsupported material setting : " << identifier << std::endl;
}
if(mat)
{
_scene->addMaterial(mat);
materials[matName] = _scene->getMaterialData().size() - 1;
}
}
void SceneParser::parseObj(std::stringstream &objInfo)
{
std::vector<glm::vec3> vertices;
std::string filename;
std::map<std::string, int> matNames;
std::string line;
std::string identifier;
std::ifstream file;
int curMat;
objInfo >> filename;
file.open(filename);
curMat = 0;
if (!file.is_open())
throw std::runtime_error("OBJ : could not open object file");
while (getline(file, line))
{
try{
if(line[0] == '#' || line.empty())
continue;
std::stringstream lineStream(line);
identifier = "";
lineStream >> identifier;
if(identifier == "v")
vertices.push_back(getVertex(lineStream));
else if (identifier == "f")
_scene->addObject(getFace(lineStream, vertices, curMat));
else if (identifier == "mtllib")
parseMtl(lineStream, matNames);
else if (identifier == "usemtl")
{
lineStream >> identifier;
if(matNames.find(identifier) == matNames.end())
throw std::runtime_error("OBJ: invalid material name");
curMat = matNames[identifier];
}
}catch (std::exception &e)
{
std::cerr << line << std::endl;
throw;
}
}
}
bool SceneParser::parseLine(const std::string &line)
{
if (line.empty() || line[0] == '#')
@ -274,7 +128,11 @@ bool SceneParser::parseLine(const std::string &line)
else if (identifier == "CAM")
this->parseCamera(ss);
else if (identifier == "OBJ")
parseObj(ss);
{
ss >> identifier;
ObjParser obj(identifier);
obj.parse(*_scene);
}
}
catch (const std::exception& e)
{