漫射照明伪影 (OpenGL 4)



在阅读了一些教程后,我正在尝试实现最简单的漫射照明,但惨遭失败。

我从 Wavefront obj 文件加载 3d 网格,如果我不应用照明,它看起来很好。但是,当我应用照明时,动物看起来像一个棋盘,立方体更加混乱:

动物比较(与法线)

立方体比较(带法线)

下面是顶点着色器:

#version 400
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec3 a_texCoords;
layout (location = 2) in vec3 a_normal;
uniform mat4 u_viewProjection;
uniform mat4 u_model;
out vec3 v_fragPos;
out vec3 v_fragNormal;
void main() {
v_fragPos = a_position.xyz;
v_fragNormal = a_normal;
gl_Position = u_viewProjection * a_position;
}

我按原样将片段位置和法线传递给片段着色器,因为我没有应用任何模型转换,我只是假设模型从文件加载后已经具有世界坐标(忘记u_model统一,它暂时不使用)。

然后,片段着色器:

#version 400
uniform vec3 u_lightPos;
uniform vec3 u_lightColor;
uniform vec3 u_diffuseColor;
uniform vec3 u_specularColor;
uniform vec3 u_ambientColor;
in vec3 v_fragPos;
in vec3 v_fragNormal;
out vec4 o_fragColor;
void main() {
vec3 lightDir = u_lightPos - v_fragPos;    
float cosTheta = max(dot(normalize(v_fragNormal), normalize(lightDir)), 0.0);
vec3 diffuseContribution = cosTheta * u_lightColor;
o_fragColor = vec4(u_diffuseColor * diffuseContribution, 1.0);
}

不使用模型或正态矩阵,因为目前没有对模型应用旋转(或比例)。

我想到了不正确的法线,但至少一个简单的立方体应该有正确的法线,对吧?

另外,也许我应该提到我在MacOS下使用NSOpenGLView。

任何帮助将不胜感激。 谢谢!

更新:

添加 VBO 设置。

这是单个顶点的样子:

struct Vertex1P1N1UV {
glm::vec4 mPosition;
glm::vec3 mTextureCoords;
glm::vec3 mNormal;
Vertex1P1N1UV();
Vertex1P1N1UV(glm::vec4 position, glm::vec3 texcoords, glm::vec3 normal);
};

我像这样初始化我的 VAO

auto* VAO = new GLVertexArray<Vertex1P1N1UV>();
VAO->initialize(subMesh.vertices(), GLVertexArrayLayoutDescription({
static_cast<int>(glm::vec4::length() * sizeof(GLfloat)),
static_cast<int>(glm::vec3::length() * sizeof(GLfloat)),
static_cast<int>(glm::vec3::length() * sizeof(GLfloat)) }));

VAO 初始化方法

void initialize(const std::vector<Vertex>& vertices, const GLVertexArrayLayoutDescription& layoutDescription) {
bind();
mVertexBuffer.initialize(vertices);
GLuint offset = 0;
for (GLuint location = 0; location < layoutDescription.getAttributeSizes().size(); location++) {
glEnableVertexAttribArray(location);
GLsizei attributeSize = layoutDescription.getAttributeSizes()[location];
glVertexAttribPointer(location, attributeSize / sizeof(GLfloat), GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(offset));
offset += attributeSize;
}
}

和缓冲区初始化方法

void initialize(const std::vector<Vertex>& data) override {
bind();
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(Vertex), data.data(), GL_STATIC_DRAW);
}

在这种情况下,顶点将变为顶点1P1N1UV

更新:

实现了正常可视化(重新上传屏幕截图,滚动到顶部)。 令我困扰的是,我可以通过网格看到法线,就像尽管颜色不透明,但它是透明的。这是一个深度测试问题吗?

经过2天的挣扎,我发现了问题所在。 我没有在NSOpenGLView上启用深度缓冲区。这是一行代码。 如果有人偶然发现这一点,他可以在这里查看 OpenGL GL_DEPTH_TEST不起作用 以获得解决方案。

最新更新