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);
}