我们似乎在使用OBJ模型的索引渲染EBO时遇到了麻烦。如下所示,我们首先通过迭代OBJ中的每个关键字来加载和分配顶点数据,并复制它们的值:
CBint current_material = -1;
std::vector <vec3> temp_v;
std::vector <vec3> temp_vn;
std::vector <vec2> temp_vt;
for (unsigned int i = 0; i < line.size(); i++)
{
switch ((line[i])[0])
{
case '#':
continue;
case '\0':
continue;
case 'm':
char mtl_url[128];
sscanf_s((&line[i])[0].c_str(), "mtllib %s", mtl_url, sizeof(mtl_url));
_mtl_url = mtl_url;
_materialised = true;
break;
case 'v':
float x, y, z;
if ((line[i])[1] == 'n')
{
sscanf_s((&line[i])[0].c_str(), "vn %f %f %f", &x, &y, &z);
temp_vn.push_back(vec3(x, y, z));
}
if ((line[i])[1] == 't')
{
sscanf_s((&line[i])[0].c_str(), "vt %f %f", &x, &y);
temp_vt.push_back(vec2(x, y));
}
else
{
sscanf_s((&line[i])[0].c_str(), "v %f %f %f", &x, &y, &z);
temp_v.push_back(vec3(x, y, z));
}
break;
case 'u':
char material_element[128];
sscanf_s((&line[i])[0].c_str(), "usemtl %s", &material_element, sizeof(material_element));
if (_material_elements.size() > 1)
_f[_f.size() - 1].mat_id = _material_elements.size();
_material_elements.push_back(material_element);
current_material++;
break;
case 'f':
CBuint v_i[3];
CBuint vn_i[3];
CBuint vt_i[3];
sscanf_s((&line[i])[0].c_str(), "f %d/%d/%d %d/%d/%d %d/%d/%d", &v_i[0], &vt_i[0], &vn_i[0], &v_i[1], &vt_i[1], &vn_i[1], &v_i[2], &vt_i[2], &vn_i[2]);
_f.push_back(Face(v_i[0], vt_i[0], vn_i[0], v_i[1], vt_i[1], vn_i[1], v_i[2], vt_i[2], vn_i[2]));
break;
}
然后我们通过遍历每个面来优化索引,同时迭代每个属性,然后将这些属性分配给&#34; _indices&#34;容器:
for (CBuint i = 0; i < _f.size(); i++)
{
for (CBuint j = 0; j < 3; j++)
{
CBuint v = _f[i].v[j];
CBuint vt = _f[i].vt[j];
CBuint vn = _f[i].vn[j];
out_v.push_back(temp_v[v - 1]);
out_vt.push_back(temp_vt[vt - 1]);
out_vn.push_back(temp_vn[vn - 1]);
_indices.push_back(v);
_indices.push_back(vt);
_indices.push_back(vn);
}
}
&#34; _f&#34;是&#34; Face&#34;的矢量列表的标识符,它是一个包含以下内容的简单结构:
CBuint v[3];
CBuint vt[3];
CBuint vn[3];
CBuint mat_id;
这是我们使用的另一个结构(&#34; Mesh&#34;),用于创建由OBJ中检测到的每种材料定义的多个子网格(&#34; usemtl default__0&#34;)。我们这样做,因此我们可以使用合法的材料在模型中渲染多个子网格。
Mesh(std::vector <CBuint>& i, std::vector <vec3>& v, std::vector <vec3>& vn, std::vector <vec2>& vt)
{
glGenBuffers(1, &vbo_v);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_v);
glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(Math::vec3), &v[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glGenBuffers(1, &vbo_vn);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vbo_vn);
glBufferData(GL_ARRAY_BUFFER, vn.size() * sizeof(vec3), &vn[0], GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glGenBuffers(1, &vbo_vt);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo_vt);
glBufferData(GL_ARRAY_BUFFER, vt.size() * sizeof(vec2), &vt[0], GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, i.size() * sizeof(CBuint), &i[0], GL_STATIC_DRAW);
}
在优化索引数组(&#34; f x / x / x x / x / x x / x / x&#34;)之后,我们遍历每个材质元素并推送每个材质的网格:
CBuint next_element = 0;
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
if (_materials.size() > 1)
{
for (CBuint i = 0; i < _f.size(); i++)
{
if (_f[i].mat_id == next_element)
{
_meshes.push_back(new Mesh(_indices, out_v, out_vn, out_vt));
next_element++;
}
}
}
else
_meshes.push_back(new Mesh(_indices, out_v, out_vn, out_vt));
glBindVertexArray(0);
然后最后我们调用glDrawElements而不是glDrawArrays来节省渲染时间的1/3:
glUniformMatrix4fv(_u_model, 1, GL_FALSE, _model);
_materials[0]->bind();
glBindVertexArray(_vao);
glDrawElements(GL_TRIANGLES, _indices.size(), GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
不幸的是,当使用glDrawElements时,我们得到以下结果:
http://s11.postimg.org/5qbsf2uzn/Untitled_1.jpg
然而,当使用glDrawArrays时,结果是完美的:
http://postimg.org/image/7wrq8icn3/
有谁能告诉我们我们做错了什么?此外,这是我们的顶点着色器位置代码:
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec2 texCoord;
如果有人有任何想法,我们会很感激。谢谢! DrStrange。