Nieprawidłowe wczytanie obiektu z .obj

0

Napisałem funkcję do wczytywania obiektów 3D w formacie OBJ z materiałami MTL. Zamiast właściwego obiektu wyświetla się origami w 3D. To tak, jakby trójkąty miały 1 wspólny wierzchołek, ale nie wszystkie. Sprawdzam początkowe wartości - wszystko się zgadza.

typedef struct _vertex {
	float x,y,z;
	float nx,ny,nz;
	float r,g,b;
} vertex;

typedef struct _object {
	int n;
	vertex * vertices;
	unsigned int * indices;
} object;

typedef struct _material {
	unsigned int id;
	float red;
	float green;
	float blue;
} material;

material* loadmtl(char *filename, unsigned int *n)
{
	char line[32];
	int m = -1;
	material *mat;
	FILE *file;
	file = fopen(filename, "r");			// Open file
	setvbuf(file, NULL, _IOFBF, 1024*2);	// Assume 2 KB buffer
	while(!feof(file))
	{
		fgets(line, 32, file);
		switch(line[0])
		{
			case 'n': ++(*n); break;  // tu zliczamy materiały
		}
	}
	rewind(file);
	mat = (material*)calloc(*n, sizeof(material));
	while(!feof(file))
	{
		fgets(line, 32, file);
		switch(line[0])
		{
			case 'n': sscanf(line+12, "%u", &mat[++m].id); break;
			case 9: if(line[1] == 'K' && line[2] == 'a') sscanf(line+3, "%f %f %f", &mat[m].red, &mat[m].green, &mat[m].blue); break;
		}
	}
	fclose(file);
	return mat;
}


void loadobj(char *filename, object * o)
{
	int vc=0, fc=0, nc=0, tc=0, v=0, n=0, t=0, f=0, sc=0, s=0;
	unsigned int v1,v2,v3,n1,n2,n3,t1,t2,t3,mid,mn=0,i,*faces;
	float *vertices, *normals, *textures;
	char line[64], mtllib[32];
	material *mats, *mat;
	vertex *tmp;
	FILE *file;
	file = fopen(filename, "r");			// Open file
	setvbuf(file, NULL, _IOFBF, 1024*256);	// Assume 256 KB buffer
	while(!feof(file))
	{
		fgets(line, 64, file);
		switch(line[0])
		{
			case 'v': switch(line[1])
			{
				case 'n': ++nc; break;  // tu zliczamy
				case 't': ++tc; break;
				default: ++vc;
			}
			break;
			case 'f': ++fc; break;
		}
	}
	rewind(file);
	o->n = fc;
	vertices = (GLfloat*)calloc(3*vc, sizeof(GLfloat));
	normals = (GLfloat*)calloc(3*nc, sizeof(GLfloat));
	textures = (GLfloat*)calloc(2*tc, sizeof(GLfloat));
	tmp = (vertex*)calloc(3*fc, sizeof(vertex));
	o->indices = (unsigned int*)calloc(3*fc, sizeof(unsigned int));
	while(!feof(file))
	{
		fgets(line, 64, file);
		switch(line[0])
		{
			case 'v': switch(line[1])
			{
				case 'n': sscanf(line+2, "%f %f %f", &normals[n], &normals[n+1], &normals[n+2]); n+=3; break;
				case 't': sscanf(line+2, "%f %f %*f", &textures[t], &textures[t+1]); t+=2; break;
				default: sscanf(line+2, "%f %f %f", &vertices[v], &vertices[v+1], &vertices[v+2]); v+=3;
			}
			break;
			case 'f':
				sscanf(line+2, "%u/%u/%u %u/%u/%u %u/%u/%u", &v1, &t1, &n1, &v2, &t2, &n2, &v3, &t3, &n3);
				tmp[s].x = vertices[3*v1-3];
				tmp[s].y = vertices[3*v1-2];
				tmp[s].z = vertices[3*v1-1];  // sprawdzam debuggerem - zgadza się
				tmp[s].nx = normals[3*n1-3];
				tmp[s].ny = normals[3*n1-2];
				tmp[s].nz = normals[3*n1-1];
				tmp[s].r = mat->red;
				tmp[s].g = mat->green;
				tmp[s].b = mat->blue;
				s++;
				tmp[s].x = vertices[3*v2-3];
				tmp[s].y = vertices[3*v2-2];
				tmp[s].z = vertices[3*v2-1];
				tmp[s].nx = normals[3*n2-3];
				tmp[s].ny = normals[3*n2-2];
				tmp[s].nz = normals[3*n2-1];
				tmp[s].r = mat->red;
				tmp[s].g = mat->green;
				tmp[s].b = mat->blue;
				s++;
				tmp[s].x = vertices[3*v3-3];
				tmp[s].y = vertices[3*v3-2];
				tmp[s].z = vertices[3*v3-1];
				tmp[s].nx = normals[3*n3-3];
				tmp[s].ny = normals[3*n3-2];
				tmp[s].nz = normals[3*n3-1];
				tmp[s].r = mat->red;
				tmp[s].g = mat->green;
				tmp[s].b = mat->blue;
				s++;
				break;
			case 'm':
				sscanf(line+7, "%s", mtllib);
				mats = loadmtl(mtllib, &mn);  // wczytujemy materiały
				break;
			case 'u':
				sscanf(line+12, "%u", &mid);
				for(i=0; i<mn; i++)
				{
					if(mid == mats[i].id)
					{
						mat = &mats[i];  // ustawiamy materiał
					}
				}
				break;
		}
	}
	o->vertices = tmp;  // przypisanie wskaźnika też działa
	fclose(file);
}

object obiekt;

// a może tu są błędy?
void display()
{
	glEnableClientState(GL_VERTEX_ARRAY);
	glVertexPointer(3, GL_FLOAT, sizeof(obiekt), &obiekt.vertices->x);
	glEnableClientState(GL_NORMAL_ARRAY);
	glNormalPointer(GL_FLOAT, sizeof(obiekt), &obiekt.vertices->nx);
	glEnableClientState(GL_COLOR_ARRAY);
	glColorPointer(3, GL_FLOAT, sizeof(obiekt), &obiekt.vertices->r);
	glDrawArrays(GL_TRIANGLES, 0, obiekt.n);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
}

// wczytywanie
void init()
{
	loadobj("obiekt.obj", &obiekt);
}
0

Szczerze mówiąc to widzę tu niezły bałagan, przydałby się potężny refactoring żeby doprowadzić to do czytelnej dla człowieka postaci.
Szkoda że nie pokazałeś reszty kodu, ważne jest wszystko co jest robione podczas renderingu.
Display nie jest z pewnością kompletny, nie widzę czyszczenia ekranu, włączenia z-bufora itp. Używasz shaderów?
Dopóki nie pokażesz wszystkiego ciężko będzie ci pomóc.

Teraz kilka sugestii. Przygotuj jakiś prosty obj złożony z kilku trójkątów dla którego coś się psuje.
Przepuść go przez loader i pokaż zawartość tego obj-ta na forum.
Następnie pokaż zawartość wszystkich tablic użytych w display. Warto też przechwytywać informacje o błędach za pomocą glGetError.
Na razie tyle.

0

ja widzę błąd tu:

while(!feof(file))

Efekt jest taki, że ostatnią linię przetwarzasz 2 razy.
Popraw to na:

while(fgets(line, 64, file))
        {
                switch(line[0]) { 
....

1 użytkowników online, w tym zalogowanych: 0, gości: 1