我有一个工作的应用程序,显示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模型。
1条答案
按热度按时间jucafojl1#
相应的位置和法线必须放置在两个缓冲区中的相同索引处。这意味着索引1处的法线属于索引1处的位置。
您的实际问题是(可能)为属性使用了错误的位置。属性位置(
glEnableVertexAttribArray
和glVertexAttribPointer
中使用的参数)指定着色器中属性的位置(索引类型)。您可以在着色器与glGetAttributeLocation
链接后查询属性的位置:也可以使用布局限定符预定义着色器中的位置:
无论哪种方式,在 VAO 设置期间使用的位置必须与着色器中的位置匹配。
注意,由于顶点着色器未显示,
vertex_position
和vertex_normal
必须替换为顶点着色器中的实际名称。您的第一个版本可能有效,因为您只有一个顶点属性(用于位置的那个),并且很可能(但不能保证)该属性自动指定了位置0。既然有两个,猜测它们是非常容易出错的。