歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> OpenGL錯誤總結

OpenGL錯誤總結

日期:2017/3/1 9:46:49   编辑:Linux編程

const char* getGLErrorInfo(int errorId)
{
switch (errorId)
{
case GL_INVALID_ENUM:
return ("GL Invalid Enum\n");
case GL_INVALID_VALUE:
return ("GL Invalid Value\n");
case GL_INVALID_OPERATION:
return ("GL Invalid Operation\n");
case GL_OUT_OF_MEMORY:
return ("GL Out Of Memory\n");
//case GL_INVALID_FRAMEBUFFER_OPERATION:
// return ("GL Invalid FrameBuffer Operation\n");
case GL_STACK_OVERFLOW:
return ("GL Stack Overflow\n");
case GL_STACK_UNDERFLOW:
return ("GL Stack Underflow\n");
//case GL_TABLE_TOO_LARGE:
// return ("GL Table Too Large\n");
};

return "GL Undefined Error";
}

錯誤示例1:

double viewMatrix[16];

glGetDoublev(GL_MODELVIEW, viewMatrix); 編譯不會報錯,但是獲取的viewMatrix失敗。通過glGetError 獲得錯誤碼是GL_INVALID_ENUM 0x0500。

正確寫法glGetDoublev(GL_MODELVIEW_MATRIX, viewMatrix);

GL_PROJECTION_MATRIX / GL_PROJECTION

獲取視口信息直接GL_VIEWPORT

錯誤示例2:

畫線條(即使只畫一根線條)時候應該傳GL_LINES, 不小心傳了GL_LINE,編譯也不會報錯,但就是沒效果。

畫點GL_POINTS,四邊形GL_QUADS。不小心寫了GL_QUAD 編譯報錯 使用了未定義的枚舉變量。

GL_LINE,GL_POINT,opengl中用來定義多邊形的繪制模式,還有GL_FILL模式。

錯誤示例3:

在BeginDraw函數中call函數glPushAttrib,保存屬性,在EndDraw函數中忘記glPopAttrib,檢查opengl狀態時,輸出錯誤碼為0x01,差了opengl手冊居然沒有這個錯誤碼的說明。。。

錯誤示例4:

void Display()
{
// Clear frame buffer
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_DEPTH_TEST);

// Set light
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);

// Rotate and draw shape
glPushMatrix();

glTranslatef(0.5f, -0.3f, 0.0f);

// 根據四元數計算旋轉矩陣
ConvertQuaternionToMatrix(g_Rotation, mat);
glMultMatrixf(mat);

// 縮放操作
glScalef(g_Zoom, g_Zoom, g_Zoom);

// 調用顯示列表繪制物體
glCallList(g_CurrentShape);
glPopMatrix();

// 繪制UI
TwDraw();

// Present frame buffer
glutSwapBuffers();

// Recall Display at next frame
glutPostRedisplay();
}

void TwDraw()
{
// BeginDraw
glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity();
glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity();
glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();

// Draw UI

// EndDraw
glMatrixMode(GL_MODELVIEW); glPopMatrix();
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_TEXTURE); glPopMatrix(); // 將矩陣堆棧狀態設為GL_TEXTURE
}

上面代碼段代碼,在BeginDraw操作保存當前的各種矩陣堆棧,EndDraw操作還原之前的矩陣堆棧,都沒問題。關鍵是TwDraw函數放到Display函數中以後,二者結合起來運行一次以後就會有問題。而且問題十分奇怪,無論Display函數中如何glMultMatrix,如何glScale,如何glTranslate ,物體最終的位置都沒有變化。

因為什麼呢?
答案的根因是因為opengl是一個狀態機。。。TwDraw的EndDraw操作將當前操作的矩陣堆棧設為 紋理堆棧,因此Display函數第一次執行,可能繼承了來自ReShape函數中的狀態,當前矩陣堆棧是模型視圖,但是一旦TwDraw函數執行,就會十分“隱晦”地將當前的堆棧狀態設為GL_TEXTURE,所以第二次Display函數中的glPushMatrix,glMultMatrix,glScale,glTranslate,glPop都是操作紋理堆棧,對物體的位置一點作用也沒有。

參見opengl官網,Avoiding 16 Common OpenGL Pitfalls
的第三點:http://www.opengl.org/archives/resources/features/KilgardTechniques/oglpitfall/

狀態紊亂導致的錯誤示例5:

批量繪制地圖上的道路,數據量很大,當批處理阈值小於2500時所有道路可以正常繪制,當批處理阈值大於2500時就會中斷。。而且是crash是必現的。不知錯在哪裡Zz。卡了很幾天,google了好久,http://www.gamedev.net/topic/456605-opengl-crashes-in-gldrawelements/ 15樓zedz方法給了靈感:glDrawElements之前,禁掉紋理、頂點、顏色數組,繪制完再開啟,此時道路沒繪制出來也沒有crash。說明問題出在頂點數組狀態上,經過排查沒有關閉GL_TEXTURE_COORD_ARRAY。道路采用顏色數組繪制,glVertexPointer只傳了顏色和位置信息,而繪制完地圖瓦片後GL_TEXTURE_COORD_ARRAY狀態並沒有被禁掉。

遇到過最隱晦的錯誤

重疊區域像素抖動特別厲害: 左圖紅色矩形框,右圖更加嚴重樓塊跟地圖根本區分不開,視覺效果十分差! 正常的效果應該是: 出問題時透視參數:gluPerspective(45, aspect, 0.001, 10000.0); 樓塊,地圖本身繪制是沒有問題的。問題出在gluPerspective函數設置視稜錐過長,超過了OpenGL深度緩沖區的精度,導致每次片源的深度測試結果不一致(不在支持重入性)。一般深度緩沖區是16byte buffer。精度是0-65536。 錯誤示例5: 網友的疑問,模型縮小時會有黑塊閃爍問題, 放大後則沒有問題 他的視稜錐設置: 0.1到30000,范圍為300000,一般深度緩沖區16位精度也就32768。。。 Alpha混合錯誤:

圖1是原始紋理圖片,圖2是錯誤的顯示結果(設計師不滿意要求修改),圖3是修改後的效果與原始氣泡樣式保持一致。

圖2采用的混合模式時:glBlend( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 混合公式為

dst{ RGBA } = src{ RGBA } * srcA + dst{ RGBA } * (1 - srcA) 氣泡主體部分也混合了底圖背景(灰色調),所以整體結果是灰色調。

圖3采用的混合模式時:glBlend( GL_ONE, GL_ONE_MINUS_SRC_ALPHA); 混合公式為

dst{ RGBA } = src{ RGBA } * 1 + dst{ RGBA } * (1 - srcA) 既有摳圖效果,又保持氣泡色調不變。

同樣的BUG再次出現:

左下角為原始紋理,黑色部分RGBA全部為0,;左上角混合模式為(srcA, 1-srcA),結果描邊處看上去有種髒的感覺;右上角混合模式為(1, 1-srcA) 結果十分干淨、明朗!

其他錯誤:

模型頂點和照相機相對位置不對,導致看不到效果。

開了光照,但是模型頂點沒有設置法線 導致繪制失敗。

後續繼續更新中。。。

修改記錄:

2012/7/29 - 增加錯誤示例3、4。

2013/7/9 -增加深度緩沖區錯誤。

2013/9/6 - 增加alpha混合錯誤

2013/11/23 -增加狀態紊亂錯誤示例5

Copyright © Linux教程網 All Rights Reserved