当前位置: 首页 > 知识库问答 >
问题:

OpenGL:切换多边形模式会导致分段故障

司马英才
2023-03-14

我的计算机使用Intel显卡运行Ubuntu 16.04。我的OpenGL配置文件使用Mesa 11.2。

我简陋的OpenGL程序在窗口中显示一个简单的正方形。如果我按某个键,我想让程序切换到线框图模式,所以我定义了以下回调函数:

void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode) {
    if (key == GLFW_KEY_ESCAPE and action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
    if (key == GLFW_KEY_M and action == GLFW_PRESS) {
        // Find the rasterizing mode.
        GLint rastMode;
        glGetIntegerv(GL_POLYGON_MODE, &rastMode);

        // Switch modes depending on current rasterizing mode.
        if (rastMode == GL_FILL) {
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        }
        else {
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        }
    }
}

不幸的是,在我的程序运行时按m会导致段错误。不过,奇怪的是,在我的另一台计算机(运行Ubuntu 16.04但使用Nvidia GPU)上,我没有这样的问题,并且程序按预期工作。

问题不在于glPolygonMode:我可以将其放入我的main函数中,程序将成功切换模式。问题似乎在于glGetIntegerv。如果我在我的main函数中调用该函数(比如,就在游戏循环之外),我的方块将拒绝出现(尽管没有SEGFULT)。

以下是完整的代码:

#include <array>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

// Vertex and fragment shader source files.
constexpr char VERTEX_SHADER_SOURCE_FILE[]   = "simple_vertex.shader";
constexpr char FRAGMENT_SHADER_SOURCE_FILE[] = "simple_fragment.shader";

// Window properties.
constexpr int  WINDOW_WIDTH   = 800;
constexpr int  WINDOW_HEIGHT  = 800;
constexpr char WINDOW_TITLE[] = "Triangle";

// Background colour.
constexpr std::array<GLfloat, 4> bgColour { 0.3f, 0.1f, 0.3f, 1.0f };

/*
 * Instructs GLFW to close window if escape key is pressed and to toggle between rasterizing modes
 * if m is pressed.
 */
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode);

int main() {
    // Initialize GLFW.
    if (not glfwInit()) {
        std::cerr << "ERROR: Failed to start GLFW.\n";
        return 1;
    }

    // Set required OpenGL version.
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Create a window object and bind it to the current context.
    GLFWwindow *window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, nullptr,
                                          nullptr);
    if (not window) {
        std::cerr << "ERROR: Failed to create GLFW window.\n";
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent(window);

    // Set callback functions.
    glfwSetKeyCallback(window, keyCallback);

    // Initialize GLEW with experimental features enabled.
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        std::cerr << "ERROR: Failed to start GLEW.\n";
        glfwTerminate();
        return 1;
    }

    // Display information on the current GL connection.
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;
    std::cout << "Version: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "Shading Language: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;

    // Define the viewport dimensions.
    int width, height;
    glfwGetFramebufferSize(window, &width, &height);
    glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height));

    // Create a vertex shader object.
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);

    // Load the vertex shader source code.
    std::string vertexShaderSource;
    std::ifstream vsfs(VERTEX_SHADER_SOURCE_FILE);
    if (vsfs.is_open()) {
        std::stringstream ss;
        ss << vsfs.rdbuf();
        vertexShaderSource = ss.str();
    }
    else {
        std::cerr << "ERROR: File " << VERTEX_SHADER_SOURCE_FILE << " could not be found.\n";
        glfwTerminate();
        return 1;
    }

    // Attach the shader source code to the vertex shader object and compile.
    const char *vertexShaderSource_cstr = vertexShaderSource.c_str();
    glShaderSource(vertexShader, 1, &vertexShaderSource_cstr, nullptr);
    glCompileShader(vertexShader);

    // Check if compilation was successful.
    GLint success;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
    if (not success) {
        std::cerr << "ERROR: Vertex shader compilation failed.\n";
        glfwTerminate();
        return 1;
    }

    // Create a fragment shader object.
    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

    // Load the fragment shader source code.
    std::string fragmentShaderSource;
    std::ifstream fsfs(FRAGMENT_SHADER_SOURCE_FILE);
    if (fsfs.is_open()) {
        std::stringstream ss;
        ss << fsfs.rdbuf();
        fragmentShaderSource = ss.str();
    }
    else {
        std::cerr << "ERROR: File " << FRAGMENT_SHADER_SOURCE_FILE << " could not be found.\n";
        glfwTerminate();
        return 1;
    }

    // Attach the shader source code to the fragment shader object and compile.
    const char *fragmentShaderSource_cstr = fragmentShaderSource.c_str();
    glShaderSource(fragmentShader, 1, &fragmentShaderSource_cstr, nullptr);
    glCompileShader(fragmentShader);

    // Check if compilation was successful.
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (not success) {
        std::cerr << "ERROR: Fragment shader compilation failed.\n";
        glfwTerminate();
        return 1;
    }

    // Link the vertex and fragment shaders into a shader program.
    GLuint shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram, vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);   

    // Check that shader program was successfully linked.
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (not success) {
        std::cerr << "ERROR: Shader program linking failed.\n";
        glfwTerminate();
        return 1;
    }

    // Delete shader objects.
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    // Coordinates of square's vertices.
    std::array<GLfloat, 12> vertices {
         0.5f,  0.5f,  0.0f,
         0.5f, -0.5f,  0.0f,
        -0.5f, -0.5f,  0.0f,
        -0.5f,  0.5f,  0.0f
    };

    // Indices to draw.
    std::array<GLuint, 6> indices {
        0, 1, 3,
        1, 2, 3
    };

    // Create a vertex array object.
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    // Create a vertex buffer object.
    GLuint vbo;
    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // Create an element buffer object.
    GLuint ebo;
    glGenBuffers(1, &ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

    // Pass vertex data into currently bound vertex buffer object.
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);

    // Pass index data into currently bound element buffer object.
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices.data(), GL_STATIC_DRAW);

    // Create and enable a vertex attribute.
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), static_cast<GLvoid*>(0));
    glEnableVertexAttribArray(0);

    // It is good practice to unbind the vertex array object, vertex buffer object, and element
    // buffer object.
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);

    // Set background colour.
    glClearColor(bgColour[0], bgColour[1], bgColour[2], bgColour[3]);

    // Main loop.
    while (not glfwWindowShouldClose(window)) {
        // Clear the screen of colours and poll for events.
        glClear(GL_COLOR_BUFFER_BIT);
        glfwPollEvents();

        // Inform OpenGL to use the shader program created above.
        glUseProgram(shaderProgram);

        // Bind the vertex array object and element buffer object.
        glBindVertexArray(vao);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);

        // Draw the triangle using glDrawElements. The first argument gives the OpenGL primitive to
        // render, the second argument gives the number of vertices to draw, the third gives type
        // used to represent an index, and finally the last argument gives a possible offset in the
        // EBO.
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, static_cast<GLvoid*>(0));

        // Unbind the vertex array object (good practice).
        glBindVertexArray(0);

        // Swap buffers.
        glfwSwapBuffers(window);
    }

    // Clean up.
    glDeleteVertexArrays(1, &vao);
    glDeleteBuffers(1, &vbo);
    glDeleteProgram(shaderProgram);
    glfwDestroyWindow(window);
    glfwTerminate();
    return 0;
}

void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mode) {
    if (key == GLFW_KEY_ESCAPE and action == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, GL_TRUE);
    }
    if (key == GLFW_KEY_M and action == GLFW_PRESS) {
        // Find the rasterizing mode.
        GLint rastMode;
        glGetIntegerv(GL_POLYGON_MODE, &rastMode);

        // Switch modes depending on current rasterizing mode.
        if (rastMode == GL_FILL) {
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        }
        else {
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        }
    }
}

共有1个答案

洪念
2023-03-14

文件显示:

params返回两个值:符号常量,指示正面和背面多边形是光栅化为点、线还是填充多边形

总结@Wyzard和我的评论:glGetIntegerv(GL_POLYGON_模式,

解决方案是传递两个整数的缓冲区。

 类似资料:
  • 我正在尝试用Objective-C编写一个波阵面OBJ文件查看器,它能够从文件中加载网格/材质/着色器。我已经为着色器和着色器程序创建了类,我正在尝试创建一个OpenGL着色器程序对象,作为着色器程序类的init方法的一部分: 但是,调用glCreateProgram会导致EXC_BAD_访问,调用[SRShader compile]也会导致EXC_BAD_访问,而[SRShader compil

  • 我能够创建一个窗口,并清除到所需的颜色。但无法在左下角绘制正方形。

  • 我希望通过一条线串拆分一个多多边形(代表一个有岛屿的国家),从而将该县一分为二。 此结果是GeometryCollection对象中的一组多边形。如何将结果分组为两个多多边形对象,每个对象都包含各自一半的多边形? 使现代化 问题:确定分裂形状几何的“左”和“右”侧提供了一个很好的解决方案,其中从结果中的每个多边形中提取一个点,看看当与分裂的LineString结合时,它是否形成顺时针或逆时针线串。

  • 我没有使用查看页面,我调用任何片段事务的唯一地方是单击活动布局中导航栏上的按钮。 当我切换到片段太快(像来回),我得到这个例外: java.lang.IllegalStateException:无活动 当我点击切换另一个片段时,第一个片段还没有完全加载完毕。我正在使用碎片活动。 有人能对此发表一些见解吗? 我的代码切换s: 编辑:去掉过渡解决了问题,但我想知道是否有一种方法可以在适当的位置完成过渡

  • 我最近遇到了一个问题,我们的一个遗留应用程序依赖于UPS跟踪API。UPS更改了其通信协议以要求TLSv1。2.不幸的是,JDK1.6的最新公共版本似乎不支持此协议,因此我的选择是支付oracle支持合同或升级到JDK1.7。我升级到了1.7 我改变了项目的依赖关系,一切看起来都很好。当我尝试实际部署到应用程序服务器时,失败了,错误如下: com.sun.xml.bind.v2.runtime.I

  • 服务模式切换比较麻烦,需要您的Kubernetes支持,目前我们使用的是istio的方案,也就是说您需要在你的kubernetes上安装istio的相关服务,并且在我们的模版管理将istio所需要的几个模版配置上。才能开启此功能。 如果您没有安装Istio,可跳过此章。 依赖 在"模版管理"菜单找到Gateway、VritualService、InitContainer、IstioProxy这几个