【问题标题】:How to correctly link an opengl program under debian?debian下如何正确链接opengl程序?
【发布时间】:2019-12-26 10:41:10
【问题描述】:

为了学习如何做opengl,我有一个极简的构建系统和一个玩具程序。我的 makefile 生成这些命令:

g++ -O1 -std=c++17 -Wall -Wextra -pedantic   -c -o main.o main.cpp
g++   main.o  -lglfw -lGLEW -lGL -o main

在那个目录中,我有一个单独的 main.cpp 文件。与这里关于 SO 的许多问题相反,这确实有效。 编译和链接没有问题。但是,当我运行程序时,它只显示我用glClear 编写的背景颜色,而不是我的测试三角形

我已经验证我的代码没有问题,因为如果我使用我在教程中发现的(相当复杂和臃肿的)构建系统编译它,它似乎可以工作。但是,我想了解如何自己实际构建一个 opengl 程序。我怀疑我缺少一些库或其他东西,但我希望程序崩溃,而不是(几乎)什么都不做。

我正在运行最新的 debian。

怎么会编译链接完美,却无法正常运行?


免责声明:我对 opengl 和窗口应用程序完全陌生。我不是 100% 确定我为什么需要 glew。

代码:

#include <iostream>

#include <GL/glew.h>

#include <GLFW/glfw3.h>

bool install_shader(GLuint where, std::string const& code, GLuint* attach_to) {
  GLuint shader_id = glCreateShader(where);
  {
    auto const p = code.c_str();
    glShaderSource(shader_id,1,&p,nullptr); // nullptr indicates null-termination here
  }
  glCompileShader(shader_id);
  GLint out;
  glGetShaderiv(shader_id, GL_COMPILE_STATUS, &out);
  if (out == GL_FALSE) {
    // something went wrong with the shader compilation
    glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &out);
    if (out == 0) {
      std::cout << "Unknown Error during shader compilation\n";
    } else {
      std::string error;
      error.resize(out-1);
      glGetShaderInfoLog(shader_id, out, nullptr, error.data());
      std::cout << "Shader Compilation failed with error: " << error;
    }
    return false;
  } else {
    std::cout << "shader(" << int(shader_id) << "@" << int(where) << ") compiled fine\n";

    if (attach_to) {
      glAttachShader(*attach_to, shader_id);
    }

    // XXX THE SHADERS SHOULD BE DELETED AFTER LINKING !!!!
    // glDeleteShader(shader_id)

    return true;
  }
}

bool install_program(GLuint program_id) {
  glLinkProgram(program_id);
  GLint out;
  glGetProgramiv(program_id, GL_LINK_STATUS, &out);
  if (out == GL_FALSE) {
    // something went wrong with the program linking
    glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &out);
    if (out == 0) {
      std::cout << "Unknown link-Error in shader program\n";
    } else {
      std::string error;
      error.resize(out-1);
      glGetProgramInfoLog(program_id, out, nullptr, error.data());
      std::cout << "Program linking failed with error: " << error;
    }
    return false;
  } else {
    std::cout << "program(" << int(program_id) << ") compiled fine\n";
    return true;
  }
}

int main() {
  if (glfwInit()) {
    std::cout <<  "Initialisation fine\n";
  } else {
    std::cout <<  "Initialisation failed\n";
    return 1;
  }

  glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // We want OpenGL 3.3
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);

  if (GLFWwindow* window = glfwCreateWindow(800,600,"testwindow",nullptr,nullptr)) {
    glfwMakeContextCurrent(window);

    if (glewInit() == GLEW_OK) {
      std::cout << "GLEW also fine\n";
    } else {
      std::cout << "GLEW says nope!\n";
      goto die;
      return 2;
    }

    //std::cout << "Ensure we can capture the escape key being pressed below...\n";
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
    /*business*/
    // (1) specify the triangle to draw
    // An array of 3 vectors which represents 3 vertices
    GLfloat g_vertex_buffer_data[] = {
       -0.4f, -0.8f, 0.f,
        0.4f, -0.8f, 0.f,
        0.0f,  0.8f, 0.f,
    };
    GLuint vertexbuffer;
    glGenBuffers(1, &vertexbuffer);

    GLuint program_id = glCreateProgram();

    // (3) vertex shader
    std::string vshader_code = "#version 330 core\n"
      "layout (location = 0) in vec3 aPos;\n"
      "\n"
      "void main()\n"
      "{\n"
      "    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
      "}\n";

    if (!install_shader(GL_VERTEX_SHADER,vshader_code,&program_id)) {
      goto die;
    }

    std::string fshader_code = "#version 330 core\n"
      "out vec3 color;\n"
      "\n"
      "void main()\n"
      "{\n"
      "    color = vec3(0.9,0.8,0.1);\n"
      "}\n";

    if (!install_shader(GL_FRAGMENT_SHADER,fshader_code,&program_id)) {
      goto die;
    }

    if (!install_program(program_id)) {
      goto die;
    }

    glClearColor(0.3, 0.5, 0.5, 1.0);

    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

    do {
      glClear(GL_COLOR_BUFFER_BIT);

      glUseProgram(program_id);


      glEnableVertexAttribArray(0); // this 0 also refes to 'layout (location = 0)' in the vertex shader

      glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
      glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

      glVertexAttribPointer(
        0,        // this refes to 'layout (location = 0)' in the vertex shader
        3,        // each vertex has 3 coordinates (2d data is also possible)
        GL_FLOAT, // coordinates are of type GLfloat (GL_FLOAT)
        GL_FALSE, // we don't need the input data to be nomalised,
        0, //&g_vertex_buffer_data[3] - &g_vertex_buffer_data[0], // stride
        nullptr        // offset ptr
      );

      // Draw the triangle !
      glDrawArrays(GL_TRIANGLES, 0, 3);
      glDisableVertexAttribArray(0);

      glfwSwapBuffers(window);

      glfwPollEvents();
    } // Check if the ESC key was pressed or the window was closed
    while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 );

  } else {
    std::cout << "Could not create window\n";
  }

  die:
  glfwTerminate();
  std::cout <<  "Terminated\n";
}

【问题讨论】:

  • I have verified that it's not a problem with my code, because if I compile it with a (quite complex and bloated) build system I found in a tutorial it seems to work. 这并不一定意味着代码是正确的。实际上,您可能会发生一些未定义的行为,并且其他构建系统可能具有其他编译选项,或者由于某些其他原因导致不同的内存布局,这可能导致代码“正确”运行,即使它是技术上无效。
  • 并且代码将有助于弄清楚为什么它不会崩溃以及在哪里挂钩一些错误检查以追踪问题。
  • @t.niese:我把我的代码放在pastebin 中。我从教程中的示例中复制了大部分内容。主要来自 opengl-tutorial.org 和 learnopengl.com。
  • 我发现的构建系统使用了 glfw 和 glew 的副本,它被编译和链接。但是,我认为这很丑陋。我想链接到我的系统已经提供的库。它的存在是有原因的。
  • 只是为了排除一件事:在这两种情况下,您在同一台机器上使用相同的 GPU 运行程序?因为从技术上讲,给定的 OpenGL 设置无效,应该只显示一个带有 Nvidia GPU 及其驱动程序的三角形。

标签: c++ opengl linker glfw glew


【解决方案1】:

您需要有一个Vertex Array Object,并将其绑定以存储绘制三角形所需的状态:

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

// your remaining code
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
// ...

兼容性 OpenGL 配置文件使 VAO 对象 0 成为默认对象。核心 OpenGL 配置文件使 VAO 对象 0 根本不是对象。因此,如果核心配置文件中绑定了 VAO 0,则不应调用任何修改 VAO 状态的函数。这包括将GL_ELEMENT_ARRAY_BUFFER 与 glBindBuffer 绑定。

根据配置文件和/或驱动程序,可能会有一个活动的默认 VAO,这将导致渲染 tinggle。但是要进行标准的抱怨设置,您需要为要渲染的对象创建一个 VAO。

这并不能真正解释为什么它可以与捆绑的 GLFW 和 GLEW 一起使用,但也许其中之一会创建一个默认 VAO 来模仿兼容性配置文件行为或 NVIDIA 驱动程序的开启。

您可以使用该代码检查您是否处于核心配置文件或兼容性配置文件中:

GLint prof;
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &prof);
std::cout << (prof&GL_CONTEXT_CORE_PROFILE_BIT) << " " << (prof&GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) << std::endl;

【讨论】:

  • 太棒了,它有效。现在为我了解 VAO。你知道为什么教程代码在没有 VAO 的情况下工作吗?
  • @bitmask 这就是为什么你永远不应该假设代码是正确的和不相关的;)
  • 是的,我知道。我的坏:)
  • @bitmask 没有仔细查看您使用的构建系统的设置,并使用 glfw 和 glew 版本,我只能猜测,配置文件在那里有不同的默认值。
  • @bitmask 我添加了一些代码行,您可以将它们包含在您的项目中,以检查使用该构建系统创建的上下文是否使用兼容性配置文件运行。
猜你喜欢
  • 2020-12-20
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
  • 1970-01-01
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多