OpenGL錯誤總結

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章