亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

基于VC++的OpenGL編程講座之曲線和曲面

2019-11-17 05:16:25
字體:
來源:轉載
供稿:網友

  計算機圖形學中,所有的光滑曲線、曲面都采用線段或三角形逼近來模擬,但為了精確地表現曲線,通常需要成千上萬個線段或三角形來逼近,這種方法對于計算機的硬件資源有相當高的要求。然而,許多有用的曲線、曲面在數學上只需要用少數幾個參數(如控制點等)來描述。這種方法所需要的存儲空間比線段、三角形逼近的方法來所需要的空間要小得多,并且控制點方法描述的曲線、曲面比線段、三角形逼近的曲線、曲面更精確。
為了說明如何在OpenGL中繪制復雜曲線和曲面,我們對上述兩類比方法都進行了介紹。下面我們先來介紹有關基礎知識,然后再看是如何實現的吧。

   一、曲線的繪制

  OpenGL通過一種求值器的機制來產生曲線和曲面,該機制非常靈活,可以生成任意角度的多項式曲線,并可以將其他類型的多邊形曲線和曲面轉換成貝塞爾曲線和曲面。這些求值器能在任何度的曲線及曲面上計算指定數目的點。隨后,OpenGL利用曲線和曲面上的點生成標準OpenGL圖元,例如與曲線或曲面近似的線段和多邊形。由于可讓OpenGL計算在曲線上所需的任意數量的點,因此可以達到應用所需的精度。
對于曲線,OpenGL中使用glMap1*()函數來創建一維求值器,該函數原型為:

void glMap1{fd}(GLenum target,TYPE u1,TYPE u2,
GLint stride, GLint order,const TYPE *points);

  函數的第一個參數target指出控制頂點的意義以及在參數points中需要提供多少值,具體值見表一所示。參數points指針可以指向控制點集、RGBA顏色值或紋理坐標串等。例如若target是GL_MAP1_COLOR_4,則就能在RGBA四維空間中生成一條帶有顏色信息的曲線,這在數據場可視化中應用極廣。參數u1和u2,指明變量U的范圍,U一般從0變化到1。參數stride是跨度,表示在每塊存儲區內浮點數或雙精度數的個數,即兩個控制點間的偏移量,比如上例中的控制點集ctrpoint[4][3]的跨度就為3,即單個控制點的坐標元素個數。函數參數order是次數加 1,叫階數,與控制點數一致。

參數 意義 GL_MAP1_VERTEX_3 x,y,z頂點坐標 GL_MAP1_VERTEX_4 x,y,z,w 頂點坐標 GL_MAP1_INDEX 顏色表 GL_MAP1_COLOR_4 R,G,B,A GL_MAP1_NORMAL 法向量 GL_MAP1_TEXTURE_COORD_1 s 紋理坐標 GL_MAP1_TEXTURE_COORD_2 s,t 紋理坐標 GL_MAP1_TEXTURE_COORD_3 s,t,r 紋理坐標 GL_MAP1_TEXTURE_COORD_4 s,t,r,q 紋理坐標               表一、參數target的取值表

  使用求值器定義曲線后,必須要啟動求值器,才能進行下一步的繪制工作。啟動函數仍是glEnable(),其中參數與glMap1*()的第一個參數一致。同樣,關閉函數為glDisable(),參數也一樣。

  一旦啟動一個或多個求值器,我們就可以構造近似曲線了。最簡單的方法是通過調用計算坐標函數glEvalcoord1*()替換所有對函數glVertex*()的調用。與glVertex*()使用二維、三維和四維坐標不同,glEvalcoord1*()將u值傳給所有已啟動的求值器,然后由這些已啟動的求值器生成坐標、法向量、顏色或紋理坐標。OpenGL曲線坐標計算的函數形式如下:

void glEvalCoord1{fd}[v](TYPE u);
  該函數產生曲線坐標值并繪制。參數u是定義域內的值,這個函數調用一次只產生一個坐標。在使用glEvalCoord1*()計算坐標,因為u可取定義域內的任意值,所以由此計算出的坐標值也是任意的。

  使用glEvalCoord1*()函數的優點是,可以對U使用任意值,然而,假如想對u使用N個不同的值,就必須對glEvalCoord1*()函數執行N次調用,為此,OpenGL提供了等間隔值取值法,即先調用glMapGrid1*()定義一個間隔相等的一維網格,然后再用glEvalMesh1()通過一次函數執行,將求值器應用在網格上,計算相應的坐標值。下面具體解釋這兩個函數:

  1、void glMapGrid1{fd}(GLint n,TYPE u1,TYPE u2);

  定義一個網格,從u1到u2分為n步,它們是等間隔的。實際上,這個函數定義的是參數空間網格。

  2、void glEvalMesh1(GLenum mode,GLint p1,GLint p2);

  計算并繪制坐標點。參數mode可以是GL_POINT或GL_LINE,即沿曲線繪制點或沿曲線繪制相連的線段。這個函數的調用效果同在p1和p2之間的每一步給出一個glEvalCoord1()的效果一樣。從編程角度來說,除了當i=0或i=n,它準確以u1或u2作為參數調用glEvalCoord1()之外,它等價于一下代碼:

glBegin(GL_POINT); /* glBegin(GL_LINE_STRip); */
   for(i=p1;i <=p2;i++)
     glEvalCoord1(u1+i*(u2-u1)/n);
   glEnd();

  為了進一步說明OpenGL中曲線的繪制方法。下面我們來看一個簡單的例子,這是用四個控制頂點來畫一條三次Bezier曲線。程序如下(注:這是本講座中提供的第一個完整的OpenGL實例代碼,假如讀者朋友對整個程序結構有些迷惑的話,也不要緊,慢慢地往下看,先有一個感官上的印象,主要是把握如何實現曲線繪制這一部分。關于OpenGL的程序整體結構實現,筆者將在第五講中專門闡述):

#include "glos.h"
#include
#include
#include
void myinit(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
GLfloat ctrlpoints[4][3] = {
   { -4.0, -4.0, 0.0 }, { -2.0, 4.0, 0.0 },
   { 2.0, -4.0, 0.0 }, { 4.0, 4.0, 0.0 }
};
void myinit(void)
{
   glClearColor(0.0, 0.0, 0.0, 1.0);
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4,
&ctrlpoints[0][0]);
   glEnable(GL_MAP1_VERTEX_3);
   glShadeModel(GL_FLAT);
}
void CALLBACK display(void)
{
   int i;
   glClear(GL_COLOR_BUFFER_BIT);
   glColor3f(1.0, 1.0, 1.0);
   glBegin(GL_LINE_STRIP);
   for (i = 0; i <= 30; i++)
      glEvalCoord1f((GLfloat) i/30.0);
   glEnd();
   /* 顯示控制點 */
   glPointSize(5.0);
   glColor3f(1.0, 1.0, 0.0);
   glBegin(GL_POINTS);
   for (i = 0; i < 4; i++)
     glVertex3fv(&ctrlpoints[i][0]);
   glEnd();
  glFlush();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  if (w <= h)
glOrtho(-5.0, 5.0, -5.0*(GLfloat)h/(GLfloat)w,
5.0*(GLfloat)h/(GLfloat)w, -5.0, 5.0);
  else
glOrtho(-5.0*(GLfloat)w/(GLfloat)h, 5.0*(GLfloat)w/(GLfloat)h, -5.0, 5.0, -5.0, 5.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
   }

二、曲面構造

  曲面的繪制方法基本上與曲線的繪制方法是相同的,所不同的是曲面使用二維求值器,并且控制點連接起來形成一個網格。

  對于曲面,求值器除了使用二個參數U、V之外,其余與一維求值器基本相同。頂點坐標 、顏色、法線矢量和紋理坐標都對應于曲面而不是曲線。在OpenGL中定義二維求值器的函數是:

void glMap2{fd}(GLenum target,TYPE u1,TYPE u2,GLint ustride,GLint uorder,TYPE v1,TYPE v2,
GLint vstride,GLint vorder,TYPE points);

  參數target可以是表一中任意值,不過需將MAP1改為MAP2。同樣,啟動曲面的函數仍是glEnable(),關閉是glDisable()。u1、u2為u的最大值和最小值;v1、v2為v的最大值和最小值。參數ustride和vstride指出在控制點數組中u和v向相鄰點的跨度,即可從一個非常大的數組中選擇一塊控制點長方形。例如,若數據定義成如下形式:

GLfloat ctlpoints[100][100][3];
  并且,要用從ctlpoints[20][30]開始的4x4子集,選擇ustride為100*3,vstride為3,初始點設置為ctlpoints[20][30][0]。最后的參數都是階數,uorder和vorder,二者可以不同。

  曲面坐標計算函數為:

void glEvalCoord2{fd}[v](TYPE u,TYPE v);
  該函數產生曲面坐標并繪制。參數u和v是定義域內的值。下面看一個繪制Bezier曲面的例子:

/* 控制點的坐標 */
   GLfloat ctrlpoints[4][4][3] = {
{{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0},
  {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
  {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0},
{0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}},
{{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0},
{0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}},
{{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
{0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}}
};
void myinit(void)
{
     glClearColor (0.0, 0.0, 0.0, 1.0);
     glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4,
&ctrlpoints[0][0][0]);
glEnable(GL_MAP2_VERTEX_3);
glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
glEnable(GL_DEPTH_TEST);
   }
   void CALLBACK display(void)
   {
     int i, j;
glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);
     glColor3f(0.3, 0.6, 0.9);
     glPushMatrix ();
     glRotatef(35.0, 1.0, 1.0, 1.0);
     for (j = 0; j <= 8; j++)
     {
       glBegin(GL_LINE_STRIP);
       for (i = 0; i <= 30; i++)
         glEvalCoord2f((GLfloat)i/30.0, (GLfloat)j/8.0);
       glEnd();
       glBegin(GL_LINE_STRIP);
         for (i = 0; i <= 30; i++)
           glEvalCoord2f((GLfloat)j/8.0,
(GLfloat)i/30.0);
       glEnd();
     }
     glPopMatrix ();
     glFlush();
   }

  OpenGL中定義均勻間隔的曲面坐標值的函數與曲線的類似,其函數形式為:

void glMapGrid2{fd}(GLenum nu,TYPE u1,TYPE u2,GLenum nv,TYPE v1,TYPE v2);
void glEvalMesh2(GLenum mode,GLint p1,GLint p2,GLint q1,GLint q2);

  第一個函數定義參數空間的均勻網格,從u1到u2分為等間隔的nu步,從v1到v2分為等間隔的nv步,然后glEvalMesh2()把這個網格應用到已經啟動的曲面計算上。第二個函數參數mode除了可以是GL_POINT和GL_LINE外,還可以是GL_FILL,即生成填充空間曲面。

  下面舉出一個用網格繪制一個經過光照和明暗處理的Bezier曲面的例程:


#include "glos.h"
#include
#include
#include
void myinit(void);
void initlights(void);
void CALLBACK myReshape(GLsizei w, GLsizei h);
void CALLBACK display(void);
/* 控制點坐標 */
GLfloat ctrlpoints[4][4][3] = {
   {{-1.5, -1.5, 2.0}, {-0.5, -1.5, 2.0},
  {0.5, -1.5, -1.0}, {1.5, -1.5, 2.0}},
  {{-1.5, -0.5, 1.0}, {-0.5, 1.5, 2.0},
{0.5, 0.5, 1.0}, {1.5, -0.5, -1.0}},
{{-1.5, 0.5, 2.0}, {-0.5, 0.5, 1.0},
{0.5, 0.5, 3.0}, {1.5, -1.5, 1.5}},
{{-1.5, 1.5, -2.0}, {-0.5, 1.5, -2.0},
{0.5, 0.5, 1.0}, {1.5, 1.5, -1.0}}
};
void initlights(void)
{
   GLfloat ambient[] = { 0.4, 0.6, 0.2, 1.0 };
   GLfloat position[] = { 0.0, 1.0, 3.0, 1.0 };
   GLfloat mat_diffuse[] = { 0.2, 0.4, 0.8, 1.0 };
   GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat mat_shininess[] = { 80.0 };
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
   glLightfv(GL_LIGHT0, GL_POSITION, position);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}
void CALLBACK display(void)
{
  glClear(GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);
  glPushMatrix();
  glRotatef(35.0, 1.0, 1.0, 1.0);
  glEvalMesh2(GL_FILL, 0, 20, 0, 20);
  glPopMatrix();
  glFlush();
}
void myinit(void)
{
     glClearColor (0.0, 0.0, 0.0, 1.0);
   glEnable (GL_DEPTH_TEST);
  glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12,
4, &ctrlpoints[0][0][0]);
  glEnable(GL_MAP2_VERTEX_3);
  glEnable(GL_AUTO_NORMAL);
  glEnable(GL_NORMALIZE);
  glMapGrid2f(20, 0.0, 1.0, 20, 0.0, 1.0);
initlights();
}
void CALLBACK myReshape(GLsizei w, GLsizei h)
{
   glViewport(0, 0, w, h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   if (w <= h)
glOrtho(-4.0, 4.0, -4.0*(GLfloat)h/(GLfloat)w,
4.0*(GLfloat)h/(GLfloat)w, -4.0, 4.0);
else
  glOrtho(-4.0*(GLfloat)w/(GLfloat)h,
4.0*(GLfloat)w/(GLfloat)h, -4.0, 4.0, -4.0, 4.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void main(void)
{
   auxInitDisplayMode (AUX_SINGLE AUX_RGBA);
  auxInitPosition (0, 0, 500, 500);
  auxInitWindow ("Lighted and Filled Bezier Surface");
  myinit();
  auxReshapeFunc (myReshape);
  auxMainLoop(display);
}

三、圖元逼近法繪制三維物體
  在OpenGL的輔助庫中,提供了繪制11種基本幾何圖形的函數,具體參考第一講的有關內容,在此不再贅述。這里我們討論用另外一種方法來繪制三維物體 。
  需要注重的是,這里我們用來近似曲面的多邊形最好選擇三角形,而不是四邊形或其他外形的多邊形,這是因為三角形的三個頂點在任何時候都位于同一平面內,它一定是非常簡單的非凹多邊形,而四邊形或其他多邊形的頂點可能不在同一平面內,也就有可能不是簡單多邊形,對于這樣的多邊形,OpenGL是不能正常處理的。假設我們繪制一個球體,球體表面用很多個小三角形拼接而成,顯然,用來近似球面的三角形越小、三角形越多,那么球面就越光滑。為了簡要地說明如何用三角形逼近球體,這里我們使用三角形來構造一個20面體,二十面體的頂點坐標定義在vdata[][]數組中,tindinces[][]數組定義了構成二十面體的二十個三角形頂點的繪制順序。下面是主要實現代碼:
#define x 5.25731
#define z 8.50651
static GLfloat vdata[12][3]={
{x,0.0,z},{x,0.0,z},{-x,0.0,-z},{x,0.0,-z},
{0.0,z,x},{0.0,z,-x},{0.0,-z-x},{0.0,-z,-x},
{z,x,0.0},{-z,x,0.0},{z,-x,0.0},{-z,-x,0.0}
};
static GLint tindices[20][3]={
{0,4,1},{0,9,4},{9,5,4},{4,5,8},{4,8,1},
{8,10,1},{8,3,10},{5,3,8},{5,2,3},{2,7,3},
{7,10,3},{7,6,10},{7,11,6},{11,0,6},
{6,1,10},{9,0,11},{9,11,2},{9,2,5},{7,2,11}
};
glColor3f(1.0, 0.0, 0.0);
for(int i=0;i <20;i++){
glBegin(GL_TRIANGLES);
glVertex3fv(&vdata[tindices[i][0]][0]);
glVertex3fv(&vdata[tindices[i][1]][0]);
glVertex3fv(&vdata[tindices[i][2]][0]);
glEnd();
}

  顯然,用正二十面體來表示一個球體顯得過于粗糟,可以通過增加面數的方法使正多面體和求更為接近,一種簡單的方法是剖分法,即將前面定義的三角形面分成幾個面,例如,一分為四,形成4個多邊形等,具體實現方法這里就不再贅述了。

上一篇:實例講解

下一篇:C++ 友元(friend)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区二中文字幕在线看| 亚洲女人天堂色在线7777| 国产精品99免视看9| 欧美电影在线观看完整版| 欧美性猛交xxxx偷拍洗澡| 亚洲精品wwww| 欧美性色xo影院| 日韩一区在线视频| 成人高h视频在线| 国内自拍欧美激情| 国产成人在线亚洲欧美| 日本国产高清不卡| 国产欧美一区二区三区四区| 亚洲国产精品久久久久久| 欧美在线播放视频| 亚洲第一视频网站| 97在线视频精品| 亚洲欧美国产另类| 亚洲已满18点击进入在线看片| 日韩在线视频观看正片免费网站| 久久久国产精品亚洲一区| 在线电影中文日韩| 精品国产一区二区三区在线观看| 欧美成人精品在线| 亚洲天堂一区二区三区| 亚洲精品999| www.xxxx欧美| 91精品国产综合久久久久久蜜臀| www.亚洲人.com| 国产精品香蕉国产| 日韩天堂在线视频| 美女性感视频久久久| 欧美性xxxxx| 亚洲人成免费电影| 性色av一区二区三区在线观看| 欧美日韩黄色大片| 精品一区二区三区电影| 中文字幕日韩高清| 日韩国产激情在线| 亚洲精品美女久久久| 81精品国产乱码久久久久久| 韩国精品美女www爽爽爽视频| 欧美小视频在线观看| 国产精品高潮呻吟久久av黑人| 日本亚洲欧美三级| 两个人的视频www国产精品| 国产日韩欧美视频在线| 国产综合福利在线| 成人欧美一区二区三区黑人| 亚洲欧美三级在线| 亚洲电影免费观看高清完整版| 日韩最新免费不卡| 久久99国产精品自在自在app| 最近更新的2019中文字幕| 亚洲国产精品va在线观看黑人| 日韩亚洲欧美成人| 日韩免费中文字幕| 成人网中文字幕| 国内免费久久久久久久久久久| 91精品国产九九九久久久亚洲| 奇米影视亚洲狠狠色| 欧美做受高潮1| 69久久夜色精品国产7777| 久久久精品国产| 性欧美办公室18xxxxhd| 俺也去精品视频在线观看| 国产成人一区二区在线| 欧美在线一区二区视频| 在线观看中文字幕亚洲| 中文字幕精品—区二区| 97超碰蝌蚪网人人做人人爽| 97久久久免费福利网址| 久久这里有精品| 欧美另类老女人| 亚洲一区二区三区在线视频| 精品久久久久久久久中文字幕| 亚洲综合中文字幕68页| 日韩欧美国产中文字幕| 亚洲国产91色在线| 亚洲护士老师的毛茸茸最新章节| 国产又爽又黄的激情精品视频| 国产欧美精品在线播放| 日韩精品免费在线观看| 欧美电影免费观看| 欧美电影免费看| 欧美最顶级的aⅴ艳星| 欧美成人一区二区三区电影| 国产区精品在线观看| 欧美日本精品在线| 日日噜噜噜夜夜爽亚洲精品| 亚洲第五色综合网| 成人黄色激情网| 欧美激情国产高清| 中文字幕亚洲一区二区三区| 亚洲精品一二区| 国产精品视频久久久久| 国产成人91久久精品| 一区二区欧美激情| 欧美午夜宅男影院在线观看| 国产91免费观看| 久久久久国产一区二区三区| 国产精品扒开腿做爽爽爽的视频| 亚洲成人a级网| 91综合免费在线| 中文字幕欧美视频在线| 亚洲乱码av中文一区二区| 97久久精品人搡人人玩| 亚洲精品国产综合久久| 成人自拍性视频| 国产999在线| 亚洲偷欧美偷国内偷| 国产欧美va欧美va香蕉在线| 久久影视电视剧免费网站清宫辞电视| 亚洲男人的天堂在线| 色综合久久久久久中文网| 亚洲人精品午夜在线观看| 午夜精品久久久久久久99热| 中文字幕亚洲欧美日韩2019| 欧美日韩在线免费| 97av在线影院| 欧美日韩美女在线| 国产成人免费91av在线| 国产aⅴ夜夜欢一区二区三区| 欧美与欧洲交xxxx免费观看| 精品人伦一区二区三区蜜桃免费| 久久久噜久噜久久综合| 欧美综合激情网| 亚洲人成在线观看| 成人免费在线视频网址| 亚洲黄色片网站| 精品久久久国产| 精品福利免费观看| 激情成人中文字幕| 都市激情亚洲色图| 国产综合福利在线| 亚洲色图偷窥自拍| 日韩在线视频观看正片免费网站| 国产91免费看片| 国产精品爽爽爽| 亚洲美女av在线| 九九精品在线视频| 91精品国产91| 欧美性xxxx极品hd满灌| 在线观看日韩av| 欧美国产乱视频| 一个人www欧美| 欧美成人全部免费| 精品国产一区av| 深夜福利国产精品| 亚洲少妇中文在线| 欧美电影免费观看| 91免费在线视频| 日韩电影中文字幕在线观看| 日韩精品免费综合视频在线播放| www.精品av.com| 成人黄色片网站| 亚洲精品第一国产综合精品| 欧美精品在线观看91| 日韩av电影手机在线观看| 欧美成人免费在线视频| 亚洲精品白浆高清久久久久久| 国产乱人伦真实精品视频| 91在线无精精品一区二区| 欧美亚洲午夜视频在线观看|