Mac OS X上的OpenGL仅绘制黑屏,而不是三角形(GLEW,GLFW)

时间:2018-11-26 20:12:08

标签: c++ macos opengl glfw glew

我是编程和OpenGL的新手,并且正在关注Cherno的OpenGL初学者教程。但是,它没有显示三角形,而是显示了黑屏。

我相信我的着色器已正确解析和编译。我将Mac OS 10.13与OpenGL 3.2配合使用。 GLFW在加载窗口后确实给出了错误,但我已阅读到该错误不会产生任何严重的后果。我在下面列出了错误。

我非常关注Cherno的教程,但是由于缺乏OpenGL的经验,我很难找到类似于我的问题。我确实在Basic.shader中的main()函数之后删除了分号,因为着色器在那里时无法编译。

这是我第一次发布到StackOverflow,所以我不格式化问题。对于荷兰的评论,我们深感抱歉,从现在开始,我将用英语撰写;)如果我的代码难以遵循,请发表评论或发送电子邮件至afas460x@gmail.com

编辑1:我发现它与VAO有关。我不知道它是什么或如何使用。该文档非常令人困惑。有人可以解释吗?

main.cpp:

// OpenGL test
// Geschreven door Job Winterdijk
// 18-11-2018
// foutcodes door return:
//              2 :  !glfwInit
//              3 :  !glfwCreateWindow
//              4 :  glewInit != GLEW_OK
//              5 :  CompileShader()
//              6 :  ParseShader() > ongedefieneerde shader

// debug macros
#define DEBUG_OUTPUT_PARSE_SHADER 1
#define DEBUG_OUTPUT_ARGV_0 1
#define DEBUG_OUTPUT_GLSL_VERSION 1

// gedeelde libs
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

#include <cstring>

// GLEW moet eerder geinclude worden dan ander GL libs
#include "include/GL/glew.h"

// Gedeelde OpenGL libs
#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>

// Statische libs
#include "include/GLFW/glfw3.h"

struct ShaderSource
{
    std::string VertexShader;
    std::string FragmentShader;
};

static void TerminateWithError(unsigned int err)
{
    // dit is niet goed :(
    std::cout << "weg ermee..." << std::endl;
    glfwTerminate();
    exit(err);
}

static ShaderSource ParseShader(const std::string& path)
{
    // maakt een enum type aan om by te houden naar welke stream er geschreven moet worden
    enum class ShaderTarget
    {
        NONE=-1, VERTEX=0, FRAGMENT=1
    };

    ShaderTarget target = ShaderTarget::NONE;

    // maakt een nieuwe input stream aan
    std::ifstream stream(path);

    // maakt twee nieuwe output streams aan
    // 0 = de vertex shader
    // 1 = de fragment shader
    std::stringstream out[2];

    // houd een lijn uit het bestand vast
    std::string line;

    // deze loop blijft lopen totdat getline == null AKA het einde van het bestand
    while (getline(stream, line)) {
        if (line.find("#shader") != std::string::npos) {
            if (line.find("vertex") != std::string::npos) {
                // de vertex shader is gevonden, schrijf naar vertex shader string
                target = ShaderTarget::VERTEX;
            } else if (line.find("fragment") != std::string::npos){
                // de fragment shader is gevonden, schrijf naar fragment shader string
                target = ShaderTarget::FRAGMENT;
            } else {
                TerminateWithError(6);
            }
        } else {
            // de gelezen lijn is een lijn die code bevat
            out[(int) target] << line << '\n';
        }
    }

    return {out[0].str(), out[1].str()};
}

static unsigned int CompileShader(const std::string& inputShader, unsigned int type)
{
    unsigned int id = glCreateShader(type); // maakt een lege shader aan
    const char* inputShaderCS = inputShader.c_str(); // maakt een char pointer naar het eerste element van de CS van std::string, werkt alleen maar zolang de oorspronkelijke string ook blijft bestaan

    glShaderSource(id, 1, &inputShaderCS, nullptr); // geeft de ongecompileerde shader door aan OpenGL
    glCompileShader(id); // compileert de shader

    // hopa we gaan nu error handelen hebbe we er een beetje zin in!!!!!

    // glGetShaderiv() haalt informatie over een shader op en stopt dit in een var waar de pointer naar wijst
    int result;
    glGetShaderiv(id, GL_COMPILE_STATUS, &result);

    // kijken of het compileren succesvol was
    if (result == GL_FALSE) {
        // als het niet succesvol was wordt de rede opgeslagen in de info log
        // die kan je met getShaderiv() lezen
        // net zoals de lengte van de info log

        int length;
        glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);

        // message moet op de heap gealloceerd worden omdat je pas tijdens runtime weet hoelang de foutmelding is
        char* message = new char[length];
        glGetShaderInfoLog(id, length, &length, message);

        // zet het type shader om in menselijke taal
        char ShaderTypeString[10];
        if (type == GL_VERTEX_SHADER) {
            strcpy(ShaderTypeString, "VERTEX");
        } else if (type == GL_FRAGMENT_SHADER) {
            strcpy(ShaderTypeString, "FRAGMENT");
        }

        // schrijf een foutmelding naar stderr stream
        std::cerr << "[CompileShader(in, type) | main.cpp] Er is een fout opgetreden tijdens het compileren van een shader." << std::endl;
        std::cerr << "shader type: " << ShaderTypeString << std::endl;
        std::cerr << "Shader info log:\n" << message << std::endl;

        delete [] message;

        TerminateWithError(5);
    }

    return id; // returned de aangemaakte en gecompileerde shader
}

static unsigned int CreateShaders(const std::string& vertexShader, const std::string& fragmentShader)
{
    unsigned int program = glCreateProgram(); // een programma zorgt ervoor dat meerdere shaders aan elkaar gekoppeld kunnen worden

    // compilleert bijde shaders
    unsigned int vertexShaderID = CompileShader(vertexShader, GL_VERTEX_SHADER);
    unsigned int fragmentShaderID = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    // voegt bijde shader aan het programma toe
    glAttachShader(program, vertexShaderID);
    glAttachShader(program, fragmentShaderID);

    // linkt het programma AKA maakt het programma uitvoerbaar
    glLinkProgram(program);

    // kijkt of het programma in ?deze staat? uitgevoerd kan worden
    glValidateProgram(program);

    // verwijderd de shaders, dit kan omdat de shaders nu onderdeel zijn van de program (net als .o bestanden zegmaar)
    glDeleteShader(vertexShaderID);
    glDeleteShader(fragmentShaderID);

    // returned het ID van de program
    return program;
}

int main(int argc, char *argv[])
{
    // (debug) print de uitvoer van argv[0] met als doel te achterhalen wat het path is waarvan main uitgevoerd wordt
#if DEBUG_OUTPUT_ARGV_0==1
    std::cout << "executable path: \n" << argv[0] << "\n\n";
#endif

    GLFWwindow *window; // het scherm

    // initialiseert glfw en tekent een scherm
    if (!glfwInit()) return 2;

    // dit gaat er hopenlijk voor zorgen dat ik OpenGL 3.3 kan gebruiken
    // anders ga ik huilen :(
    // ben letterlijk een uur bezig geweest met dit oplossen ;-;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);

    // glfwCreateWindow geeft een foutmelding
    window = glfwCreateWindow(500, 500, "OpenGL test/yehes", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return 3;
    }

    // selecteert een OpenGL context
    glfwMakeContextCurrent(window);

    // print de ondersteunde GLSL versie
    // handige reminder: dit kan alleen maar als er een actieve OpenGL context is
    // anders krijg je eem EXC_BAD_ACCES en dan ben je echt een jaar bezig met de oplossing zoeken
#if DEBUG_OUTPUT_GLSL_VERSION==1
    std::cout << "Ondersteunde GLSL versie is: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << "\n" << std::endl;
#endif

    // initialiseert GLEW
    if (glewInit() != GLEW_OK) {
        return 4;
    }

    // de buffer is wat er aan de GPU wordt doorgegeven

    unsigned int buffer; // buffer ID
    glGenBuffers(1, &buffer); // maakt buffer aan
    glBindBuffer(GL_ARRAY_BUFFER, buffer); // selecteert de buffer

    // dit verteld OpenGL?of de shader? of de GPU? hoed de vertex geformat is
    glEnable(0); // activeert de type vertex
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, 0); // definieert de type vertex

    // dit zijn de vertexen die in de buffer geladen gaan worden
    float data[6] = {
        -0.5f,-0.5f,
        0.0f, 0.5f,
        0.5f, -0.5f
    };

    // maakt de buffer aan en laad de data in de buffer
    // als je nog geen dat in de buffer wil laden dan kan je NULL invullen op de plek waarnu data staat
    glBufferData(GL_ARRAY_BUFFER, 6*sizeof(float), data, GL_STATIC_DRAW);

    // de shaders worden het geheugen in geladen
    ShaderSource source = ParseShader("./res/Shaders/Basic.shader");

    // (debug) laat de uitvoer van de geparste shaders zien
    // om de mysterieuze bug op te lossen
#if DEBUG_OUTPUT_PARSE_SHADER==1

    std::cout << "ParseShader : VERTEX\r" << source.VertexShader << "\rParseShader : FRAGMENT\r" << source.FragmentShader << std::endl;
    std::cout << "---END---" << "\n" << std::endl;

#endif

    // het programma wordt aangemaakt en de shaders worden eraan gebonden
    unsigned int program = CreateShaders(source.VertexShader, source.FragmentShader);

    // het programma wordt geselecteerd
    glUseProgram(program);

    // dit is de game loop
    while (!glfwWindowShouldClose(window)) {
        // docs.gl zegt dat dit de buffer leeg haalt maar wss is dat een andere buffer want anders zou de driehoek toch verdwijnen?
        glClear(GL_COLOR_BUFFER_BIT);

        // hier moet je renderen
        glDrawArrays(GL_TRIANGLES, 0, 3);

        // hier moet je stoppen met renderen

        // glfw heeft twee buffers de front en de back buffer
        // de front buffer is wat er nu op het scherm staat
        // de back buffer is waar je naar rendert
        // glfwSwapBuffers() wisselt deze om
        glfwSwapBuffers(window);

        // glfwPollEvents() haalt nieuwe informatie van de window system om te kijken of er nieuwe gebruikers input is
        // deze gebruik je als je een continue game loop hebt
        // als er alleen maar iets hoeft te veranderen als er gebruikersinvoer is hebruik je glfwWaitEvents()
        glfwPollEvents();
    }

    // het programma moet verwijderd worden
    glDeleteProgram(program);

    glfwTerminate();
    return 0;
}

Basic.shader:

#shader vertex
#version 330 core

layout(location = 0) in vec4 position;

void main()
{
    gl_Position = position;
}

#shader fragment
#version 330 core

layout(location = 0) out vec4 color;

void main()
{
    color = vec4(1.0, 0.0, 0.0, 1.0);
}

调用glfwCreateWindow()后显示的错误消息:

Setting <GLFWContentView: 0x1007650c0> as the first responder for window <GLFWWindow: 0x10073bea0>, but it is in a different window ((null))! This would eventually crash when the view is freed. The first responder will be set to nil.
(
    0   AppKit                              0x00007fff2e896862 -[NSWindow _validateFirstResponder:] + 578
    1   AppKit                              0x00007fff2dfdd5f0 -[NSWindow _setFirstResponder:] + 31
    2   AppKit                              0x00007fff2e07bd5d -[NSWindow _realMakeFirstResponder:] + 448
    3   OpenGL test                         0x0000000100035c3a createNativeWindow + 1034
    4   OpenGL test                         0x00000001000355cf _glfwPlatformCreateWindow + 63
    5   OpenGL test                         0x000000010002de57 glfwCreateWindow + 887
    6   OpenGL test                         0x00000001000014d7 main + 231
    7   libdyld.dylib                       0x00007fff588ec015 start + 1
)

0 个答案:

没有答案