Hi, folks!
I have tried to create a 3D model class called Model3, which will inherit from my base class Model. This Model3-class supports only Wavefront OBJ files at the moment and I'm having trouble setting up correct data for OpenGL to process. I try to get rid of the deprecated OpenGL functions and use vertex array objects and vertex buffers objects instead to accomplish my goal to display a 3D model on screen.
The problem is rather simple to describe: polygons are formed incorrectly.
This is how I see the model in Blender (in which I also did the model):
[url="http://imageshack.us/photo/my-images/838/timg.png/"][url="http://imageshack.us/photo/my-images/838/timg.png/"][url="http://imageshack.us/photo/my-images/838/timg.png/"]http://imageshack.us/photo/my-images/838/timg.png/[/url][/url][/url]
And this is what ends up looking in my program:
[url="http://imageshack.us/photo/my-images/546/tim2i.png/"][url="http://imageshack.us/photo/my-images/546/tim2i.png/"][url="http://imageshack.us/photo/my-images/546/tim2i.png/"]http://imageshack.us/photo/my-images/546/tim2i.png/[/url][/url][/url]
Here's Model3 class definition:
/// ----------------------------------
/// @class Model3
/// @brief Represents a 3D model.
/// @typedef Model3D
/// ----------------------------------
typedef class Model3 : public Model{
public:
/// Enumerations:
enum class FormatFile : unsigned int{
FORMATFILE_3DS,
FORMATFILE_OBJ
};
/// Constructors & destructors:
Model3(void);
Model3(Model3 const& model) = default;
Model3(Model3&& model) = default;
~Model3(void);
/// Member functions:
Model3& set_data(Model3::FormatFile const& format_file, std::string const& name_file);
Model3& set_data(Model3::FormatFile const& format_file, std::string const&& name_file);
Model3& set_data(Model3::FormatFile&& format_file, std::string const& name_file);
Model3& set_data(Model3::FormatFile&& format_file, std::string const&& name_file);
void show(void) const;
/// Member functions (overloaded operators):
Model3& operator=(Model3 const& model);
Model3& operator=(Model3&& model);
private:
/// Member data:
std::vector<Helixirr::Vector3<float>> _m_voDataFace[3]; // Element 0 contains vertex coordinates, element 1 contains texture coordinates, element 2 contains vertex normals.
std::vector<Helixirr::Vector3<float>> _m_voDataVertex[3]; // Element 0 contains vertex coordinates, element 1 contains texture coordinates, element 2 contains vertex normals.
unsigned int _m_uiIdArrayVertex, _m_uiBufferVertex;
}Model3D;
Here are implementations of functions set_data and show:
/// Member functions:
Model3& Model3::set_data(Model3::FormatFile const& format_file, std::string const& name_file){ /* UNFINISHED! */
std::ifstream __file(name_file);
// 3D model loading lambdas:
auto const __load_3ds = [&](void){
/* UNFINISHED! */
};
auto const __load_obj = [&](void){ /* WORKS HALF RIGHT AND MORE FUNCTIONALITY IS REQUIRED! */
auto const __read_data_vertices = [](std::string const& string, float coordinates[], unsigned int const&& amount_elements, unsigned int&& index_begin){
// Variables used in the following for loop:
// index_begin = end index for string substraction operation
// __i = index of the temporary float array
// __j = start index for string substraction operation
for(unsigned int __i = 0, __j = index_begin; __i != amount_elements; ++__j){
if(string[__j] == ' '){ // If the "end character" for floating number is detected:
coordinates[__i++] = atof(string.substr(index_begin, ++__j).c_str());
index_begin = __j;
}
}
};
std::string __line;
clock_t init = clock();
while(std::getline(__file, __line)){ // For each line in the requested file:
switch(__line[0]){ // Check out the first letter of a line:
case 'f':{
// Read through the whole line ignoring all the insignificant characters (like '\n'):
for(unsigned int __i = 2, __j = 2, __k = 0; __j != __line.size() - 1; ++__j){
if(__line[__j] == '/'){
_m_voDataFace[__k].push_back(_m_voDataVertex[__k][atoi(__line.substr(__i, ++__j).c_str())]);
__i = __j;
++__k;
}
else if(__line[__j] == ' '){
++__j;
__i = __j;
__k = 0;
}
}
continue;
}
case 'v': // If a requested line contains some sort of vertex data:
if(__line[1] == ' '){ // If the requested line contains vertex coordinates:
float __coordinates[3] = {0.0f}; // A temporary float array to store vertex coordinates.
__read_data_vertices(__line, __coordinates, 3, 2);
_m_voDataVertex[0].push_back(Helixirr::Vector3<float>(std::move(__coordinates[0]), std::move(__coordinates[1]), std::move(__coordinates[2])));
}
else if(__line[1] == 'n'){ // If the requested line contains vertex normals:
float __coordinates[3] = {0.0f}; // A temporary float array to store vertex normals.
__read_data_vertices(__line, __coordinates, 3, 3);
_m_voDataVertex[2].push_back(Helixirr::Vector3<float>(std::move(__coordinates[0]), std::move(__coordinates[1]), std::move(__coordinates[2])));
}
else if(__line[1] == 't'){ // If the requested line contains UV coordinates:
float __coordinates[2] = {0.0f}; // A temporary float array to store UV coordinates.
__read_data_vertices(__line, __coordinates, 2, 3);
_m_voDataVertex[1].push_back(Helixirr::Vector3<float>(std::move(__coordinates[0]), std::move(__coordinates[1]), 0.0f));
}
continue;
default:
continue;
}
}
printf("OBJ file loading - elapsed time: %f\n", static_cast<double>(clock() - init) / static_cast<double>(CLOCKS_PER_SEC));
};
// Detect requested file format:
switch(format_file){
case Model3::FormatFile::FORMATFILE_3DS:
__load_3ds();
break;
case Model3::FormatFile::FORMATFILE_OBJ:
__load_obj();
break;
default:
break;
}
// Create and bind a vertex array:
if(_m_uiIdArrayVertex == 0)
glGenVertexArrays(1, &_m_uiIdArrayVertex);
glBindVertexArray(_m_uiIdArrayVertex);
// Create and bind a vertex buffer object:
if(_m_uiBufferVertex == 0)
glGenBuffers(1, &_m_uiBufferVertex);
glBindBuffer(GL_ARRAY_BUFFER, _m_uiBufferVertex);
// Insert vertex data:
glBufferData(GL_ARRAY_BUFFER, sizeof(_m_voDataFace[0][0]) * _m_voDataFace[0].size(), &_m_voDataFace[0][0], GL_STATIC_DRAW);
return *this;
}
Model3& Model3::set_data(Model3::FormatFile const& format_file, std::string const&& name_file){
return this->set_data(format_file, name_file);
}
Model3& Model3::set_data(Model3::FormatFile&& format_file, std::string const& name_file){
return this->set_data(format_file, name_file);
}
Model3& Model3::set_data(Model3::FormatFile&& format_file, std::string const&& name_file){
return this->set_data(format_file, name_file);
}
void Model3::show(void) const{
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, _m_uiBufferVertex);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnable(GL_POINT_SMOOTH);
glPointSize(2.0f);
glDrawArrays(GL_TRIANGLES, 0, _m_voDataFace[0].size() + 1);
glDisableVertexAttribArray(0);
}
I don't understand what have I done wrong. Can anybody help me?