1. 程式人生 > >OpenGL(二)圖形繪製之平面多面體的繪製

OpenGL(二)圖形繪製之平面多面體的繪製

通過繪製一個三菱錐初步瞭解繪製平面多面體。

<span style="font-size:18px;">#include<windows.h>
#include<gl/gl.h>
#include<gl/glut.h>
#include<gl/glu.h>
#include<stdio.h>

//視窗的大小
GLsizei windowWidth;
GLsizei windowHeight;


//旋轉角度引數
static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

//確定多邊形的繞法的方向
BOOL bDepth = FALSE; //深度測試開關
BOOL bCull =  FALSE; //剔除開關



//初始化視窗
void SetupRC(void)
{
	//設定視窗背景西顏色為黑色
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

	//指定多變形的陰影模式為平面陰暗模式
	glShadeModel(GL_FLAT);

}
void ChangeSize(int w, int h)
{
	if (h == 0)
		h = 1;

	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();


	if (w <= h)
	{
		glOrtho(-100.0f, 100.0f, -100.0f*h / w, 100.0f*h / w, -100.0f, 100.0f);
	}
	else
	{
		glOrtho(-100.0f*w / h, 100.0f*w / h, -100.0f, 100.0f, -100.0f, 100.0f);
	}
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void RenderScene(void)
{
	//清除顏色及深度緩衝區
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);


	//是否開啟設度模式
	if (bDepth)
		glEnable(GL_DEPTH_TEST);
	else
		glDisable(GL_DEPTH_TEST);

	//是否開啟剔除
	if (bCull)
		glEnable(GL_CULL_FACE);
	else
		glDisable(GL_CULL_FACE);

	//旋轉圖形
	glPushMatrix();

	//角度正負決定是順逆時針
	glRotatef(xRot,1.0f,0.0f,0.0f); //使整個場景繞著x軸旋轉  
	glRotatef(yRot, 0.0, 1.0, 0.0f);//使整個場景繞著y軸旋轉  


	//指定順時針繞法的多變形為正多變邊形正面
	//glFrontFace(GL_CW);

	//繪製三菱錐的三個稜面
    //他們的顏色分別為紅、綠、藍
	glBegin(GL_TRIANGLE_FAN);

	glVertex3f(0.0, 0.0,80);
	glVertex3f(0.0, 50.0,0.0);


	glColor3f(1.0,0.0,0.0);  //紅色
	glVertex3f(50.0,-50.0,0.0);

	glColor3f(0.0f, 1.0f, 0.0); //綠色
	glVertex3f(-50.0,-50.0,0.0);


	glColor3f(0.0f,0.0f,1.0f); //藍色
	glVertex3f(0.0,50.0,0.0);
	
	glEnd();


	//繪製三菱錐的地面,其顏色為黃色
	glBegin(GL_TRIANGLE_FAN);
	glVertex3f(0.0,50.0,0.0);
	glVertex3f(50.0,-50.0,0.0);
	glColor3f(1.0,1.0,0.0);  //黃色
	glVertex3f(-50.0,-50.0,0.0);
	glEnd();


	glPopMatrix();
	glutSwapBuffers();  //重新整理命令緩衝區
}

void SpecialKeys(int key, int x, int y)
{
	if (key == GLUT_KEY_UP)    xRot -= 5.0f;
	if (key == GLUT_KEY_DOWN)  xRot += 5.0f;
	if (key == GLUT_KEY_LEFT)  yRot -= 5.0f;
	if (key == GLUT_KEY_RIGHT) yRot += 5.0f;


	//結合glPushMatrix()和glPopMatrix()繪圖模式理解旋轉
	// 首先,glPushMateix記住來的繪圖座標(起點)
	//glRotatef(xRot, 1.0f, 0.0f, 0.0f);
	//glRotatef(yRot, 0.0f, 1.0f, 0.0f);
	//然後旋轉相應的座標後繪製圖形
	//glPopMatrix 回到了座標原來的位置(起點)

	printf("%lf\n", yRot);
	if (xRot >= 360.0f)   xRot = 0.0f;
	if (xRot < -1.0f)    xRot=355.0f;
	if (yRot >= 360.0f)    yRot = 0.0f;
	if (yRot < -1.0f)    yRot = 355.0f;


	//重新整理視窗  強制
	glutPostRedisplay();
}
void ProcessMenu(int value)
{
	switch (value)
	{
	case 1:bDepth = !bDepth;
		break;
	case 2:bCull = !bCull;
		break;
	default:
		break;
	}
	//強制重新整理
	glutPostRedisplay();
}

int main(int argc, char *argv[])
{

	//initialize the GLUT library  
	//初始化GLUT庫
	glutInit(&argc, argv);


	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutCreateWindow("三菱錐");

	//回撥函式
	glutDisplayFunc(RenderScene);
	glutReshapeFunc(ChangeSize);

	//設定特殊鍵盤相應回撥函式
	glutSpecialFunc(SpecialKeys);
	//void glutSpecialFunc(void(*func)(int key,int x,int y));
	//special函式第一個關鍵字是鍵盤的值,  x,y是獲取滑鼠點選的座標
	// sets the special keyboard callback for the current window
	//the special keyboared callback is triggered when keyboard function or 
	//directional keys are pressed



	//建立一個選單
	glutCreateMenu(ProcessMenu);
	glutAddMenuEntry("深度測試",1);
	glutAddMenuEntry("剔除背面",2);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	SetupRC();
	glutMainLoop();
	return 0;
}


</span>

程式一開始執行的圖片結果如下:


通過旋轉和使用深度測試功能結果如下:


本次學習知識點:

在旋轉的過程中,紅色的稜鏡始終不能顯示出來,這是因為紅色的稜面是最先繪製的,它總是被後面繪製的綠色,

藍色或黃色的多邊形所遮擋,要改變這種狀況就需要啟用深度測試。
1.  深度測試 (恢復看不到的區域)
 在繪製圖形的過程中,有時一個物體的一部分會被其前方的物體擋住(從觀察者的角度看),如果這是這個物體在檔在其前面的物體繪製完成之後繪製,那麼螢幕中顯示的圖形將不是我們所希望的,即後面的物體擋住了前面的物體。
只需啟用一項稱為深度測試的功能就可以解決這一問題。

    啟動深度測試: 呼叫  glEnable(GL_DEPTH_TEST);

    關閉深度測試: 呼叫 glDisable(GL_DEPTH_TEST);

深度測試是一種移除被擋住表面的有效技術,它的過程是:在繪製一個畫素時,會給他分配一個值(稱為z值),這個值表示它與觀察者的距離。然後,如果需要在同一個位置上繪製另一個畫素,將比較新畫素和已經儲存的該位置的畫素的z值。如果新畫素的z的值比較大,即它離觀察者更近因而在原來那個畫素的前面,原來的畫素就會被新畫素擋住。這一操作在內部有深度緩衝區完成。

為了使深度緩衝區正常完成深度測試功能,每次渲染場景時,必須先清除深度緩衝區:
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)


2.隱藏表面

啟用深度測試之後,我們得到良好的視覺效果,但是還是付出了一些效能代價,因為每個畫出的畫素都必須與先前畫素的z值比較。但是如果我們知道某些表面無論如何也不必畫出,我們可以將其指出,這種技術稱為"剔除",這種技術可以將已知永遠看不到的幾何圖形消除掉,這樣可以顯著的改善效能。
那麼哪些表面時永遠看不到的呢?最常見的例子就是封閉物體的內部表面。一種稱為回溯的技術可以消除表面的背面,通過

                glEnable/glDisable(GL_CULL_FACE)

來實現。啟用剔除技術後,我們發現三稜錐的底面消失了,這是因為在繪製的過程中,我們都使用了順時針繞法的多邊形正面,但這樣底面的正面正對著三稜錐的內部,故此啟用剔除技術後把底面剔出掉了,要改變這種狀況,可以在繪製三稜錐的底面前呼叫函式

                  glFrontFace(GL_CCW);