У меня проблема с загрузкой файла .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, я создал буферы, которые тоже старые нормали и координаты текстуры)
Вот что я получаю:
(рендер блендера — так и должно быть, другие — как он рендерится в моем движке)
блендер рендеринг и рендеринг двигателя
любой совет?
Я решил это.
Проблема была тут
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)));
}
Других решений пока нет …