![]() |
|
|
|
| ||||||
|
Welcome to the The ProgrammersTalk Community forums. You are currently viewing our boards as a guest which gives you limited access to view most discussions and access our other features. By joining our free community you will have access to post topics, communicate privately with other members (PM), respond to polls, upload content and access many other special features. Registration is fast, simple and absolutely free so please, join our community today! If you have any problems with the registration process or your account login, please contact contact us. |
| Tags: loader, obj |
![]() |
![]() | | LinkBack | Thread Tools | Display Modes | ![]() |
| ||||
| How to make a basic .obj loader First I'll start with the basic layout of an .obj file. If you don't have some basic knowledge of OpenGL it's best that you get some, you'll only really need knowledge on how to draw basic polygons. You should also know how to setup a basic OpenGL window. You'll also need the glut libary which can be found here: http://www.xmission.com/~nate/glut.html # a comment Normally at the top of the file there's a comment saying which exporter made the file and what not, we just ignore these because well they're comments. v x y z This tells us that the following information is a vertex, one point of our face. If it's the first vertex in our file, it's vertex 1, if it's the 10th vertex in the file, it's vertex 10. We'll see why this is relevant later on. vt u v [w] This tells us that the following information is a texture coordinate, I haven't tried to get these working as I haven't needed them so you'll have to use your own brains to work them out. Again there position corresponds to what vertex they effect. vn x y z This tells us that the following information is a vertex normal. A normal is a vector perpendicular to another vector. These are needed for correct lighting. Again if it's the first normal in our file it's the normal of vertex 1, if it's the 100th normal, it's the normal of vertex 100. f v1 v2 v3 or f v1//vn1 v2//vn1 v3//vn3 or f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 This tells us information about the face, this is what brings everything together, I will only be covering f v1 v2 v3 because well I haven't worked out a way to use the others yet (hehe). It's basically a whole number saying which vertex to use, eg: f 5 2 6 is telling us that one corner of our triangle is vertex 5 another corner is vertex 2 and the last is vertex 6. (Remember our vertices are just points, when we specify 3 points together in OpenGL after glBegin(GL_TRIANGLES) it connects them up to make a triangle.) Here's a basic example of a .obj file, a simple cube: Code: # Blender3D v245 OBJ File: # www.blender3d.org v 1.000000 -1.000000 -1.000000 v 1.000000 -1.000000 1.000000 v -1.000000 -1.000000 1.000000 v -1.000000 -1.000000 -1.000000 v 1.000000 1.000000 -1.000000 v 0.999999 1.000000 1.000001 v -1.000000 1.000000 1.000000 v -1.000000 1.000000 -1.000000 f 5 1 4 f 5 4 8 f 3 7 8 f 3 8 4 f 2 6 3 f 6 7 3 f 1 5 2 f 5 6 2 f 5 8 6 f 8 7 6 f 1 2 3 f 1 3 4 First we need a way to get the information from the line, there's other ways, but I prefer using this (Thanks to Bench): Code: #include <vector>
#include <sstream>
using namespace std;
string getWord(string Line, int Pos)
{
vector<string> Vec;
stringstream ss(Line);
string Word, a;
while(ss >> Word)
Vec.push_back(Word);
if(Pos > Vec.size()-1) //Check whether it's in range
return "";
else
{
try { a = Vec.at(Pos); } //Just to be safe
catch(...) { a = ""; } //I'm not sure what to catch
return a; //Return the word
}
} Code: int convertToInt(string Num)
{
istringstream i(Num);
int x;
if(!(i >> x))
throw 0;
return x;
}
float convertToFloat(string Num)
{
istringstream i(Num);
float x;
if(!(i >> x))
throw 0;
return x;
} First we need a way to store all the information about our class! We'll need something to hold our x, y and z coordinates! Code: struct Vector {
float x, y, z;
}; Now we need something to hold our Vertex information, remember we have the vertex position and then the normal! Code: struct Vertex {
Vector Pos;
Vector Normal;
}; Code: struct Triangle {
int v1, v2, v3; //One for each of our corners!
}; First we declare our class Code: class Model
{ Code: private: //So we can't change them willy nilly
Triangle Triangles[50000]; //As .obj files don't tell us how many faces
//we have, we have to take a guess, feel free to change the amount for
//bigger models, the most I've come across is 130k
Vertex Verticies[50000]; //Same as above
int TriangleCount; //Keep track of the amount of triangles we have
int VertexCount; //Keep track of the amount of Vertices we have
int NormalCount; //Keep track of the amount of normals we have
bool Loaded; //So we know whether it's been loaded of not Code: public: //So we can access the functions
Model(); //Constructor
int Load(const char* Filename);//The function to load, it's int so we can exit the function easily if there's an error!
void Draw(void); //The function to draw
}; Code: Model::Model()
{
VertexCount = 1; //Start on 1
TriangleCount = 1; //Start on 1
NormalCount = 1; //Start on 1
Loaded = false; //We haven't loaded a model yet!
} Now for the loading! It's really quite simple so don't run away now! Code: int Model::Load(const char *Filename)
{ Code: ifstream F; //Our file
string Line; //The current line of the file Next, we open our file and check if it opened! Code: F.open(Filename, ios::in);
if(F.fail()) //Has it failed to open
{
cout << "Error opening \"" << Filename << "\"" << endl; //Send an error message
return 0; //Exit the function
} Next we check if we've already got a model loaded, if so, we reset the Triangle, Vertex and Normal count so we don't have both models loaded at once! You can remove this line and see what happens if you want, it won't break, promise! Code: if(Loaded) //If loaded is true
{
VertexCount = 1; //Reset
TriangleCount = 1; //Reset
NormalCount = 1; //Reset
} First, we start our while loop, standard stuff really. Code: while(!F.eof())
{ Code: getline(F, Line); Thanks to the functions I mentioned earlier we can do that easily! Code: if(getWord(Line, 0) == "v") //If the first word is v
{ Code: if(VertexCount > 50000) break; //If we're exceeding our 50000 we'd better stop
Verticies[VertexCount].Pos.x = convertToFloat(getWord(Line, 1)); //Set our x location to the second word of the line.
Verticies[VertexCount].Pos.y = convertToFloat(getWord(Line, 2)); //Set our y variable to the thrid word of the line.
Verticies[VertexCount].Pos.z = convertToFloat(getWord(Line, 3)); //Set our z variable to the fourth word of the line.
VertexCount++; //Next vertex please! Code: }
else if(getWord(Line, 0) == "vn") //If it wasn't v is it vn?
{
if(NormalCount > 50000) break; //Are we about to exceed the limit?
Verticies[NormalCount].Normal.x = convertToFloat(getWord(Line, 1));
Verticies[NormalCount].Normal.y = convertToFloat(getWord(Line, 2));
Verticies[NormalCount].Normal.z = convertToFloat(getWord(Line, 3));
NormalCount++; //Next Normal Please!
}
else if(getWord(Line, 0) == "f") //If it wasn't v or vn then is it a face?
{
if(TriangleCount > 50000) break; //Check to see if we're exceeding limit again
Triangles[TriangleCount].v1 = convertToInt(getWord(Line, 1));
Triangles[TriangleCount].v2 = convertToInt(getWord(Line, 2));
Triangles[TriangleCount].v3 = convertToInt(getWord(Line, 3));
TriangleCount++; //Next triangle please!
}
} //Close Loop! Code: F.close();
Loaded = true;
cout << "Triangles: " << TriangleCount-1 << endl;
cout << "Vertecies: " << VertexCount-1 << endl;
cout << "Normals: " << NormalCount-1 << endl;
} Last edited by MrPickle : 03-16-2008 at 06:21 AM. |
| |
| ||||
| That's our loading function done! Hold your horses, don't try and compile it yet we're not done! We still have to draw our model! Code: void Model::Draw(void) //declare our function
{
if(Loaded) //Check if it's loaded!
{ Code: glBegin(GL_TRIANGLES); //Say we're using triangles!
for(int i = 1; i < TriangleCount; i++) //For each face
{
glNormal3f(Verticies[Triangles[i].v1].Normal.x, Verticies[Triangles[i].v1].Normal.y, Verticies[Triangles[i].v1].Normal.z);
glVertex3f(Verticies[Triangles[i].v1].Pos.x, Verticies[Triangles[i].v1].Pos.y, Verticies[Triangles[i].v1].Pos.z);
glNormal3f(Verticies[Triangles[i].v2].Normal.x, Verticies[Triangles[i].v2].Normal.y, Verticies[Triangles[i].v2].Normal.z);
glVertex3f(Verticies[Triangles[i].v2].Pos.x, Verticies[Triangles[i].v2].Pos.y, Verticies[Triangles[i].v2].Pos.z);
glNormal3f(Verticies[Triangles[i].v3].Normal.x, Verticies[Triangles[i].v3].Normal.y, Verticies[Triangles[i].v3].Normal.z);
glVertex3f(Verticies[Triangles[i].v3].Pos.x, Verticies[Triangles[i].v3].Pos.
}
glEnd(); //Stop drawing! Now we must close the function and if Code: } } If you used the starting code I provided you can toggle the grid on and off by pressing g and load a new model with l. Download here! Tell me if you're having problems and I'll help you! Last edited by MrPickle : 03-16-2008 at 06:18 AM. |
| The Following User Says Thank You to MrPickle For This Useful Post: | ||
ccoonen (03-16-2008) | ||
| |||
| Excellent, thanks buddy! I can't wait ![]() __________________ Day Cares | Golf Courses | Disc Golf Courses | Campgrounds | Ice Rinks | Paintball Fields | Dentists | Plastic Surgeons | Aging Jokes Catholic Churches | Lutheran Churches | Methodist Churches | Episcopal Churches | Clean Jokes |
| |||
| errors in compilation Hi I am using Visual Studio 2005 v8.0. and I have some errors in the routine -> OpenFileDialog(char FileName[]) Here is the errors Warning 1 warning C4018: '>' : signed/unsigned mismatch 58 Error 2 error C2440: '=' : cannot convert from 'char [512]' to 'LPWSTR' 178 Error 3 error C2440: '=' : cannot convert from 'const char [10]' to 'LPCWSTR' 180 Error 4 error C2664: 'GetCurrentDirectoryW' : cannot convert parameter 2 from 'char [512]' to 'LPWSTR' 183 Error 5 error C2664: 'SetCurrentDirectoryW' : cannot convert parameter 1 from 'char [512]' to 'LPCWSTR' 193 Error 6 error C2664: 'SetCurrentDirectoryW' : cannot convert parameter 1 from 'char [512]' to 'LPCWSTR' 197 The comments in the code mention to not ask you how it works, but I would like to know if it works for you, what version do u have and where did you get that code, thanks a lot in advance |
![]() |
| Thread Tools | |
| Display Modes | |
| |