Загрузка мультитекстурированного файла .obj (c ++ / opengl)

У меня проблема с загрузкой файла .obj в приложении OpenGL.
Это модель автомобиля, изготовленная из разных секций (в которой используются разные материалы, например стекло, колеса и т. Д.)

У меня есть класс WavefrontModel, который содержит массив WavefrontSection, который имеет свои собственные вершины, нормали, материалы и координаты текс.

class WavefrontSection
{
public:
WavefrontSection(string mat_name = ""){ material = NULL; }
void ConstructVAO();
void Render();

std::vector<float> vert;
std::vector<float> tex_coord;
std::vector<float> norm;

/* these are the indexes used to build the VAO */
std::vector<int>   vert_index;
std::vector<int>   norm_index;
std::vector<int>   tex_index;

/* This is the material, containing ambient, diffuse and specular materials,
and texture */
Material *material;

/* This is the VAO */
VAO vao;
};

Материалы, нормали и вершины загружаются нормально
Вот экран:

http://postimg.org/image/ubkm0nrjj/

Проблема возникает, когда я пытаюсь применить текстуры (по одной на раздел), которые я загрузил.
Вот код загрузчика:

int WavefrontModel::load(string file,string _mtlFile)
{
gl3WriteOnStream("Loading model "+file,log_stream);

ifstream model(file.c_str());

if(!model)
{
cerr<<"Cannot open file "<<file<<endl;
gl3WriteOnStream("Cannot open file "+file,error_stream);
return -1;
}

char buf[256];
char *curr_tok = NULL;

/* These vectors stores all the vertices,normals and texture coord.
Later each section will just copy in their arrays their vertices, normals
and coords. To get the right order, i store the .obj face index information
in WavefrontSections::*_index vector */

std::vector<float> vert;
std::vector<float> norm;
std::vector<float> tex;

mtlHeader.Open(_mtlFile);  /* I open the material file, to parse all the materials */

int curr_section = 0;

while(!model.eof())
{
model.getline(buf,256);

curr_tok = strtok(buf,WHITESPACE);

if(!curr_tok || curr_tok[0] == '#')
{
continue;
}
else if(strcmp(curr_tok,"v") == 0)
{
vert.push_back(atof(strtok(NULL,WHITESPACE)));
vert.push_back(atof(strtok(NULL,WHITESPACE)));
vert.push_back(atof(strtok(NULL,WHITESPACE)));
}
else if(strcmp(curr_tok,"vn") == 0)
{
norm.push_back(atof(strtok(NULL,WHITESPACE)));
norm.push_back(atof(strtok(NULL,WHITESPACE)));
norm.push_back(atof(strtok(NULL,WHITESPACE)));
}
else if(strcmp(curr_tok,"vt") == 0)
{
tex.push_back(atof(strtok(NULL,WHITESPACE)));
tex.push_back(atof(strtok(NULL,WHITESPACE)));
}
else if(strcmp(curr_tok,"usemtl") == 0)
{
char *mtl = strtok(NULL,WHITESPACE);
bool already_pres = false;

/*I check if a sections already uses that material,
if so, i add the new indexes to that section,
otherwise I just create a new section */

for(int i = 0;i < sections.size();i++)
{
if(strcmp(mtl,sections[i]->material->name.c_str()) == 0)
{
curr_section = i;
already_pres = true;
break;
}
}if(!already_pres)
{
curr_section = sections.size();
sections.push_back(new WavefrontSection(mtl));
sections[curr_section]->material = mtlHeader.parseMaterial(mtl);
}
}
else if(strcmp(curr_tok,"f") == 0)
{
char *tmp_tok = NULL;
char *temp = NULL;

/* Here I parse model's faces. I added a '-1' to the indexes, because in the .obj
file they start from 1, but in my vectors they start from 0 */

while((tmp_tok = strtok(NULL,WHITESPACE)))
{
sections[curr_section]->vert_index.push_back(atoi(tmp_tok)-1);

if((temp = strstr(tmp_tok,"//"))) ///no texture
{
temp++;
sections[curr_section]->norm_index.push_back(atoi(++temp)-1);
}
else if((temp = strstr(tmp_tok,"/"))) ///with texture
{
sections[curr_section]->tex_index.push_back(atoi(++temp)-1);

if((temp = strstr(temp,"/")))
{
sections[curr_section]->norm_index.push_back(atoi(++temp)-1);
}
}
}
}

}cout<<"This model has got "<<sections.size()<<" sections"<<endl;

/* Now I add vertices, normals and texture coords to each section,
using the indexes that I previously stored in each section */

for(int i = 0;i < sections.size();i++)
{
for(int j = 0;j < sections[i]->vert_index.size();j++)
{
sections[i]->vert.push_back(vert[sections[i]->vert_index[j]*3]);   //x component
sections[i]->vert.push_back(vert[sections[i]->vert_index[j]*3+1]); //y component
sections[i]->vert.push_back(vert[sections[i]->vert_index[j]*3+2]); //z component
}

for(int j = 0;j < sections[i]->tex_index.size();j++)
{
sections[i]->tex_coord.push_back(tex[sections[i]->tex_index[j]*2]);   //u component
sections[i]->tex_coord.push_back(tex[sections[i]->tex_index[j]*2+1]); //v component
}

for(int j = 0;j < sections[i]->norm_index.size();j++)
{
sections[i]->norm.push_back(norm[sections[i]->norm_index[j]*3]);     //x component
sections[i]->norm.push_back(norm[sections[i]->norm_index[j]*3+1]);   //y component
sections[i]->norm.push_back(norm[sections[i]->norm_index[j]*3+2]);   //z component
}

sections[i]->ConstructVAO();   //I construct the VAO for each section

printf("Section %i has %i verts, %i normals, %i tex coords\n",i,sections[i]->vert.size()/3,sections[i]->norm.size()/3,sections[i]->tex_coord.size()/2);
}}

А вот код для рендеринга всей модели:

void WavefrontModel::render(GLenum render_mode,bool normals,bool textured)
{
glPolygonMode(GL_FRONT_AND_BACK,render_mode);

glModelMatrix.LoadIdentity();
glModelMatrix.translate(pos);
glModelMatrix.rotate(angle,rot.x,rot.y,rot.z);
glModelMatrix.scale(scaleVec);

shader->sendUniformMatrix4fv(shader->getUniformLocation("projMat"),1,GL_FALSE,GLXSDLRenderPipeline::glProjectionMatrix);
shader->sendUniformMatrix4fv(shader->getUniformLocation("viewMat"),1,GL_FALSE,GLXSDLRenderPipeline::glViewMatrix);
shader->sendUniformMatrix4fv(shader->getUniformLocation("modMat"),1,GL_FALSE,glModelMatrix);
shader->sendUniform1i(shader->getUniformLocation("texture"),0);for(int i = 0;i < sections.size();i++)
{
if(sections[i]->material)
{
sections[i]->material->sendMaterialUniforms(shader);
sections[i]->material->texture.bind_unit(0);
}
shader->bind();
sections[i]->Render();
shader->unbind();

if(sections[i]->material)
sections[i]->material->texture.unbind();}
}

который вызывает render () для каждого экземпляра WavefrontSection.
Метод WavefrontSection :: render () реализован следующим образом

void WavefrontSection::Render()
{
vao.DrawArrays(GL_TRIANGLES,0,vert.size());
}

(вызывая ConstructVAO, я создал буферы, которые тоже старые нормали и координаты текстуры)

Вот что я получаю:
(рендер блендера — так и должно быть, другие — как он рендерится в моем движке)

блендер рендеринг и рендеринг двигателя

любой совет?

0

Решение

Я решил это.
Проблема была тут

else if(strcmp(curr_tok,"vt") == 0)
{
tex.push_back(atof(strtok(NULL,WHITESPACE)));
tex.push_back(atof(strtok(NULL,WHITESPACE)));
}

Я заменил его

else if(strcmp(curr_tok,"vt") == 0)
{
tex.push_back(atof(strtok(NULL,WHITESPACE)));
tex.push_back(1-atof(strtok(NULL,WHITESPACE)));
}
0

Другие решения

Других решений пока нет …