OpenGL學習進程(4)第二課:繪制圖形


    本節是OpenGL學習的第二個課時,下面介紹如何用點和線來繪制圖形:

 

    (1)用點的坐標來繪制矩形:

#include <GL/glut.h>

void display(void)
{
    // clear all pixels  
    glClear(GL_COLOR_BUFFER_BIT);

    // draw yellow polygon (rectangle) with corners at
    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_POLYGON);           //繪制開始前必須調用glBegin以通知繪制圖形的類型,比如還可以繪制點,線等。
    glVertex3f(0.20, 0.20, 0.0);
    glVertex3f(0.80, 0.20, 0.0);
    glVertex3f(0.80, 0.80, 0.0);
    glVertex3f(0.20, 0.80, 0.0);
    glEnd();                              //結束之后則要調用glEnd函數

    glFlush();
}

void init(void)
{
    // select clearing color: blue
    glClearColor(0.0, 1.0, 0.0, 0.0);

    // initialize viewing values
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(400, 300);
    glutCreateWindow("polyon");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

    代碼解釋:

    1)glClear(GLbitfield mask)

    glClear sets the bitplane area of the window to values previously selected by glClearColor, glClearDepth, and glClearStencil. Multiple color buffers can be cleared simultaneously by selecting more than one buffer at a time using glDrawBuffer.

    The pixel ownership test, the scissor test, dithering, and the buffer writemasks affect the operation of glClear. The scissor box bounds the cleared region. Alpha function, blend function, logical operation, stenciling, texture mapping, and depth-buffering are ignored by glClear.

    glClear takes a single argument that is the bitwise OR of several values indicating which buffer is to be cleared.The values are as follows:

    GL_COLOR_BUFFER_BIT Indicates the buffers currently enabled for color writing.

    GL_DEPTH_BUFFER_BIT Indicates the depth buffer.

    GL_STENCIL_BUFFER_BIT Indicates the stencil buffer. 

    The value to which each buffer is cleared depends on the setting of the clear value for that buffer.

    2)glClearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)

    glClearColor specifies the red, green, blue, and alpha values used by glClear to clear the color buffers. Values specified by glClearColor are clamped to the range [0,1].

    3)glMatrixMode(GLenum mode)

    學習OpenGL時,對矩陣的操作是核心。glMatrixMode告訴我們這個當前矩陣是什么矩陣。

    4)glColor3f()

    對顏色進行設定。OpenGl繪制圖形形狀時,並不繪制顏色,而是在繪制形狀之前指定好顏色

    5)glLoadIdentity()

    恢復初始坐標系,重置當前指定的矩陣為單位矩陣。

    6)glOrtho(left, right, bottom, top, near, far)

    glOrtho(投影變換函數)創建一個正交平行的視景體,一般用於"物體不會因為離屏幕的遠近而產生大小的變換"的情況。

    OpenGL中有兩個比較重要的投影變換函數,glViewport和glOrtho。

 

    (2)演示投影變換函數對畫出圖形位置的影響:

      1).示例1:

#include <GL/glut.h>

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_POLYGON);
 glVertex3f(0.20, 0.20, 0.0);
    glVertex3f(0.80, 0.20, 0.0);
    glVertex3f(0.80, 0.80, 0.0);
    glVertex3f(0.20, 0.80, 0.0);
    glEnd();

    glFlush();
}

void init(void)
{
    glClearColor(0.0, 1.0, 0.0, 0.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(400, 300);
    glutCreateWindow("polyon");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

      2).示例2:

#include <GL/glut.h>

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 1.0, 0.0);
    glBegin(GL_POLYGON);
 glVertex3f(-0.80, 0.80, 0.0);
    glVertex3f(-0.80, -0.80, 0.0);
    glVertex3f(0.80, -0.80, 0.0);
    glVertex3f(0.80, 0.80, 0.0);
    glEnd();

    glFlush();
}

void init(void)
{
    glClearColor(0.0, 1.0, 0.0, 0.0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(300, 300);
    glutInitWindowPosition(400, 300);
    glutCreateWindow("polyon");
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

      3)結論:

      代碼中紅色標志了他們的對應關系。

      glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)函數實際上讓當前窗體顯示的區域對應到一個笛卡爾坐標系xy平面的矩形上(僅2D,所以只看前4個參數),原點是窗體顯示區域的中心。

      在第一個例子中的點僅存在於第一象限,因此雖然窗體包含有4個坐標系,它僅僅在第一個區域顯示圖形。在第二個例子中,4個點存在4個象限中,因此顯示的矩形橫跨4個象限。

      而在開始的例子中,窗體的顯示區域僅僅對應了第一象限。

 

    (3)詳細介紹:

      1).在openGL中編程,經常用到glColor3f()函數進行顏色設定,現對參數與顏色的對應關系整理如下:

glColor3f(0.0, 0.0, 0.0);  --> 黑色  
glColor3f(1.0, 0.0, 0.0);  --> 紅色  
glColor3f(0.0, 1.0, 0.0);  --> 綠色  
glColor3f(0.0, 0.0, 1.0);  --> 藍色  
glColor3f(1.0, 1.0, 0.0);  --> 黃色  
glColor3f(1.0, 0.0, 1.0);  --> 品紅色  
glColor3f(0.0, 1.0, 1.0);  --> 青色  
glColor3f(1.0, 1.0, 1.0);  --> 白色

      2).void glMatrixMode(GLenum mode)

      mode告訴計算機將什么矩陣設置為當前矩陣,可選值有: GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE。

GL_MODELVIEW: 應用這個參數后,表示接下來的矩陣操作都是針對模型視景矩陣堆棧 。  直到下一次調用這個函數並更改參數為止。   
GL_PROJECTION:應用這個參數后,表示接下來的矩陣操作都是針對投影矩陣堆棧    。  直到下一次調用這個函數並更改參數為止。
GL_TEXTURE :  應用這個參數后,表示接下來的矩陣操作都是針對紋理矩陣堆棧    。  直到下一次調用這個函數並更改參數為止。

      由於對不同的矩陣有不同的操作,置了當前的矩陣后,我們接下來所調用的所有openGL庫函數的功能必須確定是針對我們設定的這個當前矩陣的,不能張冠李戴。

 glMatrixMode(GL_MODELVIEW );//設置當前矩陣為模型視景矩陣
 gluPerspective(45.0f,(GLfloat)cx/(GLfloat)cy,0.1f,100.0f);//對圖像進行透視投影,以將三維物體顯示在二維平面上
 這樣調用是錯誤的,結果將沒有圖像顯示。這是因為,我們設置了當前矩陣為模型視景矩陣,而gluPerspective()是要對投影矩陣進行操作,那么計算機就會把模型矩陣當做投影矩陣,來與 gluPerspective()指定的矩陣進行乘法運算,最終就會導致錯誤。

      3).void glLoadIdentity(void)(http://blog.sina.com.cn/s/blog_957b9fdb0100zez9.html)

      glLoadIdentity是非常簡單的恢復初始坐標系的手段,用一個4×4的單位矩陣來替換當前矩陣。

當您調用glLoadIdentity()之后,您實際上將當前點移到了屏幕中心:類似於一個復位操作
1.X坐標軸從左至右,Y坐標軸從下至上,Z坐標軸從里至外。
2.OpenGL屏幕中心的坐標值是X和Y軸上的0.0f點。
3.中心左面的坐標值是負值,右面是正值。移向屏幕頂端是正值,移向屏幕底端是負值。移入屏幕深處是負值,移出屏幕則是正值。

     由於某些原因可能使得當前矩陣中的元素有一些不確定的值,這將導致程序對圖形對象進行幾何變形時得到一個非預期的結果。因此有必要將當前矩陣初始成一個單位矩陣,即對圖形對象不做任何變換。這就是為什么在調用過glMatrixMode()命令后,總是要調用該命令的原因。

      用單位矩陣替換當前矩陣並不改變當前矩陣模式。

      4).glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far)

      創建一個平行視景體(就是一個長方體空間區域,也相當於對立體空間進行3D裁剪)。這種投影意味着離觀察者較遠的對象看上去不會變小(與透視投影相反)。實際上這個函數的操作是創建一個正射投影矩陣,並且用這個矩陣乘以當前矩陣。     

 

  六個參數, 前兩個是x軸最小坐標和最大坐標,中間兩個是y軸,最后兩個是z軸值。其中近裁剪平面是一個矩形,矩形左下角點三維空間坐標是(left,bottom,-near),右上角點是(right,top,-near);遠裁剪平面也是一個矩形,左下角點空間坐標是(left,bottom,-far),右上角點是(right,top,-far)。

  注意,所有的near和far值同時為正或同時為負, 值不能相同。如果沒有其他變換,正射投影的方向平行於Z軸,且視點朝向Z負軸。這意味着物體在視點前面時far和near都為負值,物體在視點后面時far和near都為正值。只有在視景體里的物體才能顯示出來。如果最后兩個值是(0,0),也就是near和far值相同了,視景體深度沒有了,整個視景體都被壓成個平面了,就會顯示不正確。

      5).glBegin()和glEnd()

     繪制圖像的開始或結束的標志。

      它們之間可以執行的函數:

glVertex*()    設置頂點坐標
glColor*()     設置當前顏色
glIndex*()     設置當前顏色表
glNormal*()    設置法向坐標
glCoord*()     產生坐標
glCallList(),glCallLists()    執行顯示列表
glTexCoord*()  設置紋理坐標
glEdgeFlag*()  控制邊界繪制
glMaterial*()  設置材質

      可以繪制的圖形的類型:

GL_POINTS         單個頂點集
GL_LINES          多組雙頂點線段
GL_POLYGON        單個簡單填充凸多邊形
GL_TRAINGLES      多組獨立填充三角形
GL_QUADS          多組獨立填充四邊形
GL_LINE_STRIP     不閉合折線
GL_LINE_LOOP      閉合折線
GL_TRAINGLE_STRIP 線型連續填充三角形串
GL_TRAINGLE_FAN   扇形連續填充三角形串
GL_QUAD_STRIP     連續填充四邊形串

      6)3D編程的基礎知識:

1、  渲染:對一個三維物體進行幾何描述,並且把它轉換為屏幕上的一幅圖像,這個過程就叫渲染。
2紋理貼圖:通過一副圖像向一個多邊形提供額外細節的技巧稱為紋理貼圖。我們所提供的圖像稱為紋理,紋理中每個單獨的元素稱為紋理單元(或紋理像素,texel)。
3過濾(filtering):在一個物體的表面上拉伸或壓縮紋理單元(紋理像素)的過程稱為過濾。
4混合(blending):指屏幕上顏色或物體的組合。混合可以用於多種目的,如制作透明效果、反射效果等。
5裁剪區域:窗口(即屏幕)是以像素為單位進行度量的。裁剪區域指的是占據窗口的笛卡爾坐標空間中的區域。也可以解釋為填充窗口的笛卡爾坐標空間中的區域。注意,裁剪區域使用的是笛卡爾坐標系統。
6視口:因為裁剪區域的寬度和高度很少正好與窗口的寬度和高度(以像素為單位)相匹配,所以需要把坐標系統從邏輯笛卡爾坐標空間映射到物理屏幕像素坐標空間。視口就是窗口中用於繪制裁剪區域的客戶區域。這里,要注意窗口與視口的區別,視口在窗口中指定,我們可以使用視口來縮小或者放大窗口中的圖像。//類似4所說的東西
7.   管線:它用於描述一種過程,該過程可能涉及兩個或更多個獨特的階段或步驟。
8、  OpenGL命令緩沖區:當應用程序進行OpenGL API函數調用時,這些命令被放置在一個命令緩沖區中。最終,這個緩沖區中會填滿API 調用命令、頂點數據、紋理數據之類的東西。當緩沖區被刷新時,命令和數據就會被傳遞給管線的下一個階段。
9、  變換和光照(T&L):這是一個數學計算密集型的階段。在變換階段,描述物體幾何形狀的頂點被重新計算(經歷多次不同坐標空間的變換),以確定這個物體的位置和朝向。同時進行的光照計算階段(世界坐標空間中)將確定每個頂點該具有的顏色和亮度。
10、 光柵化:該階段根據幾何圖形、顏色和紋理數據實際創建彩色圖像。然后,圖像被放入到幀緩沖區之中。
11、 幀緩沖區:即圖形顯示設備的內存。圖像放入到幀緩沖區意味着將會在屏幕上顯示(刷新幀緩沖區時)。

 

    (4)繪制不同圖形的實例:

#include <GL/glut.h>
#include <math.h>
const int n = 1000;
const GLfloat R = 0.40f;
const GLfloat Pi = 3.1415926536f;
const GLfloat factor = 0.1f;

void paint(void)
{   //在下半部分畫一個正弦圖像,上半部分畫一個圓和一個五角形
    glClear(GL_COLOR_BUFFER_BIT);
    
    //1.圓形
    int i;
    glColor3f(1.0,0.0,0.0);//紅色的圓
    glBegin(GL_POLYGON);//有頂點就必須要有glBegin() glEnd();
    for(i=0; i<n; ++i)
        glVertex2f(R*cos(2*Pi/n*i)-0.50f, R*sin(2*Pi/n*i)+0.5f);//將圓形的中點向左上方平移
    glEnd();
    glFlush();

    //2.五角形
    glColor3f(0.0f,0.0f,0.0f);//黑色的五角形
    GLfloat a = 1/ (4 - 4 * cos(72 * Pi / 180));
    GLfloat bx = a * cos(18 * Pi / 180);
    GLfloat by = a * sin(18 * Pi / 180);
    GLfloat cy = -a * cos(18 * Pi / 180);
    GLfloat
        PointA[2] = { 0+0.50, a+0.50 },
        PointB[2] = { bx+0.5, by+0.50 },
        PointC[2] = { 0.25+0.50, cy+0.50 },
        PointD[2] = { -0.25+0.50, cy+0.50 },
        PointE[2] = { -bx+0.50, by+0.50 };     //將整體向右上方平移
    // 按照A->C->E->B->D->A的順序,將五角星畫出
    glBegin(GL_LINE_LOOP);//閉合折線
    glVertex2fv(PointA);
    glVertex2fv(PointC);
    glVertex2fv(PointE);
    glVertex2fv(PointB);
    glVertex2fv(PointD);
    glEnd();
    glFlush();

    //3.正弦圖像:
    //黑色的正弦圖像
    GLfloat x;
    glBegin(GL_LINE_STRIP);
    for(x=-1.0f/factor; x<1.0f/factor; x+=0.01f)
    {
        glVertex2f(x*factor, sin(x)*factor-0.50);
    }
    glEnd();
    glFlush();

    //4.分割線:
    glColor3f(0.5f,0.5f,0.0f);//黃色的分割線
    glBegin(GL_LINES);
    glVertex2f(-1.0f, 0.0f);
    glVertex2f(1.0f, 0.0f);         // 以上兩個點可以畫x軸
    glVertex2f(0.0f, 0.0f);
    glVertex2f(0.0f, 1.0f);         // 以上兩個點可以畫y軸
    glEnd();
    glFlush();
}

void init(void)
{
    glClearColor(0.0,1.0,1.0,0.0);//設背景為青色
    glMatrixMode(GL_PROJECTION);//創建投影矩陣堆棧
    glLoadIdentity();//將當前矩陣設為單位矩陣,恢復初始坐標系
    gluOrtho2D(-1.0f,1.0f,-1.0f,1.0f);//窗口左上角坐標(-1,1),右下角坐標(1,-1);
}

int main(int argc,char *argv[])
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowSize(600,600);
    glutInitWindowPosition(300, 100);
    glutCreateWindow("圓形五角形和正弦圖像");
    init();
    glutDisplayFunc(paint);
    glutMainLoop();
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM