OpenGL 代码不是每次都显示相同的东西吗?

OpenGL code doesn't display the same thing every time?

当 运行 程序两次时,它在 运行 时显示的结果不同,即使我使用的是相同的可执行文件。

这里有一些背景信息:

我正在使用 Sierra 10.13 在 MacAir 上编程,我的 IDE 是 Xcode 10.1。

我发现我的问题是由在顶点着色器中添加变换矩阵引起的:

// This code is not working
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 textureCoords;

out vec2 pass_textureCoords;

uniform mat4 transformM;

void main() {
    gl_Position = transformM * vec4(position, 1.0);
    pass_textureCoords = textureCoords;
}

然后我以这种方式加载 transformM 矩阵(我使用 GLM 库进行数学计算):

void LoadMatrix(int location, glm::mat4 matrix) {
    glUniformMatrix4fv(location, 1, GL_FALSE, &matrix[0][0]);
}

其中 位置 是:

uniformName = "transformM";
location = glGetUniformLocation(_shaderID, uniformName.c_str());

(我保持简单,但您可以在此处找到完整代码:https://github.com/Cuiyere/Ecosystem

事实上,我希望我的代码能够渲染一个立方体并旋转它,但它并没有像 50% 的时间那样出现。

我不明白为什么会出现这个问题。我检查了我的代码一百次,检查了 docs.gl 网站,将 ThinMatrix 的代码与我的进行了比较(即使它是用 Java 编写的,整体结构和 OpenGL 功能仍然完全相同),检查了 OpenGL 论坛,但据我所知,没有人遇到过这个问题。

我认为这是 OpenGL 使用顶点着色器的方式的问题,但我不能肯定。

glm::mat4 的默认构造函数不初始化矩阵。在class Render的构造函数中调用void Renderer::CreateProjectionMatrix()之前,_projectionMatrix没有被初始化。

方法void Renderer::CreateProjectionMatrix()没有初始化矩阵_projectionMatrix的所有字段。矩阵中未初始化的字段导致未定义的行为。

在函数的开头将identity matrix赋值给_projectionMatrix,确保所有字段都是 已初始化:

void Renderer::CreateProjectionMatrix() {

    _projectionMatrix = glm::mat4(1.0f);

    // [...]
}

或者使用构造函数初始化矩阵:

Renderer::Renderer (Shaders::StaticShader shader)
    : _projectionMatrix(1.0f)
{
    CreateProjectionMatrix();
    // [...]
} 

但是注意,如果一个方法名为CreateProjectionMatrix,它应该设置成员_projectionMatrix的所有字段。


此外,您还必须在构造函数中初始化 class Camera 的成员 _position_pitch_yaw_roll

Camera()
  : _position(0.0f, 0.0f, 0.0f)
  , _pitch(0.0f)
  , _yaw(0.0f)
  , _roll(0.0f)
{}; 

方法中ShaderProgram::CompileShader是另外一个问题。 ShaderProgram::ReadShader 的 return 值的类型是 std::string。所以 ReadShader( shaderPath ).c_str() 将 return 一个指向临时对象的指针,该对象在赋值语句结束时立即被破坏。 std::string 对象被破坏,指针指向任何地方。

ShaderProgram::ReadShader的return值赋给一个局部变量,并在ShaderProgram::CompileShader的范围内使用指向该局部变量内容的指针:

unsigned int ShaderProgram::CompileShader (unsigned int type, const std::string & shaderPath) {
    unsigned int id = glCreateShader(type);

    std::string code = ReadShader( shaderPath );
    const char* src = code.c_str();

    glShaderSource(id, 1, &src, nullptr);
    glCompileShader(id);   

    // [...]
}