OpenGL:索引和法线之间的连接在哪里?

mw3dktmi  于 2023-06-22  发布在  其他
关注(0)|答案(1)|浏览(175)

我有一个工作的应用程序,显示3D模型线框模式正确。现在我想添加一个新的模式,其中这些模型显示为由光源照亮的实体。
将多边形模式从glPolygonMode(GL_FRONT_AND_BACK,GL_LINE)更改为glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)不会完成这项工作,因为缺少完整的法线和照明内容。到目前为止,这对我来说是很清楚的。我不明白的是,法线被正确地应用到当前几何体的地方,意味着OpenGL在哪里/如何知道,提供的法线坐标属于我的(以前的)线框模式的坐标?
这就是我到目前为止所改变的:
a)一个新的着色器程序为我的实体3D模型:

#version 130
in vec3 Normal;
in vec3 fpos;

out vec4 fragment_color;

const vec3 lightPos = vec3(0.0,0.0,5.0);
const vec3 diffColor = vec3(1.0,0.5,0.0);
const vec3 specColor = vec3(1.0,1.0,1.0);

void main () {
 vec3 normal = normalize(Normal);
 vec3 viewDir = normalize(-fpos);
 if (dot(normal, viewDir) < 0.0) normal *= -1.0;

 vec3 lightDir = normalize(lightPos - fpos);
 float lamb = max(dot(lightDir, normal), 0.0);
 float spec = 0.0;

 if (lamb > 0.0) {
  vec3 refDir = reflect(-lightDir, normal);
  float specAngle = max(dot(refDir, viewDir), 0.0);
  spec = pow(specAngle, 4.0);
 }
fragment_color = vec4(lamb * diffColor + spec * specColor, 1.0);
}\0";

b)设置坐标后(这是旧的,工作代码已经用于我的线框图视图)...

glBindVertexArray(entity->m_gl3Element.VAO);
glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.coordVBO);
glBufferData(GL_ARRAY_BUFFER,m_vertexArray.size()*sizeof(float),m_vertexArray.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

...我现在还添加了加载法线数据的代码...

glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.normalVBO);
glBufferData(GL_ARRAY_BUFFER, normalArray.size()*sizeof(float),normalArray.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.normalVBO);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,0,(void*)0);

...最后通过调用关闭:

glBindVertexArray(0);

稍后整个内容通过调用

glDrawArrays(...)

在做了这些修改之后,我的模型看起来是实心的,但仍然是完全黑色的,所以照明/法线的东西不能正常工作。
我的问题:我不明白法线应用于坐标的位置-是来自调用glEnableVertexAttribArray(2)和glVertexAttribPointer(2,...)的神奇索引"2"进行此赋值吗?OpenGL是否总是“知道”这个“2”是法线?
法线本身应该很好,因为它们来自从磁盘加载的3D模型。

jucafojl

jucafojl1#

相应的位置和法线必须放置在两个缓冲区中的相同索引处。这意味着索引1处的法线属于索引1处的位置。
您的实际问题是(可能)为属性使用了错误的位置。属性位置(glEnableVertexAttribArrayglVertexAttribPointer中使用的参数)指定着色器中属性的位置(索引类型)。您可以在着色器与glGetAttributeLocation链接后查询属性的位置:

auto location = glGetAttribLocation(program, "vertex_position");
glBindVertexArray(entity->m_gl3Element.VAO);
glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.coordVBO);
glBufferData(GL_ARRAY_BUFFER,m_vertexArray.size()*sizeof(float),m_vertexArray.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

location = glGetAttribLocation(program, "vertex_normal");
glBindBuffer(GL_ARRAY_BUFFER,entity->m_gl3Element.normalVBO);
glBufferData(GL_ARRAY_BUFFER, normalArray.size()*sizeof(float),normalArray.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(location);
glVertexAttribPointer(location,3,GL_FLOAT,GL_FALSE,0,(void*)0);

也可以使用布局限定符预定义着色器中的位置:

layout(location = 0) in vec3 vertex_position;
layout(location = 2) in vec3 vertex_normal;

无论哪种方式,在 VAO 设置期间使用的位置必须与着色器中的位置匹配。
注意,由于顶点着色器未显示,vertex_positionvertex_normal必须替换为顶点着色器中的实际名称。
您的第一个版本可能有效,因为您只有一个顶点属性(用于位置的那个),并且很可能(但不能保证)该属性自动指定了位置0。既然有两个,猜测它们是非常容易出错的。

相关问题