无法渲染到GtkGLArea

时间:2019-03-26 12:29:23

标签: c++ opengl gtk3

我尝试将三角形渲染为GtkGLArea,但是我只看到用glClearColor()清除框架的颜色。

请注意:

  • 我知道三角形太大,以至于会填满整个屏幕,但是我也尝试过较小的三角形,但是它也不起作用。
  • 我还知道,通常我不应该在每次渲染之前创建程序,我只是在这里这样做以使示例简短。
  • 我非常确定该错误既不会出现在LoadShaders中,也不会出现在着色器中,因为我已经使用GLFW尝试了完全相同的功能,并且它们可以正常工作。

可能导致问题的原因:

  • 我没有刷新当前帧或交换帧缓冲区,因为文档(https://developer.gnome.org/gtk3/stable/GtkGLArea.html)没有提到我必须这样做。我已经尝试过glFlush(),但也没有帮助。

  • 我假设屏幕坐标在所有轴上都从-1变为1,就像在普通OpenGL中一样。也许这是错误的,但我也无法在文档中找到任何内容。

有人可以帮我吗?

这是我的编译方式:

g++ -O3 -s -o main main.cpp -isystem include -Llibs -DNDEBUG `pkg-config --cflags gtk+-3.0` `pkg-config --libs gtk+-3.0` -lepoxy -lm

这是我的代码:

#include <gtk/gtk.h>
#include <epoxy/gl.h>
#include <epoxy/glx.h>
#include <iostream>
#include <vector>

GLuint LoadShaders(char const* vertex, char const* fragment){

    // Create the shaders
    GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
    GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

    GLint Result = GL_FALSE;
    int InfoLogLength;

    // Compile Vertex Shader
    glShaderSource(VertexShaderID, 1, &vertex , NULL);
    glCompileShader(VertexShaderID);

    // Check Vertex Shader
    glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 ){
        std::vector<char> VertexShaderErrorMessage(InfoLogLength+1);
        glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
        printf("%s\n", &VertexShaderErrorMessage[0]);
    }

    // Compile Fragment Shader
    glShaderSource(FragmentShaderID, 1, &fragment , NULL);
    glCompileShader(FragmentShaderID);

    // Check Fragment Shader
    glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 ){
        std::vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
        glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
        printf("%s\n", &FragmentShaderErrorMessage[0]);
    }

    // Link the program
    GLuint ProgramID = glCreateProgram();
    glAttachShader(ProgramID, VertexShaderID);
    glAttachShader(ProgramID, FragmentShaderID);
    glLinkProgram(ProgramID);

    // Check the program
    glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    if ( InfoLogLength > 0 ){
        std::vector<char> ProgramErrorMessage(InfoLogLength+1);
        glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
        printf("%s\n", &ProgramErrorMessage[0]);
    }

    glDetachShader(ProgramID, VertexShaderID);
    glDetachShader(ProgramID, FragmentShaderID);

    glDeleteShader(VertexShaderID);
    glDeleteShader(FragmentShaderID);

    return ProgramID;
}

char const* vertShader = R"GLSL(
#version 330 core
void main(){
    gl_Position.z = 0.0;
    gl_Position.w = 1.0;
    if (0 == gl_VertexID) {
        gl_Position.x = -100.0;
        gl_Position.y = -100.0;
    }
    if (2 == gl_VertexID) {
        gl_Position.x =  0.0;
        gl_Position.y =  100.0;
    }
    if (1 == gl_VertexID) {
        gl_Position.x =  100.0;
        gl_Position.y = -100.0;
    }
}
)GLSL";

char const* fragShader = R"GLSL(
#version 330 core
layout(location = 0) out vec4 color;
void main(){
    color = vec4(1.0, 0.0, 0.0, 1.0);
}
)GLSL";

gboolean
render(GtkGLArea*, GdkGLContext*, gpointer) {
    glClearColor(0.5, 0.5, 0.5, 0);
    glClear(GL_COLOR_BUFFER_BIT);

    GLuint programID;
    programID = LoadShaders(vertShader, fragShader);

    glUseProgram(programID);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    //glFlush();
    glDeleteProgram(programID);
    return TRUE;
}

int
main(int argc, char** argv) {
    gtk_init(&argc, &argv);

    auto window{gtk_window_new(GTK_WINDOW_TOPLEVEL)};
    auto glWidget{gtk_gl_area_new()};
    gtk_container_add(GTK_CONTAINER(window), glWidget);
    g_signal_connect (glWidget, "render", G_CALLBACK(render), nullptr);
    gtk_widget_show_all(window);

    gtk_main();

    return EXIT_SUCCESS;
}

1 个答案:

答案 0 :(得分:2)

我能想到的两件事:

  • 您不是从操作系统请求Core上下文。看来您必须重写create-context并创建+返回gdk_gl_context_set_required_versionGdkGLContext
  • 当您执行启动Core上下文时,即使您完全在顶点着色器中生成几何图形,我也很确定您仍然需要VAO绑定。

RE:缺少VAO:

使用此GLFW程序和VAO创建/绑定已将其注释掉:

#include <glad/glad.h>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <iostream>

void CheckStatus( GLuint obj, bool isShader )
{
    GLint status = GL_FALSE, log[ 1 << 11 ] = { 0 };
    ( isShader ? glGetShaderiv : glGetProgramiv )( obj, isShader ? GL_COMPILE_STATUS : GL_LINK_STATUS, &status );
    ( isShader ? glGetShaderInfoLog : glGetProgramInfoLog )( obj, sizeof( log ), NULL, (GLchar*)log );
    if( status == GL_TRUE ) return;
    std::cerr << (GLchar*)log << "\n";
    std::exit( EXIT_FAILURE );
}

void AttachShader( GLuint program, GLenum type, const char* src )
{
    GLuint shader = glCreateShader( type );
    glShaderSource( shader, 1, &src, NULL );
    glCompileShader( shader );
    CheckStatus( shader, true );
    glAttachShader( program, shader );
    glDeleteShader( shader );
}

const char* vert = 1 + R"GLSL(
#version 330 core
void main(){
    gl_Position.z = 0.0;
    gl_Position.w = 1.0;
    if (0 == gl_VertexID) {
        gl_Position.x = -100.0;
        gl_Position.y = -100.0;
    }
    if (2 == gl_VertexID) {
        gl_Position.x =  0.0;
        gl_Position.y =  100.0;
    }
    if (1 == gl_VertexID) {
        gl_Position.x =  100.0;
        gl_Position.y = -100.0;
    }
}
)GLSL";

const char* frag = 1 + R"GLSL(
#version 330 core
layout(location = 0) out vec4 color;
void main(){
    color = vec4(1.0, 0.0, 0.0, 1.0);
}
)GLSL";

int main( int, char** )
{
    glfwSetErrorCallback( []( int, const char* desc ) { std::cerr << desc << "\n"; std::exit( EXIT_FAILURE ); } );
    glfwInit();
    glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE );
    glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    GLFWwindow* window = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL );
    glfwMakeContextCurrent( window );
    gladLoadGLLoader( (GLADloadproc)glfwGetProcAddress );

    //GLuint vao = 0;
    //glGenVertexArrays( 1, &vao );
    //glBindVertexArray( vao );

    GLuint prog = glCreateProgram();
    AttachShader( prog, GL_VERTEX_SHADER, vert );
    AttachShader( prog, GL_FRAGMENT_SHADER, frag );
    glLinkProgram( prog );
    CheckStatus( prog, false );

    while( !glfwWindowShouldClose( window ) )
    {
        glfwPollEvents();
        int w, h;
        glfwGetFramebufferSize( window, &w, &h );
        glViewport( 0, 0, w, h );

        glClearColor( 0.5, 0.5, 0.5, 0 );
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glUseProgram( prog );
        glDrawArrays( GL_TRIANGLES, 0, 3 );
        glfwSwapBuffers( window );
    }

    glfwTerminate();
}

在具有Mesa 13.0.6的llvmpipe后端的Linux上运行&the MESA_DEBUG=1 envvar给了我一个灰色的窗口,并且此消息在stdout上显示:

Mesa: User error: GL_INVALID_OPERATION in glDrawArrays(no VAO bound)

还原VAO会显示预期的红色窗口。