importing .obj file into OpenGL

Started by
8 comments, last by blueshogun96 11 years, 1 month ago

Hi everyone, when I import an .obj file I get a model looking similar to the one I want but some triangles look distorted.

this is the model

[sharedmedia=core:attachments:13638]
and this is what i get (ignore rotation)
[sharedmedia=core:attachments:13637]

declarations:


// vertex, normal, and index related declarations
GLfloat vertices[500];
GLfloat normals[540];
int indices[1300];
int vertexIndex = 0, normalIndex = 0, elementIndex = 0;

my load function:


// extracts object's vertices, indices, and normals from given file
int LoadObject( const char* filename, GLfloat vertices[], GLfloat normals[], int elements[] )
{
	// local variables
	const int MAX_CHARS_PER_LINE = 64;
	char lineBuffer[64];
	char temp[16];
	char tempFloat[16];
	FILE *objFile;
	int count;
	GLfloat coordinate; // stored in vertices
	int index;
	int charCount;
	int isVertex = -1; // -1 for normal, 1 for vertex
	int isFirstNormal = 1; // 1 for first normal, -1 for any other normal

	// open file
	fopen_s( &objFile, filename, "r" );

	// check for errors
	if ( objFile == NULL )
	{
		return 0;
	}

	// while there are lines to read
	while ( fgets( lineBuffer, MAX_CHARS_PER_LINE, objFile ) != NULL )
	{
		
		// if we are reading a vector
		if ( strncmp( lineBuffer, "v ", 2 ) == 0 )
		{

			// initialize charCount
			charCount = 0;

			// loop through each char in the line
			for ( count = 2; count < (int)strlen( lineBuffer ); count++ )
			{
				
				// if we are reading part of a float coordinate
				if ( ( lineBuffer[count] == '-' ) || ( isdigit( lineBuffer[count] ) ) || ( lineBuffer[count] == '.') )
				{
					// store this char into temp
					temp[charCount++] = lineBuffer[count];
				}

				// if we are not reading part of a float and a float exists in temp
				else if ( charCount != 0 )
				{
					// copy the float coordinate to tempFloat
					strncpy( tempFloat, temp, charCount );

					//
					tempFloat[ charCount ] = '\n';

					// store the coordinate in our vertices array
					coordinate = atof( tempFloat );
					vertices[vertexIndex++] = coordinate;

					// re-initialize charCount
					charCount = 0;
				}
			}
		}

		// if we are reading a normal
		if ( strncmp( lineBuffer, "vn ", 3 ) == 0 )
		{

			// initialize charCount
			charCount = 0;

			// loop through each char in the line
			for ( count = 3; count < (int)strlen( lineBuffer ); count++ )
			{
				
				// if we are reading part of a float coordinate
				if ( ( lineBuffer[count] == '-' ) || ( isdigit( lineBuffer[count] ) ) || ( lineBuffer[count] == '.') )
				{
					// store this char into temp
					temp[charCount++] = lineBuffer[count];
				}

				// if we are not reading part of a float and a float exists in temp
				else if ( charCount != 0 )
				{
					// copy the float coordinate to tempFloat
					strncpy( tempFloat, temp, charCount );

					//
					tempFloat[ charCount ] = '\n';

					// store the coordinate in our normals array
					coordinate = atof( tempFloat );
					normals[normalIndex++] = coordinate;

					// re-initialize charCount
					charCount = 0;
				}
			}
		}

		// if we are reading face info
		if ( strncmp( lineBuffer, "f ", 2 ) == 0 )
		{

			// initialize charCount, isVertex and isFirstNormal
			charCount = 0;
			isVertex = 1;
			isFirstNormal = 1;

			// loop through each char in the line
			for ( count = 2; count < (int)strlen( lineBuffer ); count++ )
			{
				
				// if we are reading part of an index
				if ( isdigit( lineBuffer[count] ) )
				{
					// store this char into temp
					temp[charCount++] = lineBuffer[count];
				}

				// if we are not reading part of an index and an index exists in temp
				else if ( charCount != 0 )
				{

					// if the index is a vertex
					if ( isVertex == 1 )
					{

						// copy the float coordinate to tempFloat
						strncpy( tempFloat, temp, charCount );

						//
						tempFloat[ charCount ] = '\n';

						// store the coordinate in our indices array
						index = atof( tempFloat );
						elements[elementIndex++] = (int)index;
					}

					// if the index is a normal
					else
					{

						// if this is the first normal in the line
						if ( isFirstNormal == 1 )
						{
							// copy the float coordinate to tempFloat
							strncpy( tempFloat, temp, charCount );

							//
							tempFloat[ charCount ] = '\n';

							// store the coordinate in our normals array
							index = atof( tempFloat );
							elements[elementIndex++] = (int)index;

							// switch isFirstNormal
							isFirstNormal *= -1;
						}
					}

					// switch isVertex
					isVertex *= -1;

					// re-initialize charCount
					charCount = 0;
				}
			}
		}

	}

	// close file
	fclose( objFile );

	// return ok
	return 1;
}

my draw routine:


// draw our model
	glBegin( GL_TRIANGLES );

	// go through each element
	for ( i = 0; i < elementIndex; i += 4 )
	{
		// set offsets
		normalOffset  = 3;
		vertexOffset = 3;

		// calculate index of x coordinate of current normal
		currentNormalIndex = normalOffset * ( indices[i + 1] - 1 );

		// calculate index of x coordinates of the three vertices
		firstVertexIndex = vertexOffset * ( indices[ i + 1 ] - 1 );
		secondVertexIndex = vertexOffset * ( indices[ i + 2 ] - 1 );
		thirdVertexIndex = vertexOffset * ( indices[ i + 3 ] - 1 );

		// set the normal for our triangle face
		glNormal3f( normals[ normalOffset ], 
			normals[ normalOffset + 1 ], 
			normals[ normalOffset + 2 ] );

		// set vertex 1
		glVertex3f( vertices[ firstVertexIndex ], 
			vertices[ firstVertexIndex + 1 ],
			vertices[ firstVertexIndex + 2 ]);

		// set vertex 2
		glVertex3f( vertices[ secondVertexIndex ], 
			vertices[ secondVertexIndex + 1 ],
			vertices[ secondVertexIndex + 2 ]);
		
		// set vertex 3
		glVertex3f( vertices[ thirdVertexIndex ], 
			vertices[ thirdVertexIndex + 1 ],
			vertices[ thirdVertexIndex + 2 ]);

	}
	glEnd();

The object was exported from blender using:

  • selection only (current model)
  • include normals
  • triangulate faces
  • keep vertex order

I understand that there are alternative ways to import and draw an .obj file but this will help me understand OpenGL and 3D objects better since I'm new to both 3D modelling and OpenGL.

Can someone help through this?

arigatou

EDIT: the indices are stored like this: [vector], [vector normal], [vector], [vector] for each line and I use the same vector normal for the 3 vectors to save space

Advertisement
The indices in .OBJ files are 1-based.
What is the logic behind “( indices[i + 1] - 1 )”?


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

thanks ^^ it works. my mistake. should I delete the post?

No. Others may gain insight from it.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

thanks ^^ it works. my mistake. should I delete the post?

hi, how did you fix it pls? I have a similar issue


thanks ^^ it works. my mistake. should I delete the post?

hi, how did you fix it pls? I have a similar issue


as lspiro said, the indices are 1 based in obj files, in C and C++ (and quite many other languages aswell) arrays start at 0, so instead of:
glVertex3f( vertices[ firstVertexIndex ],
vertices[ firstVertexIndex + 1 ],
vertices[ firstVertexIndex + 2 ]);

you do:
glVertex3f( vertices[ firstVertexIndex -1 ],
vertices[ firstVertexIndex ],
vertices[ firstVertexIndex + 1 ]);

(if you use vertex arrays or VBOs you do the equivalent operation where you initialize your array/vbo instead)
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

thanks ^^ it works. my mistake. should I delete the post?

hi, how did you fix it pls? I have a similar issue

// calculate index of x coordinate of current normal
currentNormalIndex = normalOffset * ( indices[i + 1] - 1 );

// calculate index of x coordinates of the three vertices
firstVertexIndex = vertexOffset * ( indices[ i + 1 ] - 1 ); <<<<< here, replace with ( indices[ i ] - 1 )
secondVertexIndex = vertexOffset * ( indices[ i + 2 ] - 1 );
thirdVertexIndex = vertexOffset * ( indices[ i + 3 ] - 1 );

that's it. rest of the code is fine, but could be cleaned up ^ ^'

thanks ^^ it works. my mistake. should I delete the post?

hi, how did you fix it pls? I have a similar issue

as lspiro said, the indices are 1 based in obj files, in C and C++ (and quite many other languages aswell) arrays start at 0, so instead of:
glVertex3f( vertices[ firstVertexIndex ],
vertices[ firstVertexIndex + 1 ],
vertices[ firstVertexIndex + 2 ]);

you do:
glVertex3f( vertices[ firstVertexIndex -1 ],
vertices[ firstVertexIndex ],
vertices[ firstVertexIndex + 1 ]);

(if you use vertex arrays or VBOs you do the equivalent operation where you initialize your array/vbo instead)

You can go to the root of the problem instead and do -1 when storing:

Store indices:


// if the index is a normal
else
{

	// increment currentNormal
	currentNormal++;

	// if this is the third normal in the line
	if ( currentNormal == 3 )
	{
		// copy the float coordinate to tempFloat
		strncpy_s( tempFloat, 16, temp, charCount );

		//
		tempFloat[ charCount ] = '\n';

		// store the coordinate in indices array
		index = atoi( tempFloat );
		elements[(*elementIndex)++] = index - 1;

		// set current normal to 0
		currentNormal = 0;
	}
} 

Draw:


// calculate index of x coordinate of current normal
currentNormalIndex = normalOffset * ( indices[i + 3] );

// calculate index of x coordinates of the three vertices
firstVertexIndex = vertexOffset * ( indices[ i ] );
secondVertexIndex = vertexOffset * ( indices[ i + 1 ] );
thirdVertexIndex = vertexOffset * ( indices[ i + 2 ] );

looks much cleaner! ^w^

Hi,

I am trying to import chess pieces from 3dsmax to opengl.

However, I am quite new to opengl and it has been a big challenge so far.

Any help will be appreciated?

Hi,

I am trying to import chess pieces from 3dsmax to opengl.

However, I am quite new to opengl and it has been a big challenge so far.

Any help will be appreciated?

I recommend starting a new thread for this question, then it can get more specific attention.

I think the proper word you want to use is "export". Export your 3D model to a 3D format that's well documented such as collada (.dae), object (.obj), .3ds, etc. I don't have 3dsmax so I don't know what types of exports it supports; I use Blender. Depending on the format you choose to export, you may have to write your own loader for the file and parse it manually, then format the vertex data into a compatible format that OpenGL can use.

The answer to your question is not a simple one. Do you have a specific export format in mind? And how far with OpenGL have you gotten already? You may be biting off more than you can chew; I'm asking because I don't quite understand what is so difficult for you.

Shogun.

This topic is closed to new replies.

Advertisement