Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[C++] OBJ Static Mesh Importer (No materials)


JeffSventora
 Share

Recommended Posts

Wavefront OBJ (.obj) is a popular format for exporting 3D static meshes in Maya and 3DS Max. What makes it popular is the unbelievable ease in which loading meshes can be attained. Please remember, this is for STATIC meshes, no animation data. I also did not release code to read in materials but that can be done easily with some research.

By default, Waveffront OBJ files are organized in a way that is pretty friendly with OpenGL but we are going to take the imported data and convert it to an indexed mesh. An indexed mesh is one that does not retain redundant data and uses indices to reference correct vertices when drawing primitives to the screen.

If you want to know more about Wavefront OBJ files, you can look here:

[http://www.fileforma…ontobj/egff.htm](http://www.fileformat.info/format/wavefrontobj/egff.htm)

Here is the code. You can see that I organized the code in an easy to read way, you have a function that loads the mesh, easy enough!

[http://pastebin.com/Qk9RecHE](http://pastebin.com/Qk9RecHE)

```

#include

#include

#include

#include

#include

using std::vector;

using std::stringstream;

using std::string;

using std::ifstream;

using std::ofstream;

#define TAG_VERTEX_POS "v"

#define TAG_VERTEX_NORM "vn"

#define TAG_VERTEX_TEX "vt"

#define TAG_FACE "f"

typedef struct { float x, y, z; } Vec3F;

typedef struct { float x, y; } Vec2F;

struct obj_vert

{

Vec3F position;

Vec3F normal;

Vec2F tex_coord;

bool operator==(const obj_vert& comp) const

{

if( !(comp.position.x == position.x) ||

!(comp.position.y == position.y) ||

!(comp.position.z == position.z) )

return false;

if( !(comp.normal.x == normal.x) ||

!(comp.normal.y == normal.y) ||

!(comp.normal.z == normal.z) )

return false;

if( !(comp.tex_coord.x == tex_coord.x) ||

!(comp.tex_coord.y == tex_coord.y) )

return false;

return true;

}

};

struct obj_face

{

obj_vert vertices[3];

};

struct obj_face_index

{

int pos_indices[3];

int norm_indices[3];

int tex_indices[3];

};

typedef struct _mesh

{

obj_vert* verts;

int* indices;

int num_verts;

int num_indices;

_mesh(void)

{

verts = nullptr;

indices = nullptr;

}

~_mesh(void)

{

if(verts != nullptr)

{

delete [] verts;

verts = nullptr;

}

if(indices != nullptr)

{

delete [] indices;

indices = nullptr;

}

}

} mesh, *lpmesh;

// Helper Functions

lpmesh load_mesh(const char* file);

int contains_vector(const vector& vec, obj_vert check);

bool is_obj_file(const char* filename);

bool write_mesh(const lpmesh write_mesh, const char* filename);

// Entry Point

int main(int argc, char* argv[])

{

for(int i = 1; i < argc; ++i)

{

if(is_obj_file(argv[i]))

{

lpmesh in_mesh = load_mesh(argv[i]);

if(!write_mesh(in_mesh, argv[i]))

printf("FAILED\n\n");

else

printf("SUCCESS\n\n");

}

}

return getchar();

}

// helper Function Definitions

lpmesh load_mesh(const char* file)

{

// Used to build the unique list and indices

vector positions;

vector normals;

vector tex_coords;

vector faces;

vector unique_verts;

vector indices;

ifstream filestream;

filestream.open(file);

if(!filestream.is_open())

return nullptr;

// Read every line of the .obj file

string line_stream;

while(std::getline(filestream, line_stream))

{

stringstream str_stream(line_stream);

string type_str;

str_stream >> type_str;

if(type_str == TAG_VERTEX_POS)

{

Vec3F pos;

str_stream >> pos.x >> pos.y >> pos.z;

positions.push_back(pos);

}

else if(type_str == TAG_VERTEX_TEX)

{

Vec2F tex;

str_stream >> tex.x >> tex.y;

tex_coords.push_back(tex);

}

else if(type_str == TAG_VERTEX_NORM)

{

Vec3F norm;

str_stream >> norm.x >> norm.y >> norm.z;

normals.push_back(norm);

}

else if(type_str == TAG_FACE)

{

obj_face_index face_index;

char interrupt;

for(int i = 0; i < 3; ++i)

{

str_stream >> face_index.pos_indices[i] >> interrupt

>> face_index.tex_indices[i] >> interrupt

>> face_index.norm_indices[i];

}

faces.push_back(face_index);

}

}

// Close the file

filestream.close();

// Build unique vertex list

for(size_t i = 0; i < faces.size(); ++i)

{

for(int j = 0; j < 3; ++j)

{

obj_vert new_vert;

new_vert.position = positions[faces[i].pos_indices[j] - 1];

new_vert.normal = normals[faces[i].norm_indices[j] - 1];

new_vert.tex_coord = tex_coords[faces[i].tex_indices[j] - 1];

int uindex = contains_vector(unique_verts, new_vert);

if(uindex >= 0)

indices.push_back(uindex);

else

{

indices.push_back((int)unique_verts.size());

unique_verts.push_back(new_vert);

}

}

}

// Fill out the mesh

lpmesh new_mesh = new mesh();

new_mesh->num_verts = unique_verts.size();

new_mesh->verts = new obj_vert[new_mesh->num_verts];

new_mesh->num_indices = indices.size();

new_mesh->indices = new int[new_mesh->num_indices];

int size_of_vert = sizeof(obj_vert);

memcpy(new_mesh->verts, &unique_verts[0], size_of_vert * new_mesh->num_verts);

memcpy(new_mesh->indices, &indices[0], sizeof(int) * new_mesh->num_indices);

return new_mesh;

}

int contains_vector(const vector& vec, obj_vert check)

{

for(size_t i = 0; i < vec.size(); ++i)

if(vec[i] == check)

return (int)i;

return -1;

}

bool is_obj_file(const char* filename)

{

unsigned extension_index = strlen(filename) - 4;

string file_mod = filename + extension_index;

if(file_mod != ".obj")

return false;

return true;

}

bool write_mesh(const lpmesh write_mesh, const char* filename)

{

printf("Converting \"%s\"\n", filename);

if(write_mesh == nullptr)

return false;

string file_mod = filename;

unsigned filename_len = strlen(filename);

unsigned ext_begin = file_mod.find('.') + 1;

unsigned cur_ext_len = strlen(filename + ext_begin);

char* new_file = new char[(filename_len - cur_ext_len) + 4];

memcpy(new_file, filename, filename_len - cur_ext_len);

sprintf(new_file + ext_begin, "smo\0");

printf("Writing to \"%s\"\n", new_file);

ofstream file;

file.open(new_file, std::ios_base::out | std::ios_base::binary);

if(!file.is_open())

return false;

// Write out the mesh

file.write((char*)&write_mesh->num_verts, sizeof(int));

file.write((char*)&write_mesh->num_indices, sizeof(int));

file.write((char*)&write_mesh->verts[0], sizeof(obj_vert) * write_mesh->num_verts);

file.write((char*)&write_mesh->indices[0], sizeof(int) * write_mesh->num_indices);

// Close the file

file.close();

if(new_file != nullptr)

{

delete [] new_file;

new_file = nullptr;

}

return true;

}

[/i][/i][/i][/i][/i][/i][/i]

```
Link to comment
Share on other sites

> I tried, stupid thing keeps messing it up.

It shouldn't. What you'll have to do is go into edit mode, clear the quote entirely, type in the code blocks, then paste the text straight from the IDE into the quotes. Any time you edit the topic it's going to screw the formatting up, which is stupid in and of itself. The other alternative is to pastebin it.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...