Jump to content

  • Log In with Google      Sign In   
  • Create Account

[noob]How to Draw from .OBJ in memory?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 mynameisnafe   Members   -  Reputation: 252

Like
0Likes
Like

Posted 04 September 2012 - 09:58 AM

Hi There

I read this a while ago and implemented my own version, as part of a model class. It's a really useful thread!

http://www.gamedev.n...ding-in-detail/

However, as someone in the thread points out: 'How do I go about drawing all this sh*t in OpenGL?'

I have learned that .obj indices start at 1, not 0. Can anybody help me apply this nugget of information to the following render method, which draws triangles from memory (stored in memory as in the thread linked above).

Many thanks in advance, I've been stuck on this forever and can't seem to find anything online about it.

Once I/we figure this out, I can get on with my project. Posted Image

As Turvold said, 'talk is cheap, show me the code'.

void GLModel::RenderMesh( Colour3 c ) {
glPushMatrix();

  glTranslatef(pos.x, pos.y, pos.z);
  glColor3f( c.r, c.g, c.b );
  glLineWidth(1.0);

  glBegin(GL_TRIANGLES);
   for ( int i = 0; i < mesh.noTriangles; i++ ) { //for each triangle in the list
	 Vector3D vpos; Normal3D npos;
	 // this vertex is the said triangle, verts attached
	 vpos.x = mesh.vertices[ mesh.triangleList[i].Vertex[0] ].x;
	 vpos.y = mesh.vertices[ mesh.triangleList[i].Vertex[1] ].y;
	 vpos.z = mesh.vertices[ mesh.triangleList[i].Vertex[2] ].z;
	 // this vertex is the said triangle, normals attached
	 npos.x = mesh.normals[ mesh.triangleList[i].Normal[0] ].x;
	 npos.y = mesh.normals[ mesh.triangleList[i].Normal[1] ].y;
	 npos.z = mesh.normals[ mesh.triangleList[i].Normal[2] ].z;
  
	 glVertex3f(vpos.x, vpos.y, vpos.z);
	 //glNormal3f(npos.x, npos.y, npos.z);
   } // i++
  glEnd();
glPopMatrix();
}

Please help me! - Apparently I can't upload .cpp files, if anyone wants to see the whole class, leave a comment and I'll post it Posted Image

Sponsor:

#2 carangil   Members   -  Reputation: 490

Like
4Likes
Like

Posted 04 September 2012 - 02:10 PM

I see a couple of problems here:

1. The glNormal3f should be put before the call to glVertex3f, otherwise all the normals will be off by 1.
2. For each triangle you are only pushing 1 vertex. You wrote:

// this vertex is the said triangle, verts attached
		 vpos.x = mesh.vertices[ mesh.triangleList[i].Vertex[0] ].x;
		 vpos.y = mesh.vertices[ mesh.triangleList[i].Vertex[1] ].y;  
		 vpos.z = mesh.vertices[ mesh.triangleList[i].Vertex[2] ].z;
		 // this vertex is the said triangle, normals attached
		 npos.x = mesh.normals[ mesh.triangleList[i].Normal[0] ].x;
		 npos.y = mesh.normals[ mesh.triangleList[i].Normal[1] ].y;
		 npos.z = mesh.normals[ mesh.triangleList[i].Normal[2] ].z;

		 glVertex3f(vpos.x, vpos.y, vpos.z);
		 //glNormal3f(npos.x, npos.y, npos.z);

and I think you meant:

for (j=0;j<3;j++)
{
		 // this vertex is the said triangle, verts attached
		 vpos.x = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].x;
		 vpos.y = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].y;
		 vpos.z = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].z;
		 // this vertex is the said triangle, normals attached
		 npos.x = mesh.normals[ mesh.triangleList[i].Normal[j] ].x;
		 npos.y = mesh.normals[ mesh.triangleList[i].Normal[j] ].y;
		 npos.z = mesh.normals[ mesh.triangleList[i].Normal[j] ].z;
		 glNormal3f(npos.x, npos.y, npos.z);
		 glVertex3f(vpos.x, vpos.y, vpos.z);
}

What you did was take the x coord of the 1st vertex, and y coord of the 2nd vertex and the z coord of the 3rd vertex!

Also, BTW, as soon as you get this rendering correctly, the 1st thing you should do is render with a VBO, or, at a minimum, a vertex array.
The format you have already is kind of similar to a vertex array, you just need to rearrange the data a little bit.

edit:

What I do when I load on obj file: In many cases, obj files use the same vertex/normal/texcoord index: i.e. 1/1/1 4/4/4 10/10/10, etc. Not always! Sometimes some models will re-use texcoord indices, resulting in off vertices like 10/5/10, 11/6/11, etc. OpenGL Vertex Arrays / VBO doesn't allow mis-matched vertices like this. So when I load an OBJ file, I make a map from 'obj file' vertex spec to opengl vertex index, copying when necessary. So, 1/1/1 and 1/1/2 are 2 completely different vertices in GL.

Edited by DracoLacertae, 04 September 2012 - 02:20 PM.


#3 larspensjo   Members   -  Reputation: 1561

Like
2Likes
Like

Posted 05 September 2012 - 02:16 AM

Also, BTW, as soon as you get this rendering correctly, the 1st thing you should do is render with a VBO, or, at a minimum, a vertex array.
The format you have already is kind of similar to a vertex array, you just need to rearrange the data a little bit.

I agree. Notice that you are using deprecated legacy OpenGL: http://www.opengl.org/wiki/Legacy_OpenGL. Better get it right now, until it is too late.
Current project: Ephenation.
Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

#4 mynameisnafe   Members   -  Reputation: 252

Like
0Likes
Like

Posted 07 September 2012 - 12:06 PM

Thank you guys! You are heros! Sorry it's taken me so long to get back to you.

Omg I see my error now. I'm just going to try it as you suggest before I post this..

Here's the code I'm trying:
void GLModel::RenderMesh( Colour3 c ) {
glPushMatrix();

  glTranslatef(pos.x, pos.y, pos.z);
  glColor3f( c.r, c.g, c.b );
  glLineWidth(1.0);

  glBegin(GL_TRIANGLES);
   for ( int i = 0; i < mesh.noTriangles; i++ ) { //for each triangle in the list
	 Vector3D vpos; Normal3D npos;
	  for( int j = 0; j < 3; j++ ) {
	  // this vertex is the said triangle, verts attached
	  vpos.x = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].x;
	  vpos.y = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].y;
	  vpos.z = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].z;
	  // this vertex is the said triangle, normals attached
	  npos.x = mesh.normals[ mesh.triangleList[i].Normal[j] ].x;
	  npos.y = mesh.normals[ mesh.triangleList[i].Normal[j] ].y;
	  npos.z = mesh.normals[ mesh.triangleList[i].Normal[j] ].z;
	  glNormal3f(npos.x, npos.y, npos.z);  
	  glVertex3f(vpos.x, vpos.y, vpos.z);
	 } //j++
   } // i++
  glEnd();
glPopMatrix();
}

For a model of a car i have it renders nothing? For a box I have it is a bit crazy-looking.

I'm using legacy OGL? What's the latest version these days?

Okay I'll move the normals to be processed before hand - I hadn't been using them ( :/ )

Okay

as soon as you get this rendering correctly, the 1st thing you should do is render with a VBO, or, at a minimum, a vertex array.


I thought I was rendering from a vertex array?

Okay, if you guys are willing to delve deeper, here is the code thats responsible for this, from file load to render. I really appreciate any help as I know I need tris before I can texture, have any use for lighting, worry about mtls, etc etc. I'm stuck on the first hurdle Posted Image

In winmain, we have a call to this function, with the path to the model:

void GLModel::AllocateMesh( string path ){
// Step 1 - Count the Elements in the Mesh
  string line;	// our line to read
  ifstream rfile(path); // open it up from filepath given
  if( rfile.is_open() ) { //while open
   while ( rfile.good() ) { //while not EOF or Error
	getline (rfile, line); //get content..
	// update the count held by the mesh given to us
	  if( line.substr(0,1)  == "#" )  {/* do nothing for comments */  }
	else if( line.substr(0,5)  == "mtllib") {/* this is the objects material */ }
	else if( line.substr(0,2)  == "g ")  {/* and do nowt for groups */  }
	else if( line.substr(0,2)  == "vn")  { mesh.noNormals++;  }
	else if( line.substr(0,2)  == "vt")  { mesh.noTexCoords++;  }
	else if( line.substr(0,2)  == "v ")  { mesh.noVerts++;   }
	else if( line.substr(0,2)  == "f ")  { mesh.noTriangles++;  }
   }
  }

  rfile.close(); //housekeeping
// Step 2 - Allocate the memory according to the count
  mesh.vertices	 = (Vertex3D*) malloc(sizeof(Vertex3D)*  mesh.noVerts);
  mesh.normals	  = (Normal3D*) malloc(sizeof(Normal3D)*  mesh.noNormals);
  mesh.texcoords	= (UV*)  malloc(sizeof(UV)	  *  mesh.noTexCoords);
  mesh.triangleList = (Triangle*) malloc(sizeof(Triangle)*  mesh.noTriangles);
}

This is followed directly by a call to this function which reads the file:

void GLModel::LoadMeshData( string path )  {
  string line;
  ifstream rfile(path);
  int ni, vi, ti, fi; //counters: normals, verts, texcoords, faces
  ni = 0; vi = 0; ti = 0; fi = 0;
  if ( rfile.is_open() ) { //if file is open
   while ( !rfile.eof() ) { //til end of file:
	getline(rfile, line);
	istringstream currentline(line);
	string temp, f1, f2, f3;
	/* Vertex Normals */
	if(line.substr(0,2) == "vn")  {
	 currentline >> temp >>f1 >> f2 >> f3;
	 mesh.normals[ni].x = atof( f1.c_str() );
	 mesh.normals[ni].y = atof( f2.c_str() );
	 mesh.normals[ni].z = atof( f3.c_str() );
	 ni++; //next normal
	}
	/* Vertex texture coordinates */
	else if(line.substr(0,2) == "vt") {
	 currentline >> temp >>f1 >> f2;
	 mesh.texcoords[ti].s = atof( f1.c_str() );
	 mesh.texcoords[ti].t = atof( f2.c_str() );
	 ti++; //next texcoords
	}
	/* Vertex */
	else if(line.substr(0,1) == "v") {
	 currentline >> temp >>f1 >> f2 >> f3;
	 mesh.vertices[vi].x = atof( f1.c_str() );
	 mesh.vertices[vi].y = atof( f2.c_str() );
	 mesh.vertices[vi].z = atof( f3.c_str() );
	 vi++; //next vertex
	}
	/* Triangle/Face*/
	else if(line.substr(0,1) == "f") {
	 string temp;
	 currentline >> temp >>f1 >> f2 >> f3;
	
	 int sPos = 0;
	 int ePos = 0;
	
	 ePos = f1.find_first_of("/");
	 //we have a line with the format of "f %d/%d/%d %d/%d/%d %d/%d/%d"
	 if(ePos != string::npos) {
	  temp = f1.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].Vertex[0] = atoi( temp.c_str() ) - 1;
	  sPos = ePos + 1;
	  ePos = f1.find( "/", sPos );
	  temp = f1.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].Vertex[1] = atoi( temp.c_str() ) - 1;
	  sPos = ePos + 1;
	  ePos = f1.length();
	  temp = f1.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].Vertex[2] = atoi( temp.c_str() )- 1;
	 } //end triangle vertex data
	 sPos = 0;
	 ePos = f2.find_first_of("/");
	 if(ePos != string::npos) {
	  temp = f2.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].TexCoord[0] = atoi( temp.c_str() ) - 1;
	  sPos = ePos + 1;
	  ePos = f2.find("/", sPos + 1);
	  temp = f2.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].TexCoord[1] = atoi( temp.c_str() ) - 1;
	  sPos = ePos + 1;
	  ePos = f2.length();
	  temp = f2.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].TexCoord[2] = atoi( temp.c_str() ) - 1;
	 } //end triangle texcoord data
	 sPos = 0;
	 ePos = f3.find_first_of("/");
	 if(ePos != string::npos) {
	  temp = f3.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].Normal[0] = atoi ( temp.c_str() ) - 1;
	  sPos = ePos + 1;
	  ePos = f3.find("/", sPos + 1);
	  temp = f3.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].Normal[1] = atoi( temp.c_str() ) - 1;
	  sPos = ePos + 1;
	  ePos = f3.length();
	  temp = f3.substr(sPos, ePos - sPos);
	  mesh.triangleList[fi].Normal[2] = atoi( temp.c_str() ) - 1;
	 } //end triangle normal data
	 fi++; //next face
	} //end triangle data
   } //end while not end of file
  } //end if file is open
  rfile.close(); //housekeeping
}//end LoadMeshData

Then the model is ready to draw in Render() with this code:

//draw
  //theScene.theModel->RenderVerts( c ); //and render the model mesh vert by vert
  theScene.theModel->RenderMesh( b ); //and render the model mesh tri by tri

Which calls (and which you've seen):

void GLModel::RenderMesh( Colour3 c ) {
glPushMatrix();

  glTranslatef(pos.x, pos.y, pos.z);
  glColor3f( c.r, c.g, c.b );
  glLineWidth(1.0);

  glBegin(GL_TRIANGLES);
   for ( int i = 0; i < mesh.noTriangles; i++ ) { //for each triangle in the list
	 Vector3D vpos; Normal3D npos;
	  for( int j = 0; j < 3; j++ ) {
	  // this vertex is the said triangle, verts attached
	  vpos.x = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].x;
	  vpos.y = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].y;
	  vpos.z = mesh.vertices[ mesh.triangleList[i].Vertex[j] ].z;
	  // this vertex is the said triangle, normals attached
	  npos.x = mesh.normals[ mesh.triangleList[i].Normal[j] ].x;
	  npos.y = mesh.normals[ mesh.triangleList[i].Normal[j] ].y;
	  npos.z = mesh.normals[ mesh.triangleList[i].Normal[j] ].z;
	  glNormal3f(npos.x, npos.y, npos.z);  
	  glVertex3f(vpos.x, vpos.y, vpos.z);
	 } //j++
   } // i++
  glEnd();
glPopMatrix();
}

Edit: This is what the box looks like: Grey is the clear-colour, white is the triangles:


Capture1.PNG

#5 carangil   Members   -  Reputation: 490

Like
1Likes
Like

Posted 10 September 2012 - 04:56 PM

I thought I was rendering from a vertex array?


You are rendering from an array of vertices, but that's not an OpenGL Vertex Array. If you arrange the data just right, you can call glVertexPointer, glNormalPointer, and glTexCoordPointer, and just hand it a pointer to your data. Then you just call glDrawElements or glDrawArrays, depending on what you really want to do. This is will speed things up just because instead of individual calls to glVertex3f, you it's all done internally. Later, the next step you can take is allocate a VBO and copy it to the graphics card. You will actually keep the calls to glVertexPointer, etc, except they will be offsets to inside the VBO.

I was going to say make sure you ' - 1' from all the indices, because OBJ files start with '1' and C starts with '0'. But it looks like you already did that.

Try rendering an OBJ file with just a single face in it. If that works, the rest should :)

And instead of rendering, just printf what 'it' thinks the data is. You will probably find that you did something slightly wrong when you cut up the strings you read from the file. Can you put up one of your obj files?

#6 mynameisnafe   Members   -  Reputation: 252

Like
0Likes
Like

Posted 12 September 2012 - 08:13 AM

Looking back at the thread where the justinrwalsh dude says he saw a massive error in his code, looking at the DX11 rastertek tutorials (specifically his obj loading), and thinking about it,
I think I'm cutting the string up as v/v/v vt/vt/vt vn/vn/vn
and I think it should be v/vt/vn v/vt/vn v/vt/vn?

Thanks again for your help and advice I really appreciate it. :)

Heres the Obj file for the cube (can't upload so I'll copy paste it below) it should be fine because it's from a tutorial

# -----------------
# Start of obj file
g Box01
mtllib box.mat
usemtl box
v -62.0579 -41.4791 0.0
v 58.8424 -41.4791 0.0
v -62.0579 22.1865 0.0
v 58.8424 22.1865 0.0
v -62.0579 -41.4791 39.8714
v 58.8424 -41.4791 39.8714
v -62.0579 22.1865 39.8714
v 58.8424 22.1865 39.8714
vt 0.843206 0.405444 0.000499517
vt 0.482802 0.71377 0.9995
vt 0.478066 0.404023 0.000499636
vt 0.482802 0.716612 0.9995
vt 0.841627 0.688332 0.000499517
vt 0.482013 0.981029 0.9995
vt 0.480434 0.688332 0.000499636
vt 0.485959 0.978188 0.9995
vt 0.450102 0.00618343 0.000499547
vt 0.45247 0.509304 0.000499547
vt 0.000499517 0.512146 0.000499547
vt 0.000499517 0.512146 0.000499547
vt -0.0010791 0.00618302 0.000499547
vt 0.450102 0.00618343 0.000499547
vt 0.000499517 0.512009 0.9995
vt 0.450891 0.510588 0.9995
vt 0.45247 0.995237 0.9995
vt 0.45247 0.996658 0.9995
vt 0.000499636 0.9995 0.9995
vt 0.000499517 0.51343 0.9995
vt 0.478855 0.405444 0.000500023
vt 0.841627 0.408286 0.000499576
vt 0.83847 0.688332 0.000499576
vt 0.83847 0.688332 0.000499576
vt 0.477276 0.694016 0.000500023
vt 0.478855 0.405444 0.000500023
vt 0.482802 0.71377 0.9995
vt 0.845574 0.71377 0.999501
vt 0.844784 0.976767 0.999501
vt 0.844784 0.976767 0.999501
vt 0.482802 0.716612 0.9995
vt 0.842417 0.710929 0.9995
vt 0.843995 0.975346 0.9995
vt 0.843995 0.975346 0.9995
vt 0.478066 0.404023 0.000499636
vt 0.841627 0.688332 0.000499517
vn 0.0 0.0 -1.0
vn 0.0 0.0 -1.0
vn 0.0 0.0 1.0
vn 0.0 0.0 1.0
vn 0.0 -1.0 0.0
vn 0.0 -1.0 0.0
vn 1.0 0.0 0.0
vn 1.0 0.0 0.0
vn 0.0 1.0 0.0
vn 0.0 1.0 0.0
vn -1.0 0.0 0.0
vn -1.0 0.0 0.0
f 1/9/1 3/10/1 4/11/1
f 4/12/2 2/13/2 1/14/2
f 5/15/3 6/16/3 8/17/3
f 8/18/4 7/19/4 5/20/4
f 1/21/5 2/22/5 6/23/5
f 6/24/6 5/25/6 1/26/6
f 2/27/7 4/28/7 8/29/7
f 8/30/8 6/6/8 2/2/8
f 4/31/9 3/32/9 7/33/9
f 7/34/10 8/8/10 4/4/10
f 3/35/11 1/1/11 5/36/11
f 5/5/12 7/7/12 3/3/12
# end of obj file
# ---------------

#7 mynameisnafe   Members   -  Reputation: 252

Like
0Likes
Like

Posted 16 October 2012 - 03:25 PM

Dude!

I totally got it working!

Sorry I didn't get back to you, or keep trying earlier, uni has just started - guess what my project is.. load a .3ds model and animate it in OpenGL.

I just opened the project, looked at the loader code, saw what it was that was wrong, ran it, et viola!

I wish I could screenshot it to here for you dude, thank you anyways!

If anybody wants obj laoding code let me know!




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS