黑屏OpenGL

时间:2013-01-21 03:55:49

标签: c++ opengl

我正在尝试学习如何使用着色器程序在OpenGL 2.0中进行一些基本渲染,并且我很难将任何顶点数据显示在屏幕上。现在我不知道我的问题所在。我已经通过了一些例子,在我的代码中没有任何明显的突出显示错误,但我确信我错过了一些简单的东西。我会尝试简短地使用我的代码。

我在这里也问了同样的问题:gamedev.stackexchange,但不幸的是我没有收到任何能够解决我问题的答案。

尝试答案的快速摘要:

  1. 我可以将背景颜色清除为红色,因此我知道我的显示代码有效。
  2. 相机代码不会修改矩阵堆栈。
  3. 没有着色器编译器错误。
  4. 感谢您的帮助。

    bool GameCore::Start(int iCmdShow)
    {
        const LPCWSTR appname = TEXT("Maze Game");
        // Create the Window and kill the program if this fails.
        if(!wm->Create(appname))
        {
            return FALSE;
        }
    
        // Initialize OpenGL
        wm->InitGraphics();
        cam = wm->cam;
    
        Vector3 *v = new Vector3(0.0f,0.0f,0.0f);
        wm->testSprite = new Sprite(v);
    
        // Start the update loop.
        _beginthread(&GameCore::Execute, 0, this);
    
        // Blocking function to run the application.
        wm->RunWindow(iCmdShow);
        return true;
    }
    
    // Initialize OpenGL graphics
    void OpenGLWM::InitGraphics()
    {
        hDC = GetDC(hWnd);
    
        SetupPixelFormat();
    
        hRC = wglCreateContext(hDC);
        wglMakeCurrent(hDC, hRC);
    
        glClearColor(1, 0, 0, 0);
        glClearDepth(1.0);
        glEnable(GL_DEPTH_TEST);
    
        GLenum err = glewInit();
        if (GLEW_OK != err)
        {
            // Add error handling.
        }
    
        cam = new Camera(0, 0, -10);
        program = new ShaderProgram();
        program->Initialize();
    }
    
    // Set up pixel format for graphics initialization
    void OpenGLWM::SetupPixelFormat()
    {
        PIXELFORMATDESCRIPTOR pfd, *ppfd;
        int pixelformat;
    
        ppfd = &pfd;
    
        ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
        ppfd->nVersion = 1;
        ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        ppfd->dwLayerMask = PFD_MAIN_PLANE;
        ppfd->iPixelType = PFD_TYPE_COLORINDEX;
        ppfd->cColorBits = 16;
        ppfd->cDepthBits = 16;
        ppfd->cAccumBits = 0;
        ppfd->cStencilBits = 0;
    
        pixelformat = ChoosePixelFormat(hDC, ppfd);
        SetPixelFormat(hDC, pixelformat, ppfd);
    }
    
    // Camera Constructor
    Camera::Camera(double dX, double dY, double dZ)
    {
        Vector3 V(dX, dY, dZ);
        Vector3 R(0,0,0);
        Initialization(V, R);
    }
    
    bool ShaderProgram::Initialize()
    {
        GLint giLinked;
        GLbyte vShaderStr[] =
        "#version 110               \n"
        "attribute vec3 in_Position;\n"
        "void main()\n"
        "{\n"
            "gl_Position = vec4(in_Position, 1.0);\n"
        "}\n";
    
        GLbyte pShaderStr[] =
        "#version 110               \n"
        "precision mediump float;\n"
        "void main()\n"
        "{\n"
            "gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
        "}\n";
    
        // Load the shaders
        vertexShader.LoadShader((const char *)&vShaderStr, GL_VERTEX_SHADER);
        pixelShader.LoadShader((const char *)&pShaderStr, GL_FRAGMENT_SHADER);
    
        guiProgram = glCreateProgram();
    
        if(guiProgram == 0)
        {
            return false;
        }
        // Add the shaders to the program
        glAttachShader(guiProgram, vertexShader.guiShader);
        glAttachShader(guiProgram, pixelShader.guiShader);
    
        // Bind the position coordinates
        glBindAttribLocation(guiProgram, 0, "in_Position");
    
        // Link the program
        glLinkProgram(guiProgram);
        int iError = glGetError();
        // Get the link status
        glGetProgramiv(guiProgram, GL_LINK_STATUS, &giLinked);
    
        if(giLinked == 0)
        {
            // Add error handling.
            return false;
        }
        return true;
    }
    
    GLuint BaseShader::LoadShader(const char *cShaderSrc, GLenum type)
    {
        GLint guiCompiled;
        // Creates an empty shader object.
        guiShader = glCreateShader(type);
    
        if(guiShader == 0)
        {
            return 0;
        }
        // Load the shader.
        glShaderSource(guiShader, 1, &cShaderSrc, NULL);
    
        // Compile the shader
        glCompileShader(guiShader);
    
        // Check the compile status
        glGetShaderiv(guiShader, GL_COMPILE_STATUS, &guiCompiled);
    
        if(guiCompiled == 0)
        {
            // TODO: ADD ERROR LOGGING
            GLint infoLen = 0;
            glGetShaderiv(guiShader, GL_INFO_LOG_LENGTH, &infoLen);
            if(infoLen > 1)
            {
                char* infoLog = (char *)malloc(sizeof(char) * infoLen);
                glGetShaderInfoLog(guiShader, infoLen, NULL, infoLog);
                free(infoLog);
            }
            return 0;
        }
        return guiShader;
    }
    
    // Sprite inherits from Render Object
    Sprite::Sprite(Vector3 *_vPosition)
    {
        // Initialize the position.
        vPosition = _vPosition;
        // Create verticies
        vertexStruct * v = new vertexStruct[4];
        v[0].SetPosition(-2, 2, -40);
        v[0].SetColor(128, 128, 128, 255);
        v[1].SetPosition(2, 2, -40);
        v[1].SetColor(128, 128, 128, 255);
        v[2].SetPosition(2, -2, -40);
        v[2].SetColor(128, 128, 128, 255);
        v[3].SetPosition(-2, -2, -40);
        v[3].SetColor(128, 128, 128, 255);
    
        // Create the indicies.
        GLubyte * i = new GLubyte[6];
        i[0] = 0;
        i[1] = 1;
        i[2] = 2;
        i[3] = 0;
        i[4] = 2;
        i[5] = 3;
    
        Initialize(v, 4, i, 6);
    }
    
    void RenderObject::Initialize(vertexStruct *_vertices, unsigned int _uiNumVertices, GLubyte *_indices, unsigned int _uiNumIndicies)
    {
        vertices = _vertices;
        indices = _indices;
        uiNumVertices = _uiNumVertices;
        uiNumIndices = _uiNumIndicies;
        CreateBufferObjects();
    }
    
    void RenderObject::CreateBufferObjects()
    {
        // Get an id for the Vector3 buffer.
        glGenBuffers((GLsizei)1, &uiVertexBuffer);
        // Bind the buffer so we can "upload" the data.
        glBindBuffer(GL_ARRAY_BUFFER, uiVertexBuffer);
        // Upload the data to OpenGL.
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertexStruct) * uiNumVertices, vertices, GL_STATIC_DRAW);
    
        // Get an id for the indice buffer.
        glGenBuffers(1, &uiIndiceBuffer);
        // Bind the indice buffer so we can "upload" the data.
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, uiIndiceBuffer);
        // Upload the data to OpenGL.
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * uiNumIndices, indices, GL_STATIC_DRAW);
    }
    
    bool WindowManager::RunWindow(int iCmdShow)
    {
        // Display the window
        ShowWindow(hWnd, iCmdShow);
        UpdateWindow(hWnd);
    
        // Event loop
        while (1)
        {
            if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)
            {
                if (!GetMessage(&msg, NULL, 0, 0))
                {
                    return TRUE;
                }
    
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            // It would be better if this was its own thread.
            if(!DoWork())
            {
                return false;
            }
        }
    return true;
    }
    
    // "Draw" function.
    bool OpenGLWM::DoWork()
    {
        glClearColor(0, 0, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT);
    
        glUseProgram(program->guiProgram);
    
        testSprite->Draw();
        // Show the new scene
        SwapBuffers(hDC);
        return true;
    }
    
    void RenderObject::Draw()
    {
        // Bind the vertex buffer.
        glBindBuffer(GL_ARRAY_BUFFER, uiVertexBuffer);
        // Set where the vertex data is.
        glVertexAttribPointer(VertexEnum::Data, 3, GL_FLOAT, GL_FALSE, sizeof(vertexStruct), 0);
        glEnableVertexAttribArray(0);//VertexEnum::Data);
    
        // Load the colors.
        glVertexAttribPointer(VertexEnum::Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, 12, (void*)offsetof(vertexStruct, color));
    
        glEnableVertexAttribArray(1);//VertexEnum::Color);
        // Bind the indice buffer.
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, uiIndiceBuffer);
        glDrawElements(GL_TRIANGLE_STRIP, uiNumIndices, GL_UNSIGNED_BYTE, 0);
    }
    
    void OpenGLWM::ResizeGraphics()
    {
        // Get new window size
        RECT rect;
        int width;
        int height;
        GLfloat aspect;
    
        GetClientRect(hWnd, &rect);
        width = rect.right;
        height = rect.bottom;
        aspect = (GLfloat)width / height;
    
        // Adjust graphics to window size
        glViewport(0, 0, width, height);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0, aspect, 1.0, 100.0);
        glMatrixMode(GL_MODELVIEW);
        // Call the base function
        WindowManager::ResizeGraphics();
    }
    

1 个答案:

答案 0 :(得分:6)

程序存在一些问题,这些问题合并导致渲染不足:

  1. 首先,世界坐标顶点到屏幕坐标的转换不会发生。具体来说,顶点着色器仅将输入顶点值复制到最终顶点位置(通常称为“pass-thru”着色器)。这个问题有多种解决方案:

    • 使用了非常旧的ftransform() GLSL例程,该例程将返回转换后的顶点值:

      gl_Position = ftransform();
      
    • 使用隐式定义的GLSL矩阵:

      gl_Position = gl_ModelViewProjectionMatrix * vec4(in_Position, 1.0);
      
    • 或使用单独定义的矩阵:

      gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * vec4(in_Position, 1.0);
      
  2. 下一个问题是定义的几何体与渲染的几何形状不一致。特别是索引元素数组,定义如下

    // Create the indicies.
    GLubyte * i = new GLubyte[6];
    i[0] = 0;
    i[1] = 1;
    i[2] = 2;
    i[3] = 0;
    i[4] = 2;
    i[5] = 3;
    

    用于两个三角形,但glDrawElements调用将GL_TRIANGLE_STRIP指定为几何图元。这可以通过两种方式解决:

    • 将GL_TRIANGLES用于几何图元类型,或
    • 将三角形条的索引元素列表修复为:

      // Create the indicies.
      GLubyte * i = new GLubyte[4];
      i[0] = 1;
      i[1] = 0;
      i[2] = 2;
      i[3] = 3;
      

    这将在条带中产生两个三角形,并使用适当的顶点绕组进行正确的背面剔除。

  3. 最后,在请求深度缓冲区并启用深度测试时,每帧不清除深度缓冲区。将GL_DEPTH_BUFFER_BIT添加到glClear调用即可实现此目的。