问题
I've been writing an .obj loader for openGl. The geometry loads in fine, but the normals are always messed up. I've tried to export models in 2 different programs and nothing seems to work. As far as I know, this is how you put in a normal to a GL_TRIANGLES
glNormal3fv(norm1);
glVertex3fv(vert1);
glNormal3fv(norm2);
glVertex3fv(vert2);
glNormal3fv(norm3);
glVertex3fv(vert3);
(the normals are referencing to GLfloats in the rest of the code.)
EDIT: Here is a picture of a isohedron with the broken normals
This is the full obj loader code and file:
void loadOBJFromFile(NSString *path,float movex,float movey)
{
NSString *contentns = [[NSString alloc]initWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
NSArray *pieces = [contentns componentsSeparatedByString:@"#"];
//creating the arrays to read the vertecies and normals from.
NSArray *normals = [[pieces objectAtIndex:3]componentsSeparatedByString:@"\n"];
NSArray *vertecies = [[pieces objectAtIndex:2]componentsSeparatedByString:@"\n"];
//The +1 is to make sure we ignore the texture/ material definition that vomes before the faces.
int normalCount = [[normals objectAtIndex:0]intValue]+2;
int faceCount = [[normals objectAtIndex:normalCount]intValue];
//glTranslatef(movex, 0, movey);
glBegin(GL_TRIANGLES);
{
for (int i = 0; i < faceCount;i++)
{
//aquires all the numbers in thye current face.
NSArray *currentFace = [[normals objectAtIndex:normalCount+i+1]componentsSeparatedByString:@" "];
NSArray *v1 = [[currentFace objectAtIndex:1]componentsSeparatedByString:@"//"];
NSArray *v2 = [[currentFace objectAtIndex:2]componentsSeparatedByString:@"//"];
NSArray *v3 = [[currentFace objectAtIndex:3]componentsSeparatedByString:@"//"];
//crewatres the arrays to contain the vertecies
NSArray *vertex1 = [[vertecies objectAtIndex:[[v1 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
NSArray *vertex2 = [[vertecies objectAtIndex:[[v2 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
NSArray *vertex3 = [[vertecies objectAtIndex:[[v3 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
//creates all the arrays for the normals
NSArray *normal1 = [[normals objectAtIndex:[[v1 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
NSArray *normal2 = [[normals objectAtIndex:[[v2 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
NSArray *normal3 = [[normals objectAtIndex:[[v3 objectAtIndex:1]intValue]]componentsSeparatedByString:@" "];
//creates the vertecies coordinates
GLfloat vert1[] = {[[vertex1 objectAtIndex:1]floatValue],[[vertex1 objectAtIndex:2]floatValue],[[vertex1 objectAtIndex:3]floatValue]};
GLfloat vert2[] = {[[vertex2 objectAtIndex:1]floatValue],[[vertex2 objectAtIndex:2]floatValue],[[vertex2 objectAtIndex:3]floatValue]};
GLfloat vert3[] = {[[vertex3 objectAtIndex:1]floatValue],[[vertex3 objectAtIndex:2]floatValue],[[vertex3 objectAtIndex:3]floatValue]};
//creates the normals coordinates
GLfloat norm1[] = {[[normal1 objectAtIndex:1]floatValue],[[normal1 objectAtIndex:2]floatValue],[[normal1 objectAtIndex:3]floatValue]};
GLfloat norm2[] = {[[normal2 objectAtIndex:1]floatValue],[[normal2 objectAtIndex:2]floatValue],[[normal2 objectAtIndex:3]floatValue]};
GLfloat norm3[] = {[[normal3 objectAtIndex:1]floatValue],[[normal3 objectAtIndex:2]floatValue],[[normal3 objectAtIndex:3]floatValue]};
glNormal3fv(norm1);
glVertex3fv(vert1);
glNormal3fv(norm2);
glVertex3fv(vert2);
glNormal3fv(norm3);
glVertex3fv(vert3);
}}
glEnd();
}
obj file:
#Wavefront OBJ file created by Hexagon 2
mtllib object.mtl
g Form0
usemtl def_surf_mat
# 12
v -12.533 4.78719 0
v -12.533 20.2788 0
v -7.74583 12.533 -12.533
v -7.74583 12.533 12.533
v 0 0 -7.74583
v 0 0 7.74583
v 0 25.066 -7.74583
v 0 25.066 7.74583
v 7.74583 12.533 -12.533
v 7.74583 12.533 12.533
v 12.533 4.78719 0
v 12.533 20.2788 0
# 12
vn -0.850651 -0.525731 0
vn -0.850651 0.525731 1.50014e-08
vn -0.525731 -1.50014e-08 -0.850651
vn -0.525731 0 0.850651
vn 1.50014e-08 -0.850651 -0.525731
vn -1.50014e-08 -0.850651 0.525731
vn -1.50014e-08 0.850651 -0.525731
vn 1.50014e-08 0.850651 0.525731
vn 0.525731 0 -0.850651
vn 0.525731 7.5007e-09 0.850651
vn 0.850651 -0.525731 1.50014e-08
vn 0.850651 0.525731 -1.50014e-08
usemtl def_surf_mat
20
f 7//7 8//8 12//12
f 7//7 2//2 8//8
f 8//8 4//4 10//10
f 6//6 10//10 4//4
f 7//7 9//9 3//3
f 5//5 3//3 9//9
f 6//6 5//5 11//11
f 6//6 1//1 5//5
f 1//1 4//4 2//2
f 1//1 2//2 3//3
f 12//12 11//11 9//9
f 12//12 10//10 11//11
f 2//2 4//4 8//8
f 10//10 12//12 8//8
f 12//12 9//9 7//7
f 3//3 2//2 7//7
f 3//3 5//5 1//1
f 4//4 1//1 6//6
f 9//9 11//11 5//5
f 11//11 10//10 6//6
回答1:
With the extra information you have added to the question, I'm running out of ideas. I also cannot really read Objective-C, but I'd suggest double checking all your array indexing and line counting code (perhaps print everything out to see if they are really what you expect), because parsing based on trusting the exact layout and commenting a single exporter creates looks very hairy.
Original answer:
Without seeing your loader code nor your .obj file, here's a few things to check:
- How messed up? Completely wrong, or just e.g. flat shaded instead of smooth shaded?
- Are those norm1, norm2 etc. arrays of three GLfloats?
- Do the normal arrays contain sane values (so reading them from the file works)?
- Are your normals normalized to length 1?
- Are the normals indexed correctly, i.e. do you have the correct normal for the correct vertex?
回答2:
tl;dr but--- check that the sign of your normals is correct. It is easy in the calculation to have normals pointing in the opposite direction than you intended. E.g. they are along the correct line, but point inside rather than outside. You image is consistent with that kind or error.
As far as I can remember when computing normals you have to take the vector cross product of two edges. The order in which you do the computation determines if the normal points in or out. So make sure you do the computation in the right order.
回答3:
It seems to me the OBJ file is valid, and your OBJ parser reads the vertex positions and normals correctly. So, I believe that the rendering problem comes from a different reason.
The visual artifacts in your image looks like incorrect depth test. (drawing only half of a triangle) I guess you use a subclass of NSOpenGLView in IB (Interface Builder). Make sure you enable Depth buffer of NSOpenGLView in IB Attribute Inspector (by default, it is none). A common value of depth buffer is 24 bit, plus 8 bit for Stencil buffer.
And, here are some suggestions for improving your program;
Drawing and parsing must be performed in separate functions. Because you only need to load the file once, but you may draw the model multiple times.
Use NSMutableArray for vertice, normals and faces.
Your OBJ loader is not the best way to parse OBJ file because it depends on the comment line (starting with #). I would do:
- Read line by line and store them to an array of lines.
- Loop through each line and test the followings:
- If it starts with #, then skip to parse the line.
- If it starts with "v", then add the following 3 numbers at the same line to the vertex array.
- If it starts with "vn", then add the next 3 numbers at the line to the normal array.
- If it starts with "f", add 3 face indices to the face array.
回答4:
The answer is very simple. The object was being loaded correctly from the object file. The loader code could be optimized a lot more. After calling,
glEnable(GL_CULL_FACE | GL_CULL_FACE_MODE);
EDIT I can't believe I made such a newbie mistake back then. The culling face helped, but only a bit. The real problem was I was forgetting to clear the depth buffer.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
That should solve to problem if anyone else is also experiencing the same kind of things.
Some of the problem was fixed, I actually needed to clear another buffer or pop the matrix or something. Now the lighting geometry loads in exactly how it appears in the editors and modeling programs. Thank you all for your help.
来源:https://stackoverflow.com/questions/11229110/normals-acting-weird-in-opengl