【问题标题】:Can anyone decipher why this OpenGL Hello World draws a black window?谁能破译为什么这个 OpenGL Hello World 会画一个黑色的窗口?
【发布时间】:2010-08-12 23:08:59
【问题描述】:

请原谅长度(和宽度;这是为了在 IDE 上清晰),但我想展示代码的完整长度,因为目的是现代 VBO 和 GLSL 中的简单 Hello World。

最初是基于http://people.freedesktop.org/~idr/OpenGL_tutorials/02-GLSL-hello-world.pdf

主要的一点是没有打印单一的错误消息或警告 - 你可以看到 printfs 很多(实际上,几乎所有的代码都试图被捕获错误)。

编译是在 -std=c99 -pedantic -O0 -g -Wall 上完成的(没有警告),因此编译器错误也没有太多空间。

我已经把注意力放在了

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

(后者是我还没有完全理解的代码的唯一部分;最晦涩的 func 'ever')

如果故意使着色器无效,信息日志不会打印任何内容,并且会正常打印健康的文本。因此,它既不是着色器字符串分配也不是它们的编译。

你能看到一些可以让它打印一个空白屏幕的东西吗?

如果 glDrawArrays 与 GL_POINTS 一起使用,它会在中间打印一个点,如果 glClear 前面有适当的 glClearColor,它会改变颜色。

#include "SDL.h" // Window and program management
#include "Glee.h" // OpenGL management; Notice SDL's OpenGL header is not included
#include <stdbool.h> // C99 bool

void initGL(void);
void drawGL(void);

int main (int argc, char **argv) {

    //  Load the SDL library; Initialize the Video Subsystem
    if (SDL_Init(SDL_INIT_VIDEO) < 0 ) printf("SDL_Init fail: %s\n", SDL_GetError()); 

    /*  Video Subsystem: set up width, height, bits per pixel (0 = current display's);
        Create an OpenGL rendering context */
    if (SDL_SetVideoMode(800, 600, 0, SDL_OPENGL) == NULL) printf("SDL_SetVideoMode fail: %s\n", SDL_GetError()); 

    // Title and icon text of window
    SDL_WM_SetCaption("gl", NULL);

    // Initialize OpenGL ..
    initGL();

    bool done = false;

    // Loop indefinitely unless user quits
    while (!done) { 

        // Draw OpenGL ..
        drawGL();

        // Deal with SDL events
        SDL_Event sdl_event;
        do {
            if (    sdl_event.type == SDL_QUIT || (sdl_event.type == SDL_KEYDOWN && sdl_event.key.keysym.sym == SDLK_ESCAPE)) {
                    done = true;
                    break;
            }
        } while (SDL_PollEvent(&sdl_event));    

    }

    // Clean SDL initialized systems, unload library and return.
    SDL_Quit(); 
    return 0;
}

GLuint program;
GLuint buffer;
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
void initGL(void) {

    // Generate 1 buffer object; point its name (in uint form) to *buffer. 
    glGenBuffers(1, &buffer);       if(glGetError()) printf("glGenBuffers error\n");

    /*  bind the named (by a uint (via the previous call)) buffer object to target GL_ARRAY_BUFFER (target for vertices)
        apparently, one object is bound to a target at a time. */
    glBindBuffer(GL_ARRAY_BUFFER, buffer);      if(glGetError()) printf("glBindBuffer error\n");

    /*  Create a data store for the current object bound to GL_ARRAY_BUFFER (from above), of a size 8*size of GLfloat,
        with no initial data in it (NULL) and a hint to the GrLib that data is going to be modified once and used a 
        lot (STATIC), and it's going to be modified by the app and used by the GL for drawing or image specification (DRAW)
        Store is not mapped yet. */
    glBufferData(   GL_ARRAY_BUFFER, 4 * 2 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);            if(glGetError()) printf("glBufferData error\n");

    /*  Actually map to the GL client's address space the data store currently bound to GL_ARRAY_BUFFER (from above). 
        Write only. */
    GLfloat *data = (GLfloat *) glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);            if (!*data) printf("glMapBuffer error1\n"); if(glGetError()) printf("glMapBuffer error2\n");

    // Apparently, write some data on the object.
    data[0] = -0.75f;   data[1] = -0.75f;   data[2] = -0.75f;   data[3] =  0.75f;
    data[4] =  0.75f;   data[5] =  0.75f;   data[6] =  0.75f;   data[7] = -0.75f;

    // Unmap the data store. Required *before* the object is used.
    if(!glUnmapBuffer(GL_ARRAY_BUFFER)) printf("glUnmapBuffer error\n");

    // Specify the location and data format of an array of generic vertex attributes ..
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

    // the shaders source
    GLchar *vertex_shader_code[] =      {   "void main(void) { gl_Position = gl_Vertex; }"};
    GLchar *fragment_shader_code[] =        {   "void main(void) { gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); }"};

    /*  Create an empty shader object; used to maintain the source string; intended to run 
        on the programmable vertex processor; GL_SHADER_TYPE is set to  GL_VERTEX_SHADER 
        (e.g. for use on glGetShaderiv)*/
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);           if (!vs) printf("glCreateShader fail\n");

    /*  Set the source code in vs; 1 string; GLchar **vertex_shader_code array of pointers to strings,
        length is NULL, i.e. strings assumed null terminated     */
    glShaderSource(vs, 1, (const GLchar **) &vertex_shader_code, NULL);             if(glGetError()) printf("glShaderSource error\n");

    // Actually compile the shader
    glCompileShader(vs);            GLint compile_status;   glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_status); if (compile_status == GL_FALSE) printf("vertex_shader_code compilation fail\n"); if(glGetError()) printf("glGetShaderiv fail\n");

    // same
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);         if (!fs) printf("glCreateShader fail\n");

    // same
    glShaderSource(fs, 1, (const GLchar **) &fragment_shader_code, NULL);           if(glGetError()) printf("glShaderSource error\n");

    // same
    glCompileShader(fs);            glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_status);  if (compile_status == GL_FALSE) printf("fragment_shader_code compilation fail\n"); if(glGetError()) printf("glGetShaderiv fail\n");

    /*  Empty program for later attachment of shaders; it provides management mechanism for them.
        Shaders can be compiled before or after their attachment. */
    program = glCreateProgram();            if(!program) printf("glCreateProgram fail1\n"); if(glGetError()) printf("glCreateProgram fail2\n");

    /*  Attach shaders to program; this could be done before their compilation or their association with code
        Destined to be linked together and form an executable. */
    glAttachShader(program, vs);            if(glGetError()) printf("glAttachShader fail1\n");
    glAttachShader(program, fs);            if(glGetError()) printf("glAttachShader fail2\n");

    //  Link the program; vertex shader objects create an executable for the vertex processor and similarly for fragment shaders.
    glLinkProgram(program);             GLint link_status; glGetProgramiv(program, GL_LINK_STATUS, &link_status); if (!link_status) printf("linking fail\n"); if(glGetError()) printf("glLinkProgram fail\n");

    /*  Get info log, if any (supported by the standard to be empty).
        It does give nice output if compilation or linking fails. */
    GLchar infolog[2048];
    glGetProgramInfoLog(program, 2048, NULL, infolog); printf("%s", infolog); if (glGetError()) printf("glGetProgramInfoLog fail\n");

    /*  Install program to rendering state; one or more executables contained via compiled shaders inclusion. 
        Certain fixed functionalities are disabled for fragment and vertex processors when such executables
        are installed, and executables may reimplement them. See glUseProgram manual page about it. */
    glUseProgram(program);      if(glGetError()) printf("glUseProgram fail\n");
}


void drawGL(void) {
    // Clear color buffer to default value
    glClear(GL_COLOR_BUFFER_BIT);       if(glGetError()) printf("glClear error\n");

    // Render the a primitive triangle 
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);      if(glGetError()) printf("glDrawArrays error\n");

    SDL_GL_SwapBuffers();
}

【问题讨论】:

    标签: opengl opengl-3


    【解决方案1】:

    扩展 Calvin1602 的答案:

    ftransform 假设您不使用矩阵。 gl_Vertex 在这里应该没问题,考虑到最终结果应该是 [-1:1]^3 立方体,并且他的数据在那个区间内。 现在,如果你真的想要全部使用 GL3.1,它应该是 gl_VertexAttrib[0],但是 gl_Vertex 和 gl_VertexAttrib[0] 的别名(见下文)。

    至于启用。你使用顶点属性0,所以你需要:

    glEnableVertexAttribArray(0)

    关于弄清楚一般情况的建议:不要清除到黑色,这会让生活变得更加难以弄清楚是否绘制了黑色或什么都没有绘制(使用 glClearColor 来改变它)。

    在迂腐方面,您的 glShaderSource 调用看起来很可疑,因为您四处投射指针。我会用

    清理它
    glShaderSource(fs, 1, fragment_shader_code, NULL);
    

    它目前与 &fragment_shader_code 一起工作的原因是interesting,但在这里,我不明白你为什么不简化。

    == 编辑添加 ==

    啊,不知道我对 gl_VertexAttrib 的想法是什么。好久没看这个了,自己做了个特写……

    在 GL4.1 之前,提供非内置属性的标准方法实际上并不简单。

    // glsl
    attribute vec4 myinput;
    gl_Position = myinput;
    
    // C-code, rely on linker for location
    glLinkProgram(prog);
    GLint location = glGetAttribLocation(prog, "myinput");
    glEnableVertexAttribArray(location, ...)
    
    // alternative C-code, specify location
    glBindAttribLocation(prog, 0, "myinput");
    glLinkProgram(prog);
    glEnableVertexAttribArray(0, ...)
    

    GL4.1终于支持直接在shader中指定位置了。

    // glsl 4.10
    layout (location=0) in vec4 myinput;
    

    【讨论】:

    • 哦,是的,glEnableVertexAttribArray。你绝对应该使用矩阵。不使用它们会使代码更小,但并不简单(至少要理解)。
    • 非常感谢您的意见; glEnableVertexAttribArray(0) 包含在现场,它使它呈现形状。感谢关于 Clearing 的建议,我也不喜欢不必要的东西。 gl_VertexAttrib[0] 似乎无法被驱动程序编译器 '0(1) 识别:错误 C1008:未定义的变量“gl_VertexAttrib”' 在括号或圆括号中。字符串的怪异数组自然而然,别问为什么,我可能读过很多关于指针的文章。
    • [编辑时间已过] 我怀疑这是因为上下文来自 SDL1.2(关于 gl_VertexAttrib)。
    【解决方案2】:
    • 在顶点着色器中:gl_Position = ftransform();而不是 gl_Vertex。这会将输入向量乘以模型视图矩阵(给出相机空间中的点),然后乘以变换矩阵(给出标准化设备坐标中的点,即它在屏幕上的位置)
    • glEnable(GL_VERTEX_ARRAY);在渲染之前。参见glDrawArray reference:“如果未启用 GL_VERTEX_ARRAY,则不会生成几何图元。”

    ...我没有看到其他任何东西

    【讨论】:

    • 第一个不会改变结果;第二个段错误(如果它在 glDrawArrays 之前或在 init 结束时)。在 drawGL() 之后的 4 步后回溯没有代码。
    猜你喜欢
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 2021-06-05
    • 2010-11-11
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多