1. 程式人生 > >OpenGL 繪製二維圖形

OpenGL 繪製二維圖形

每次繪圖需要在OnDraw(CDC* pDC)中呼叫,例如:
void CStepinGLView::OnDraw(CDC* pDC)
{
	CStepinGLDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此處為本機資料新增繪製程式碼
	DrawCube();
	
	SwapBuffers(wglGetCurrentDC());
}

好了,廢話就說到這。

1.繪製點

void CStepinGLView::DrawScene(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	//繪製點
	GLfloat fPointSize[2];
	glGetFloatv(GL_POINT_SIZE_RANGE,fPointSize);  //獲取點的大小範圍   fPointSize[0]儲存點的大小最小值,1儲存最大值
	glPointSize(fPointSize[1] / 2.0f);
	glBegin(GL_POINTS);
	glVertex2f(0.0f,0.0f);
	glVertex2f(0.5f,0.5f);
	glVertex2f(-0.5f,0.5f);
	glVertex2f(0.5f,-0.5f);
	glVertex2f(-0.5f,-0.5f);
	glEnd();
}
此段程式碼中:glGetFloatv(GL_POINT_SIZE_RANGE,fPointSize); 

glGetFloatv第一個引數必須是OpenGL常量,第二個引數是一個數組的地址。函式按第一個引數的指示向第二個引數所指的地址傳輸資料。fPointSize[0]儲存點的大小的最小值,fPointSize[1]儲存點的大小的最大值。

執行截圖:

2.繪製直線和線型

void CStepinGLView::DrawLineStipple(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(fLineWidth[1] / 6.0f);

	glBegin(GL_LINES);
	glVertex2f(-0.8f,0.8f);
	glVertex2f(0.8f,0.8f);
	glEnd();
	
	//glEnable(GL_LINE_STRIP);     //第一次使用此型別,輸出都是直線
	glEnable(GL_LINE_STIPPLE);     //glEnable()啟用函式  ,此句執行後 執行畫虛線

	glLineStipple(1,0x00FF);     //設定直線的當前點畫模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,0.4f);
	glVertex2f(0.8f,0.4f);
	glEnd();

	glLineStipple(1,0x0F0F);     //設定直線的當前點畫模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,0.0f);
	glVertex2f(0.8f,0.0f);
	glEnd();

	glLineStipple(2,0x0101);     //設定直線的當前點畫模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,-0.4f);
	glVertex2f(0.8f,-0.4f);
	glEnd();

	glLineStipple(1,0x1C47);     //設定直線的當前點畫模式
	glBegin(GL_LINES);
	glVertex2f(-0.8f,-0.8f);
	glVertex2f(0.8f,-0.8f);
	glEnd();

	glDisable(GL_LINE_STIPPLE);
	glFinish();
}

OpenGL不僅能畫實線,而且可以繪製點畫線(Stippled Lines)等其他型別的直線。

為了繪製點畫線,必須先自定義點畫線的線型,然後通過 glLineStipple() 函式讓OpenGL獲取所定義的線型。

線型是通過二進位制來描述的,1代表一個實點,0則表示在該畫素處不畫直線,即不填充畫素。

例如:

0000000011111111;   //對應16進位制0x00FF,表示空白線和長折線
0000111100001111;   //0x0F0F,表示空白線及短折線
0000000100000001;   //0x0101,表示點
0001110001000111;   //0x1c47,表示折線點折線
呼叫glLineStipple()函式,讓OpenGL知道已改變的線型。第一個引數資料型別為GLint,表示線型模式重複因子;第二個引數為GLushort,表示所定義的線型。重複因子說明了用二進位制表示的點的重複次數。如果重複因子是2,一個01010101的線型模式事實上被當成0011001100110011線型來處理。

為了對所定義的線型獲取OpenGL的支援,必須事先啟動改變線型的機制:

glEnable(GL_LINE_STIPPLE);     //glEnable()啟用函式  ,此句執行後 執行畫虛線

要注意,當不再使用自定義線型時,將其關閉:

glDisable(GL_LINE_STIPPLE);

程式執行截圖:


3.繪製不閉合折線

void CStepinGLView::DrawLineStrip(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(fLineWidth[1] / 6.0f);

	glBegin(GL_LINE_STRIP);               //繪製不閉合折線
	glVertex2f(-0.8f,0.6f);
	glVertex2f(0.8f,0.6f);

	glVertex2f(-0.8f,0.2f);
	glVertex2f(0.8f,0.2f);

	glEnd();
}
程式執行截圖:


4.繪製閉合折線

void CStepinGLView::DrawLineLoop(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	GLfloat fLineWidth[2];
	glGetFloatv(GL_LINE_WIDTH_RANGE,fLineWidth);
	glLineWidth(fLineWidth[1] / 6.0f);

	glBegin(GL_LINE_LOOP);               //繪製閉合折線
	glVertex2f(-0.8f,0.6f);
	glVertex2f(0.8f,0.6f);

	glVertex2f(-0.8f,0.2f);
	glVertex2f(0.8f,0.2f);

	glVertex2f(-0.8f,0.0f);
	glVertex2f(0.8f,0.0f);
	glEnd();
}
程式執行截圖:


5.繪製多邊形

void CStepinGLView::DrawPolygons(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	glLineWidth(2.0f);
	glPolygonMode(GL_FRONT,GL_LINE);
	glPolygonMode(GL_BACK,GL_FILL);

	glFrontFace(GL_CCW);

	glBegin(GL_POLYGON);
	glVertex2f(-0.3f,0.3f);
	glVertex2f(-0.7f,-0.2f);
	glVertex2f(-0.3f,-0.4f);
	glVertex2f(0.4f,-0.4f);
	glVertex2f(0.8f,-0.2f);
	glVertex2f(0.4f,0.3f);
	glEnd();
}

在OpenGL中,一個多邊形(polygon)至少有3個頂點。直線不能相交,多邊形應構成單連通的凸區域。

一個多邊形有前面和後面之分,並且前面和後面可以有不同的屬性。比如,可以指定一個多邊形的前面為紅色而後面為藍色。

一個多邊形的前面和後面是需要指定的,可以通過定義其頂點順序來確定。

如果頂點的排序順序是逆時針的,則該多邊形是前面的,如果頂點的排序屬性是順時針的,則該多邊形是後面的。

事實上,這是可以改變的。OpenGL提供了一個靈活的函式:

glFrontFace()。該函式引數只能是GL_CW或GL_CCW;

GL_CW表示按順時針順序定義的多邊形是前面的;

GL_CCW表示按逆時針順序定義的多邊形是前面的;

多邊形是封閉的線段構造的形狀,它與用GL_LINE_LOOP 繪製的閉合折線有本質的區別。一個多邊形可以進行填充,也可以不填充。這樣就需要對多邊形的繪製模式作出說明。可以採用:

glPolygonMode() :該函式有兩個引數;

第一個引數:GL_FRONT、GL_BACK、GL_FRONT_AND_BACK  ,分別指多邊形前面、後面或前後兩面;

第二個引數:GL_POINT、GL_LINE、GL_FILL  ,分別指 在多邊形的頂點畫點,畫多邊形框架,填充多邊形;

程式執行截圖:


6.繪製三角形

void CStepinGLView::DrawTriangles(void)
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	//glTranslatef( -1.5f, 0.0f, -6.0f);        //左移1.5單位,並移入螢幕6.0
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	glLineWidth(1.0f);

	glBegin(GL_TRIANGLES);
	glVertex2f(-0.5f, 0.4f);
	glVertex2f(-0.6f, -0.5f);
	glVertex2f(0.5f, -0.5f);

	glVertex2f(-0.5f, 0.8f);
	glVertex2f(-0.5f, 0.6f);
	glVertex2f(0.5f, 0.5f);
	glEnd();

}

程式執行截圖:


7.繪製三角形片

void CStepinGLView::DrawTriangleStrip(void)     //繪製三角形片
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_TRIANGLE_STRIP);
	glVertex2f(-0.8f,0.3f);
	glVertex2f(-0.8f,-0.3f);
	glVertex2f(-0.3f,-0.3f);
	glVertex2f(0.0f,-0.3f);
	glVertex2f(0.3f,0.5f);
	glEnd();
}

採用頂點描述三角形時,前三個頂點描述了第一個三角形,第四個頂點可延伸出一個三角形。

在定義三角形片中,第一個三角形的頂點的排序順序是十分重要的,它決定了整個三角形片是前面還是後面的。

當glFrontFace()函式的引數採用GL_CCW時,第一個三角形按逆時針順序定義時,其前面是面向我們的。


三角形片中頂點被處理的順序,如下圖:


程式執行截圖:


8.繪製三角形扇

void CStepinGLView::DrawTriangleFan(void)    //繪製三角形扇
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_TRIANGLE_FAN);
	glVertex2f(-0.5f,-0.3f);
	glVertex2f(0.3f,0.0f);
	glVertex2f(0.3f,0.3f);
	glVertex2f(0.4f,0.6f);
	glVertex2f(-0.0f,0.6f);

	glEnd();
}

三角形扇的繪製中,前三個頂點定義了第一個三角形,每增加一個頂點,便增加一個三角形;



程式執行截圖:


9.繪製四邊形

void CStepinGLView::DrawQuadrilaterala(void)     //四邊形
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_QUADS);
	glVertex2f(-0.6f,0.8f);
	glVertex2f(-0.6f,-0.6f);
	glVertex2f(0.5f,0.0f);
	glVertex2f(0.6f,0.5f);
	glEnd();
}
程式執行截圖:


10.繪製四邊形片

void CStepinGLView::DrawQuadStrip(void)   //四邊形片
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_QUAD_STRIP);
	glVertex2f(-0.8f,0.3f);
	glVertex2f(-0.7f,0.6f);
	glVertex2f(-0.6f,0.1f);
	glVertex2f(-0.3f,0.6f);
	glVertex2f(-0.1f,-0.2f);
	glVertex2f(0.0f,0.6f);
	glVertex2f(0.3f,-0.4f);
	glVertex2f(0.6f,0.5f);
	glEnd();
}

繪製示意圖:


程式執行截圖:



11.邊的可見性

void CStepinGLView::DrawNonConvex(void)   //凹多邊形
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f(1.0f,0.0f,0.0f);                //顏色為紅色

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

	glBegin(GL_POLYGON);
	glEdgeFlag(TRUE);
	glVertex2f(-0.3f,0.3f);
	glEdgeFlag(FALSE);
	glVertex2f(-0.1f,-0.1f);
	glEdgeFlag(TRUE);
	glVertex2f(0.0f,-0.1f);
	glVertex2f(0.0f,0.3f);
	glEnd();

	glBegin(GL_POLYGON);
	glEdgeFlag(TRUE);
	glVertex2f(-0.1f,-0.1f);
	glVertex2f(-0.2f,-0.4f);
	glEdgeFlag(FALSE);
	glVertex2f(0.0f,-0.4f);
	glVertex2f(0.0f,-0.1f);
	glEnd();

	glBegin(GL_POLYGON);
	glEdgeFlag(FALSE);
	glVertex2f(0.0f,-0.1f);
	glEdgeFlag(TRUE);
	glVertex2f(0.0f,-0.4f);
	glVertex2f(0.4f,-0.4f);
	glVertex2f(0.45f,0.1f);
	glEnd();
}

要繪製如圖所示的凹多邊形,可以通過繪製兩個組合的四邊形。一個四邊形的頂點是(1,2,3,4),另一個四邊形的頂點是(3,4,5,6)。但是想產生左圖,就需要隱藏3---4這條邊。


OpenGL通過 glEdgeFlag() 函式來說明邊的可見性。

TRUE  表可見,FALSE   表不可見。

程式執行截圖:


12.由面建立三維形狀

void CStepinGLView::DrawCube(void)    //繪製立方體
{
	glClearColor(1.0f,1.0f,1.0f,0.0f);         //設定視窗為白色1. 1. 1.  黑色0. 0. 0.
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	
	glColor3f(1.0f,0.2f,0.5f);                //顏色為紅色
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
	glLineWidth(1.5f);
	glColor3f(0.2f,0.5f,1.0f);
	
	glPushMatrix();
	glRotatef(70.0f,0.0f,1.0f,0.0f);      //將盒子繞Y軸70度
	glRotatef(55.0f,0.0f,0.0f,1.0f);      //將盒子繞Z軸55度
	
	glBegin(GL_POLYGON);   //前面
	glVertex3f(-0.5f,0.5f,0.5f);
	glVertex3f(-0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,0.5f,0.5f);
	glEnd();

	//為了省事,我直接把前面的矩陣複製下來
	//直接修改最後一位引數,結果繪製出的圖形不對
	//原因:點的順序輸入不對,造成
	glBegin(GL_POLYGON);   //後面
	glVertex3f(-0.5f,0.5f,-0.5f);
	glVertex3f(0.5f,0.5f,-0.5f);
	glVertex3f(0.5f,-0.5f,-0.5f);
	glVertex3f(-0.5f,-0.5f,-0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //左面
	glVertex3f(-0.5f,-0.5f,0.5f);
	glVertex3f(-0.5f,0.5f,0.5f);
	glVertex3f(-0.5f,0.5f,-0.5f);
	glVertex3f(-0.5f,-0.5f,-0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //右面
	glVertex3f(0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,-0.5f);
	glVertex3f(0.5f,0.5f,-0.5f);
	glVertex3f(0.5f,0.5f,0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //底面
	glVertex3f(-0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,0.5f);
	glVertex3f(0.5f,-0.5f,-0.5f);
	glVertex3f(-0.5f,-0.5f,-0.5f);
	glEnd();

	glBegin(GL_POLYGON);   //頂面
	glVertex3f(-0.5f,0.5f,0.5f);
	glVertex3f(0.5f,0.5f,0.5f);
	glVertex3f(0.5f,0.5f,-0.5f);
	glVertex3f(-0.5f,0.5f,-0.5f);
	glEnd();

	glPopMatrix();
}
請注意,從外部看,每個面都是前面的。因此,立方體的背面、左面、和底面的頂點順序必須是順時針的

在用多邊形描述一個三維物體時,多邊形的前後面區分是十分重要的。如果一個面本來是前面的卻當成後面來處理很可能產生不良效果,特別是對其進行光照的時候。

程式執行截圖: