2013-01-21 76 views
1

我想要學習如何在OpenGL 2.0中使用着色器程序進行一些基本渲染,並且難以獲得任何頂點數據以顯示在屏幕上。現在我不知道我的問題在哪裏。我已經通過了一些例子,在我的代碼中沒有任何明顯的突出問題,但我相信我錯過了一些簡單的東西。我會盡量縮短我的代碼。空白屏幕OpenGL

我也在這裏問過同樣的問題:gamedev.stackexchange,但不幸的是我還沒有收到任何解決我的問題的答案。嘗試答案

快速摘要:

  1. 我可以明確的背景顏色爲紅色,所以我知道我的顯示代碼工作。
  2. 相機代碼不會修改矩陣堆棧。
  3. 沒有着色器編譯器錯誤。

謝謝你的幫助。

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(); 
} 
+0

@JesseGood如果GPU不支持着色器,那麼着色器是否會編譯? – leemes

+0

@JesseGood我正在使用高端顯卡,所以它應該。 – Alikar

+0

@leemes:我認爲這是可能的,肯定的,但似乎並不在這裏是問題。 –

回答

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調用中即可完成此操作。

+0

再次感謝您的幫助radical7。 – Alikar