我在 OpenGL 应用程序中加载 .obj 文件时遇到问题。这是一个由不同部分制成的汽车模型(使用不同的材料,例如玻璃、车轮等)
我有一个 WavefrontModel 类,它包含一个 WavefrontSection 数组,它们有自己的顶点、法线、材质和 tex 坐标。
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();
}
}
它在每个 WavefrontSection 实例上调用 render()。WavefrontSection::render() 方法实现如下
void WavefrontSection::Render()
{
vao.DrawArrays(GL_TRIANGLES,0,vert.size());
}
(调用 ConstructVAO,我创建了旧法线和纹理坐标的缓冲区)
这就是我得到的:(搅拌机渲染应该是这样,其他是它在我的引擎中的渲染方式)
有什么建议吗?