我遇到OpenGL法线问题。 我正在渲染龙模型,但我有一些奇怪的正常模式。
以下是我的渲染的截图: render_screen
这是我的缓冲区创建方法:
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
if (has_position) {
glGenBuffers(1, &vertex_buffer);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * 3 * sizeof(float), vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(kVertexArray);
glVertexAttribPointer(kVertexArray, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
}
if (has_normal) {
glGenBuffers(1, &normal_buffer);
glBindBuffer(GL_ARRAY_BUFFER, normal_buffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * 3 * sizeof(float), normals.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(kNormalArray);
glVertexAttribPointer(kNormalArray, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
}
if (has_tex_coord) {
glGenBuffers(1, &tex_coord_buffer);
glBindBuffer(GL_ARRAY_BUFFER, tex_coord_buffer);
glBufferData(GL_ARRAY_BUFFER, tex_coords.size() * 3 * sizeof(float), tex_coords.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(kTexCoordArray);
glVertexAttribPointer(kTexCoordArray, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
}
if (has_index) {
glGenBuffers(1, &index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * 3 * sizeof(unsigned short), indices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
}
并绘制:
glDrawElements(GL_TRIANGLES, indices.size() * 3, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
Wavefront obj加载器方法:
bool Loadfs() {
CVector3<float> vertex;
CVector3<unsigned short> vindex, tindex, nindex;
while(file_stream->offset_ < file_stream->size_) {
if (file_stream->buffer_[file_stream->offset_] == '#') {
char comment[512] = {0};
file_stream->ReadLine(comment); // check return code -> "its local variable return address"
file_stream->SkipLine();
}
else if (file_stream->buffer_[file_stream->offset_] == 'v') {
file_stream->offset_++;
if (file_stream->buffer_[file_stream->offset_] == ' ') {
has_position = true;
file_stream->offset_++;
file_stream->SkipWhiteSpace();
vertex.x = file_stream->ReadFloat();
file_stream->SkipWhiteSpace();
vertex.y = file_stream->ReadFloat();
file_stream->SkipWhiteSpace();
vertex.z = file_stream->ReadFloat();
file_stream->SkipLine();
vertices.push_back(vertex);
}
else if (file_stream->buffer_[file_stream->offset_] == 'n') {
has_normal = true;
file_stream->offset_++;
file_stream->SkipWhiteSpace();
vertex.x = file_stream->ReadFloat();
file_stream->SkipWhiteSpace();
vertex.y = file_stream->ReadFloat();
file_stream->SkipWhiteSpace();
vertex.z = file_stream->ReadFloat();
file_stream->SkipLine();
normals.push_back(vertex);
}
else if (file_stream->buffer_[file_stream->offset_] == 't') {
has_tex_coord = true;
file_stream->offset_++;
file_stream->SkipWhiteSpace();
vertex.x = file_stream->ReadFloat();
file_stream->SkipWhiteSpace();
vertex.y = file_stream->ReadFloat();
file_stream->SkipWhiteSpace();
vertex.z = file_stream->ReadFloat();
file_stream->SkipLine();
tex_coords.push_back(vertex);
}
}
else if (file_stream->buffer_[file_stream->offset_] == 'f') {
has_index = true;
file_stream->offset_++;
file_stream->SkipWhiteSpace();
//
if (has_position) {
vindex.x = file_stream->ReadShort();
}
if (has_tex_coord) {
file_stream->offset_++;
tindex.x = file_stream->ReadShort();
}
if (has_normal) {
file_stream->offset_++;
nindex.x = file_stream->ReadShort();
}
file_stream->SkipWhile(' ');
//
if (has_position) {
vindex.y = file_stream->ReadShort();
}
if (has_tex_coord) {
file_stream->offset_++;
tindex.y = file_stream->ReadShort();
}
if (has_normal) {
file_stream->offset_++;
nindex.y = file_stream->ReadShort();
}
file_stream->SkipWhile(' ');
//
if (has_position) {
vindex.z = file_stream->ReadShort();
}
if (has_tex_coord) {
file_stream->offset_++;
tindex.z = file_stream->ReadShort();
}
if (has_normal) {
file_stream->offset_++;
nindex.z = file_stream->ReadShort();
}
vi.push_back(--vindex);
ti.push_back(--tindex);
ni.push_back(--nindex);
//indices.push_back(--vindex);
}
else file_stream->SkipLine();
}
indices.insert(indices.end(), vi.begin(), vi.end());
return true;
}
这里vs:glsl主要方法:
position_ = MV * vec4(vVertex, 1.0);
normal_ = normalize(N * vNormal);
texture_ = vTexture;
//shadow_ = S * M * vec4(vVertex, 1.0);
gl_Position = MVP * vec4(vVertex, 1.0);
和fs.glsl主要方法:
vec3 rgb = vec3(1.0, 1.0, 1.0);
rgb = PhongShade(g_light, g_material, position_, normal_);
_frag_color = vec4(rgb, 1.0);
//_frag_color = texel * vec4(ambient + diffuse + specular, 1.0);
有人有任何想法吗?
答案 0 :(得分:0)
问题是OpenGL使用单个索引缓冲区来索引顶点位置,纹理坐标和普通缓冲区,每个使用相同的索引(三角形的3个索引),而Wavefront obj格式允许每个面指定单独的顶点位置,纹理坐标和法线的索引独立(三角形总共9个索引)。
您的代码中并不清楚,但很可能您实际上并未使用正在阅读的ti
和ni
索引数组,而是从{{1}创建index_buffer
因此,顶点索引用于索引vi
和normal_buffer
,给出了奇怪的结果。
要解决此问题,您需要创建顶点坐标,tex坐标和法线坐标的缓冲区,并为obj文件中的面定义中使用的顶点位置索引,tex坐标索引和普通索引的每个唯一组合创建一个条目。 ,然后将索引缓冲区索引到这些数组中,使得特定的面顶点具有相同的索引。理想情况下,这将作为预处理步骤而不是在加载时完成。
或者,放弃使用tex_coord_buffer
建立索引并使用glDrawElements
代替。根据position,tex coord和normal的面顶点索引,为每个面顶点的每个数组写出一个条目,然后渲染它。然而,这效率较低。
另一个解决方案(如果可能的话)是以这样的方式导出obj文件:每个面顶点使用相同的位置,tex坐标和法线索引。