使用OpenGL和SFML显示简单的三角形

时间:2015-10-19 22:22:14

标签: c++ opengl sfml

我正在玩OpenGL和SFML。我是这两个人的初学者。我正在阅读一些教程并尝试自己调整一下。但我无法使用以下代码。它应该显示一个白色三角形,但它只显示黑屏。它不会打印任何错误消息。

有一些注释掉的行会使用顶点缓冲区对象而不是当前使用的顶点数组。但这两者都不起作用。

我想我必须遗漏一些非常简单的东西......但不知道是什么。

我的卡说它支持OpenGL3.1,但这可能是问题的根源吗?当我在Qt中尝试使用OpenGL的类似示例时,它工作正常。

#include <SFML/Window.hpp>
#include <GL/glew.h>
#include <iostream>

bool createShader(GLuint &shaderID, GLenum shaderType, const char* shaderSource)
{
    shaderID = glCreateShader(shaderType);
    glShaderSource(shaderID, 1, &shaderSource, 0);
    glCompileShader(shaderID);

    GLint compileStatus;
    glGetShaderiv(shaderID, GL_COMPILE_STATUS, &compileStatus);
    if (compileStatus == GL_TRUE)
        return true;

    // log error
    GLint infoLogLength;
    glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &infoLogLength);
    GLchar* buffer = new GLchar[infoLogLength];
    glGetShaderInfoLog(shaderID, infoLogLength, &infoLogLength, buffer);
    std::cerr << buffer << std::endl;
    delete[] buffer;
    return false;
}

bool createShaderProgram(GLuint &programID)
{
    const char *vertexShaderSource =
        "attribute vec2 position;\n"
        "void main() {\n"
        "   gl_Position = vec4(position, 0.0, 0.0);\n"
        "}\n";

    const char *fragmentShaderSource =
        "void main() {\n"
        "   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
        "}\n";

    GLuint vertexShaderID;
    if (! createShader(vertexShaderID, GL_VERTEX_SHADER, vertexShaderSource))
        return false;

    GLuint fragmentShaderID;
    if (! createShader(fragmentShaderID, GL_FRAGMENT_SHADER, fragmentShaderSource))
        return false;

    programID = glCreateProgram();
    glAttachShader(programID, vertexShaderID);
    glAttachShader(programID, fragmentShaderID);
    glLinkProgram(programID);

    GLint linkStatus;
    glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
    if (linkStatus == GL_TRUE)
        return true;

    // log error
    GLint infoLogLength;
    glGetShaderiv(programID, GL_INFO_LOG_LENGTH, &infoLogLength);
    GLchar* buffer = new GLchar[infoLogLength];
    glGetShaderInfoLog(programID, infoLogLength, &infoLogLength, buffer);
    std::cerr << buffer << std::endl;
    delete[] buffer;
    return false;
}

int main()
{
    sf::Window window(sf::VideoMode(800, 600), "OpenGL", sf::Style::Default, sf::ContextSettings(32));
    window.setVerticalSyncEnabled(true);

    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        std::cerr << "Error: " << glewGetErrorString(err) << std::endl;
        exit(1);
    }
    std::cout << "Status: Using GLEW " << glewGetString(GLEW_VERSION) << std::endl;

    GLuint programID;
    if (! createShaderProgram(programID))
        exit(1);

    glUseProgram(programID);

    static const GLfloat vertices[] =
    {
        0.0f, 1.0f,
        -1.0f, -1.0f,
        1.0f, -1.0f
    };
    //GLuint vertexBufferID;
    //glGenBuffers(1, &vertexBufferID);
    //glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    GLint posAttrID = glGetAttribLocation(programID, "position");

    glVertexAttribPointer(posAttrID, 2, GL_FLOAT, GL_FALSE, 0, vertices); // 0);
    glEnableVertexAttribArray(posAttrID);

    bool running = true;
    while (running)
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                running = false;
            }
            else if (event.type == sf::Event::Resized)
            {
                glViewport(0, 0, event.size.width, event.size.height);
            }
        }

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDrawArrays(GL_TRIANGLES, 0, 3);

        window.display();
    }

    // release resources...

    return 0;
}

更新:

以下有些人建议我必须使用VBO和VAO。真的吗?或者它只是可选的更好的性能?我不能将数据从普通RAM发送到glVertexAttribPointer()?

我还在支持OpenGL4.4的台式机上尝试了上面的代码(在我尝试使用支持OpenGL3.1的集成显卡的懒惰笔记本电脑之前),结果是:整个屏幕都是白色的。在它变黑之前。为什么?我不诚实。

1 个答案:

答案 0 :(得分:1)

您的代码缺少用于存储顶点属性数据的缓冲区(只是取消注释缓冲区)和VAO。

VAO

VAO是一个对象,它存储每个属性的格式(数据类型,大小等)和一些告诉OpenGL的信息,它可以在哪里找到它的每个顶点数据(在哪个缓冲区中)。它还将偏移量存储到缓冲区和步幅中。它不存储顶点属性数据本身。

你可以拥有多个VAO(使用glCreateVertexArrays()创建它们),你必须首先绑定一个(glBindVertexArray())才能使用它。使用glDrawArrays()或glDrawElements()(或其任何变体)进行的任何渲染以及对glVertexAttribPointer()等的任何调用都使用当前绑定的VAO。

如果您有多个具有不同格式的顶点属性的网格,这将非常有用。您可以通过单个函数调用轻松更改所有状态。但是,切换VAO的性能很重,因此请尝试通过使用相同的属性格式存储网格来最小化这种情况。

VBO(只是通用缓冲区)

VBO本身并不知道任何这些信息。它只是一个通用缓冲区,它只知道它包含多少数据,并且有一个用法提示(STATIC_DRAW等)。

总而言之,您的代码只需要进行两项更改: 取消注释缓冲区并在调用glVertexAttribPointer()之前创建并绑定VAO。请注意,您使用glBufferData()提供的信息不属于VAO状态。

<强> EDIT1: 在顶点着色器中,通过vec4(position, 0.0, 0.0)输出gl_Position,w分量为0. w应始终为1。您应该将其更改为vec4(position, 0.0, 1.0)