2013-08-05 39 views
1

所以我做了一個缺乏塔防遊戲。我與他們共享一個構建,所以我可以檢查是否一切正常,因爲它應該在另一臺主機上。不同電腦的渲染問題

實際情況是,雖然所有東西都完美地呈現在我身邊(在我的mac/xcode + windows/visual studio 2012上),但在我的朋友那邊,似乎幾何圖形已經搞砸了。我的屏幕上的每個對象都由一個VBO表示,我每次都使用它來渲染到不同的位置。但是,似乎我的維也納組織有從所有模型導入的所有幾何圖形。 (。因此,塔與一側的樹)

這裏的結果:

enter image description here(我的電腦)enter image description here(我的朋友的電腦)

正如現在我已經成功地調試這個問題直到某個點。我可以告訴它不是我導入我的模型的方式,因爲我在創建一個帶有所有向量的debug.txt文件,然後將它們發送到gpu作爲VBO,並在兩臺計算機上輸出相同的值。所以我的載體不會因爲內存問題或類似的東西而變得混亂。所以我想也許這是我設置或渲染我的維也納組織的方式

最讓我感到震驚的是,爲什麼事情在我的電腦上工作,而他們不在我的朋友電腦上。我知道的一個區別是,我的電腦是一個開發者站(無論這意味着什麼),而我的朋友的電腦不是。

這是我的VBO加載函數和我的VBO繪圖函數: 我使用glfw創建我的窗口和上下文,幷包含glew頭文件以啓用一些較新的opengl函數。

void    G4::Renderer::LoadObject(
              G4::TILE_TYPES aType, 
              std::vector<float> &v_data, 
              std::vector<float> &n_data, 
              std::vector<float> &t_data, 
              float scale, 
              bool has_texture, 
              unsigned int texture_id 
              ) 
{ 

    unsigned int vertices_id, vertices_size, normals_id, texturecoordinates_id; 

    vertices_size = static_cast<unsigned int>(v_data.size()); 

    glGenBuffers(1, &vertices_id); 
    glGenBuffers(1, &normals_id); 

    //::->Vertex array buffer upload. 
    glBindBuffer(GL_ARRAY_BUFFER, vertices_id); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*v_data.size(), &v_data.front(), GL_STATIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    //::->Normal Array buffer upload. 
    glBindBuffer(GL_ARRAY_BUFFER, normals_id); 
    glBufferData(GL_ARRAY_BUFFER, sizeof(float)*n_data.size(), &n_data.front(), GL_STATIC_DRAW); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 



    if (has_texture) 
    { 
     glGenBuffers(1, &texturecoordinates_id); 

     glBindBuffer(GL_ARRAY_BUFFER, texturecoordinates_id); 
     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*t_data.size(), &(t_data[0]), GL_STATIC_DRAW); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 
    } 


    this->vbos[aType].Update(vertices_id, vertices_size, normals_id, texture_id, texturecoordinates_id, scale, has_texture); 



} 

抽獎代碼:

void G4::Renderer::DrawUnit(G4::VBO aVBO, bool drawWithColor, float r, float g, float b, float a) 
{ 
    bool model_has_texture = aVBO.HasTexture(); 

    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_NORMAL_ARRAY); 

    if (model_has_texture && !drawWithColor) { 
     glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
     glEnable(GL_TEXTURE_2D); 
    } 

    if (drawWithColor) 
    { 
     glColor4f(r, g, b, a); 
    } 

    glScalef(aVBO.GetScaleValue(), aVBO.GetScaleValue(), aVBO.GetScaleValue()); 

    glBindBuffer(GL_ARRAY_BUFFER, aVBO.GetVerticesID()); 
    glVertexPointer(3, GL_FLOAT, 0, 0); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 

    glBindBuffer(GL_ARRAY_BUFFER, aVBO.GetNormalsID()); 
    glNormalPointer(GL_FLOAT, 0, 0); 
    glBindBuffer(GL_ARRAY_BUFFER, 0); 


    if (model_has_texture && !drawWithColor) 
    { 
     glBindTexture(GL_TEXTURE_2D, aVBO.GetTextureID()); 
     glBindBuffer(GL_ARRAY_BUFFER, aVBO.GetTextureCoordsID()); 
     glTexCoordPointer(2, GL_FLOAT, 0, 0); 
     glBindBuffer(GL_ARRAY_BUFFER, 0); 
    } 

    glDrawArrays(GL_TRIANGLES, 0, aVBO.GetVerticesSize()); 

    if (model_has_texture && !drawWithColor) { 
     glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
     glDisable(GL_TEXTURE_2D); 

    } 

    glDisableClientState(GL_NORMAL_ARRAY); 
    glDisableClientState(GL_VERTEX_ARRAY); 

} 

我的想法,我希望有人能告訴我如何繼續調試。

+0

這些文物看起來更像一個光柵化問題,不是一個幾何問題。由於您正在渲染實際的幾何圖形,所以這些工件因爲它們對硬件問題可見而提示。詢問你的朋友是否超頻他的GPU和/或其內存。還可以嘗試在驅動程序更新之後或使用相同類型的其他GPU替換之後發生的情況。 – datenwolf

+0

我拒絕相信它是硬件相關的。另外我試了一臺我的另一位朋友的電腦,他的結果和我的其他朋友一樣。此外,你所謂的工件,因爲我提到的問題,我設法將它們識別爲(可能)其他所有模型的導入幾何。他們似乎合併爲一個 – Bisder

+1

你總是可以把它全部拋出,並重新開始使用[現代openGL API](http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Chapter-1 :-The-Graphics-Pipeline.html)(半認真的) –

回答

5

OpenGL規範。並沒有指定當你發出一個繪製調用比你的緩衝存儲更多的頂點時應該發生的確切行爲。這可以在一臺機器上正常工作,而不是在另一臺機器上正常工作的原因歸結爲實施。如果出現這種情況,每個供應商都可以隨意做他們想做的任何事情,因此渲染工件可能在AMD硬件上顯示,但在nVIDIA或Intel上完全不顯示。更糟糕的是,當要求繪製太多頂點時,實際上沒有錯誤狀態由glDrawArrays (...)的調用產生。您肯定需要在來自多個供應商的硬件上測試您的軟件以捕捉這些類型的錯誤;在您的計算機中製造GPU的人員以及驅動程序版本與操作系統和編譯器一樣重要。

儘管如此,仍然有辦法來捕捉這些愚蠢的錯誤。 gDEBugger就是其中之一,下面還將討論一個新的OpenGL擴展。我更喜歡使用新擴展,因爲根據我的經驗,除了不贊成使用的API調用和錯誤(可配置gDEBugger進行監控)外,擴展還會警告您使用低效率對齊的數據結構以及各種其他便攜性和性能問題。

我想在我的軟件中添加一些用於使用OpenGL調試輸出的代碼,因爲這是一個錯誤行爲的示例,它實際上並不會產生您可以用glGetError (...)捕獲的錯誤。有時候,你可以用調試輸出捕捉這些錯誤(儘管我只是測試了它,而這不是其中的一種情況)。你需要一個OpenGL調試環境才能工作(設置這個過程的過程是高度依賴於平臺的),但是它是一個上下文標誌,就像前向/後向兼容和核心(glfw應該讓你這麼容易)。對於x86平臺

自動斷點宏觀


// Breakpoints that should ALWAYS trigger (EVEN IN RELEASE BUILDS) [x86]! 
#ifdef _MSC_VER 
# define eTB_CriticalBreakPoint() if (IsDebuggerPresent()) __debugbreak(); 
#else 
# define eTB_CriticalBreakPoint() asm (" int $3"); 
#endif 


啓用OpenGL調試輸出(需要調試上下文和相對較新的驅動程序時,OpenGL 4.x的時代)


// SUPER VERBOSE DEBUGGING! 
if (glDebugMessageControlARB != NULL) { 
    glEnable     (GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); 
    glDebugMessageControlARB (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); 
    glDebugMessageCallbackARB ((GLDEBUGPROCARB)ETB_GL_ERROR_CALLBACK, NULL); 
} 


一些用更有意義的文字取代列舉值的重要實用功能


const char* 
ETB_GL_DEBUG_SOURCE_STR (GLenum source) 
{ 
    static const char* sources [] = { 
    "API", "Window System", "Shader Compiler", "Third Party", "Application", 
    "Other", "Unknown" 
    }; 

    int str_idx = 
    min (source - GL_DEBUG_SOURCE_API, 
      sizeof (sources)/sizeof (const char *)); 

    return sources [str_idx]; 
} 

const char* 
ETB_GL_DEBUG_TYPE_STR (GLenum type) 
{ 
    static const char* types [] = { 
    "Error",  "Deprecated Behavior", "Undefined Behavior", "Portability", 
    "Performance", "Other",    "Unknown" 
    }; 

    int str_idx = 
    min (type - GL_DEBUG_TYPE_ERROR, 
      sizeof (types)/sizeof (const char *)); 

    return types [str_idx]; 
} 

const char* 
ETB_GL_DEBUG_SEVERITY_STR (GLenum severity) 
{ 
    static const char* severities [] = { 
    "High", "Medium", "Low", "Unknown" 
    }; 

    int str_idx = 
    min (severity - GL_DEBUG_SEVERITY_HIGH, 
      sizeof (severities)/sizeof (const char *)); 

    return severities [str_idx]; 
} 

DWORD 
ETB_GL_DEBUG_SEVERITY_COLOR (GLenum severity) 
{ 
    static DWORD severities [] = { 
    0xff0000ff, // High (Red) 
    0xff00ffff, // Med (Yellow) 
    0xff00ff00, // Low (Green) 
    0xffffffff // ??? (White) 
    }; 

    int col_idx = 
    min (severity - GL_DEBUG_SEVERITY_HIGH, 
      sizeof (severities)/sizeof (DWORD)); 

    return severities [col_idx]; 
} 


調試輸出回調(有點亂,因爲它打印在不同顏色的每個字段在我的軟件)


void 
ETB_GL_ERROR_CALLBACK (GLenum  source, 
         GLenum  type, 
         GLuint  id, 
         GLenum  severity, 
         GLsizei  length, 
         const GLchar* message, 
         GLvoid*  userParam) 
{ 
    eTB_ColorPrintf (0xff00ffff, "OpenGL Error:\n"); 
    eTB_ColorPrintf (0xff808080, "=============\n"); 

    eTB_ColorPrintf (0xff6060ff, " Object ID: "); 
    eTB_ColorPrintf (0xff0080ff, "%d\n", id); 

    eTB_ColorPrintf (0xff60ff60, " Severity: "); 
    eTB_ColorPrintf (ETB_GL_DEBUG_SEVERITY_COLOR (severity), 
         "%s\n", 
         ETB_GL_DEBUG_SEVERITY_STR (severity)); 

    eTB_ColorPrintf (0xffddff80, " Type:  "); 
    eTB_ColorPrintf (0xffccaa80, "%s\n", ETB_GL_DEBUG_TYPE_STR  (type)); 

    eTB_ColorPrintf (0xffddff80, " Source: "); 
    eTB_ColorPrintf (0xffccaa80, "%s\n", ETB_GL_DEBUG_SOURCE_STR (source)); 

    eTB_ColorPrintf (0xffff6060, " Message: "); 
    eTB_ColorPrintf (0xff0000ff, "%s\n\n", message); 

    // Force the console to flush its contents before executing a breakpoint 
    eTB_FlushConsole(); 

    // Trigger a breakpoint in gDEBugger... 
    glFinish(); 

    // Trigger a breakpoint in traditional debuggers... 
    eTB_CriticalBreakPoint(); 
} 



因爲我不能真正得到你的觸發一個調試輸出事件的情況,我想我至少會展示一個我能觸發的事件的例子。這不是一個你可以用glGetError (...)捕捉的錯誤,或者是一個關於這個問題的錯誤。但可以肯定的是平局通話的問題,你可能會完全無視你的項目的持續時間不使用這個擴展:)

 
OpenGL Error: 
============= 
Object ID: 102 
Severity: Medium 
Type:  Performance 
Source: API 
Message: glDrawElements uses element index type 'GL_UNSIGNED_BYTE' that is not optimal for the current hardware configuration; consider using 'GL_UNSIGNED_SHORT' instead. 
+0

這是超過我可以要求,非常感謝你。所有關於opengl上下文中額外調試工具的額外信息都非常非常有趣,而我並不知道這些信息。我認爲glGetError是你唯一的朋友。 – Bisder

3

經過與朋友們進行進一步的調試會話和很多試用,我設法找到了問題。這花了我兩天的時間才弄清楚,實際上這只是一個愚蠢的錯誤。

glDrawArrays(GL_TRIANGLES, 0, aVBO.GetVerticesSize()); 

上面的代碼沒有得到頂點大小(作爲點),而是作爲存儲在那裏的浮點數的總數。所以一切都乘以3.添加一個/ 3解決它。

因此,我假設,因爲從其他vbos存儲在gpu上的vbo「偷走」數據乘以3倍的總點數。 (因此,樹模型堆棧到我的塔)。

雖然我無法弄清楚,但想要一個答案,就是爲什麼在我的電腦上一切都很好,但沒有在其他電腦上。正如我在我原來的問題中所指出的那樣,暗示將是我的電腦實際上是一個開發者站,而我的朋友不是。 任何人都可以解釋爲什麼這種效應不會在我身上重現,我會很樂意接受他的答案作爲解決我的問題的方法。

謝謝

+1

我只是想問:)我注意到你將vertices_size傳遞給Update(...),這實際上是你的頂點位置數組中的float組件的數量。無論如何,如果你試圖繪製比數組存儲更多的頂點,它會引發未定義的行爲。衆所周知,衆多特定於供應商的行爲出現在哪裏。如果你有一個更新的OpenGL驅動程序實現,OpenGL調試輸出擴展通常會告訴你什麼時候在繪圖調用中超出數組。很多錯誤的事情,但不會通過glGetError產生錯誤的方式就是這樣。 –

+0

現貨!儘管我很愚蠢......你有什麼機會可以幫助解決這裏神祕的第二部分? – Bisder

+1

@Bisder:您幾乎可以肯定地使用不同的視頻卡或不同的驅動程序版本。一個驅動程序可能會拒絕繪製額外的頂點,其他的可能會繪製內存中的下一個內容,但在內存中以不同的順序存儲內容。 –