導讀:visual c++是當前最為流行的軟件開發(fā)工具之一,它匯集了微軟公司的技術(shù)精華,不僅全面的貫徹了面向?qū)ο蠹夹g(shù),而且在編譯優(yōu)化技術(shù)方面較其它同類產(chǎn)品具有明顯的優(yōu)勢。
1 引言
opengl是在sgi microsoft dec ibm和intel等多家世界著名計算機公司的倡導下,基于sgi的gl標準,制定的一個通用共享的開放式三維圖形標準。opengl實際上是一種圖形與硬件的接口。在仿真三維立體建模、虛擬現(xiàn)實技術(shù)、3d游戲開發(fā)等領(lǐng)域,opengl起著重要作用。
visual c++是當前最為流行的軟件開發(fā)工具之一,它匯集了微軟公司的技術(shù)精華,不僅全面的貫徹了面向?qū)ο蠹夹g(shù),而且在編譯優(yōu)化技術(shù)方面較其它同類產(chǎn)品具有明顯的優(yōu)勢。它是一個徹底的程序員級的開發(fā)環(huán)境,“可視化”的設(shè)計減少了不少編程的工作量。visual c++6.0更加適應(yīng)當今計算機網(wǎng)絡(luò)化,運行速度快,以及加強數(shù)據(jù)傳輸?shù)膬?yōu)勢。成為軟件開發(fā)的首選工具。
當前在visual c++6.0中已經(jīng)集成了opengl圖形標準,使得opengl在三維圖形設(shè)計領(lǐng)域得到廣泛應(yīng)用。
2 opengl的實現(xiàn)原理
(1) opengl的工作結(jié)構(gòu)
opengl的指令的解釋模型是客戶/服務(wù)器模型,即客戶(試圖用opengl進行繪制工作的應(yīng)用程序)向服務(wù)器(opengl內(nèi)核)發(fā)布命令,這些opengl命令則是由服務(wù)器來解釋的。在大多數(shù)情況下,客戶和服務(wù)器是運行在同一臺計算機的?;诳蛻?服務(wù)器模式,在網(wǎng)絡(luò)環(huán)境中很容易使用opengl,且在不同計算機上的多個客戶可以得到在其他計算機上服務(wù)器的服務(wù)。
opengl的庫函數(shù)被封裝在opengl32.dll動態(tài)鏈接庫中。從客戶應(yīng)用程序發(fā)布的對opengl函數(shù)的調(diào)用首先被opengl32.dll處理,在傳給服務(wù)器后,被進一步處理,然后傳給ddi,最后傳遞給視頻顯示驅(qū)動程序。
(2) opengl的圖形操作步驟
運用opengl在計算機屏幕上繪出三維場景的基本步驟是:
·設(shè)置像素格式
像素格式告訴opengl繪制風格、顏色模式、 顏色位數(shù)等重要信息;
· 建立模型
根據(jù)基本圖元建立景物的三維模型,并對模型進行數(shù)學描述;
·舞臺布置
把景物放置在三維空間的適當位置,設(shè)置三維透視視覺體以觀察場景;
· 效果處理
設(shè)置物體的材質(zhì),加入光照及光照條件;
· 光柵化
把景物及其顏色信息轉(zhuǎn)化為可在計算機屏幕上顯示的像素信息。
(3) opengl的基本程序結(jié)構(gòu)
opengl編程類似與c編程,實際接口就是c,所以很多有關(guān)opengl的書中的程序都是使用標準c(或是win32 console application)調(diào)用opengl函數(shù)實現(xiàn)的。
·例1用標準c編寫一個“繞y軸旋轉(zhuǎn)的線框型茶壺”的例子來說明opengl的基本程序結(jié)構(gòu)。
例1 opengl例程myteapot.c
#include
#include “gl.h” //基本庫
#include “glu.h” //實用庫
#include “glaux.h” //輔助庫
#include
void init (void);void callback reshape (glsizei w,glsizei h);
void callback display (void);void callback stepdisplay (void);
int symbol=1; float rot=0;
void init (void)
{ glclearcolor(0.0,0.0,0.0,0.0); //將窗口清為黑色
}
void callback stepdisplay (void)
{ rot+=4; if(rot》360) rot=0; display ();
}
void callback display (void)
{ glclear (gl_color_buffer_bit);
//將當前顏色緩存清為窗口的顏色
glpushmatrix(); gltranslatef(0.0,0.0,-80);
if (symbol) glrotatef(rot,0,1,0);
else gltranslatef(0,0,-rot);
glcolor3f(0,1,0.5); //設(shè)置顏色
auxwireteapot(20.0);
//繪制一個線框型的茶壺
glpopmatrix();
glflush(); //強制繪圖完成
auxswapbuffers();
//交換兩個顏色緩沖區(qū)的內(nèi)容
}
void callback reshape (glsizei w,glsizei h)
{ if(h= =0)
h=1; glviewport(0,0,w,h) //定義視口;
glmatrixmode(gl_projection);
//定義操作矩陣的類型為投影操作矩陣
glloadidentity(); gluperspective(90,w/h,1.0,200);
//定義了一個四棱臺視景體
glmatrixmode(gl_modelview); glloadidentity();
}
void main(void)
{ auxinitdisplaymode(aux_double|aux_rgba);
// rgba和雙緩沖模式
auxinitposition(0,0,400,360);
//指定要建立的窗口在屏幕窗口中的位置和大小
auxinitwindow(“my teapot ”);
//顯示窗口標題
init(); auxreshapefunc(reshape); auxidlefunc(stepdisplay);
auxmainloop(display);
}
3 vc++6.0中的opengl編程
(1) 創(chuàng)建一個名字為nehe新的單文檔工程;
(2) 包含頭文件與函數(shù)庫文件
在cneheview.h文件首部添加頭文件的包含:
·#include “gl.h” //基本庫
· #include “glu.h” //實用庫
· #include “glaux.h” //輔助庫
選擇tool|options菜單命令添加頭文件包含語句,選擇菜單命令project|settings添加庫文件包含;
(3) 設(shè)置像素格式
先在cneheview.h中添加保護成員函數(shù)bsetup pixelformat(),
添加保護成員函數(shù)init(),聲明兩個公有成員:cclientdc*m_pdc; crect m_rect;在構(gòu)造函數(shù)
cneheview()中對m_pdc進行初始化。編輯bsetuppixelformat()函數(shù);
bool cneheview::bsetuppixelformat()
{static pixelformatdescriptor pfd=
//初始化像素格式
{ sizeof(pixelformatdescriptor),
// pfd的大小
1, //版本號
pfd_draw_to_window|pfd_support_opengl|
pfd_type_rgba,
24, 0,0,0,0,0,0,
//24位顏色深度,缺省的顏色位面數(shù)
0,0,0,
//沒有alpha緩沖, 忽略shift位, 沒有累積緩沖區(qū)
0,0,0,0, //忽略的累積位
32,0,0,
//32位深度緩沖區(qū), 沒有模板緩沖區(qū), 沒有輔助緩沖區(qū)
pfd_main_plane,
//主要層次方式
0, 0,0,0 //保留位,屏蔽層次掩模
};
int pixelformat;
if ((pixelformat=choosepixelformat(m_pdc-》getsafehdc(),&pfd))==0)
{messagebox(“choosepixelformat failed”);
return false;
}
if (setpixelformat(m_pdc-》getsafehdc(),pixelformat,&pfd)==false)
{messagebox(“setpixelformat failed”);
return false;
}
return true;
}
(4) 創(chuàng)建著色描述表并當前化著色描述表
編輯init()函數(shù);
(5) 刪除著色描述表
添加wm_destroy消息,生成ondestroy()函數(shù),在oncreate()函數(shù)中調(diào)用init()函數(shù);
(6) 增加wm_size消息,生成消息響應(yīng)函數(shù)onsize(),編輯該函數(shù);
(7) 選擇函數(shù)precreatewindow(createstruct& cs),編輯該函數(shù);
(8) 在ondraw()函數(shù)中完成繪制工作。
4 應(yīng)用實例
4.1 機械手臂控制系統(tǒng)的簡介
在本實例中,模擬機械手臂的控制,系統(tǒng)的工作過程如下:
(1) 控制機械手臂運動到工件上方,并夾取工件;
(2) 然后控制機械手臂運動到檢測裝置(聲腔)處,檢測完成后,控制下料筒到相應(yīng)位置;
(3) 然后讓機械手臂運動到下料口上方,放入工件;
(4) 機械手臂復(fù)位,重復(fù)以上操作。
創(chuàng)建一個基于cformview的單文檔工程,取名為robort
arm。在對話框idd_robortarm_form的上方添加一個id號為idc_buttondraw的按鈕,并為其添加消息響應(yīng)函數(shù)onbuttondraw(),在函數(shù)onbuttondraw()中完成繪制工作。在繪制一個復(fù)雜的實際系統(tǒng)時,有很多代碼是重復(fù)的。為了減少由于重復(fù)拷貝而造成的應(yīng)用程序冗長以及對系統(tǒng)資源的占用,我們在本程序中采用了動態(tài)鏈接庫。
動態(tài)鏈接庫dll(dynamic link library)是一種基于windows的程序模塊,它是一個包含函數(shù)的庫文件,可以在運行時被裝入和鏈接。動態(tài)鏈接庫dll和其他c++庫的區(qū)別在于,動態(tài)鏈接庫dll是在運行時和應(yīng)用程序鏈接,而不是在編譯、鏈接的過程中被調(diào)用。要使用動態(tài)鏈接庫dll,必須將動態(tài)鏈接庫相應(yīng)的dll文件拷貝到一定的目錄下,在本實例中,將dll文件放到了應(yīng)用程序所在的子目錄下。
一個應(yīng)用程序鏈接dll的方法有兩種:顯式鏈接和隱式鏈接。顯式鏈接指動態(tài)加載或運行時的鏈接;隱式鏈接指靜態(tài)加載或加載時動態(tài)鏈接。在本實例中,應(yīng)用的是隱式鏈接。例如:在dll代碼中,聲明了圓柱體和立方體的導出函數(shù)分別為:
__declspec(dllexport) void drawcylinder
(gldouble dtopradius = 1.0, // 頂面半徑
gldouble dbottomradius = 1.0, // 底面半徑
gldouble dlength = 1.0, // 長度
gldouble dxrotateptratio = 0.5, // x軸旋轉(zhuǎn)比率
int nslice = 20, // 等分數(shù)
int mask = 0xff, // 面掩碼
glint* ptexptr = 0, // 貼圖指針
int ntype = 2 // 貼圖類型
);
__declspec(dllexport) void drawcube
(glfloat cx = 1.0f, // x軸長度
glfloat cy = 1.0f, // y軸長度
glfloat cz = 1.0f, // z軸長度
int mask = 0xff, // 面掩碼
glint* ptexptr = 0, // 貼圖指針
int ntype = 2 // 貼圖類型
);
系統(tǒng)由基本的圓柱體和立方體構(gòu)成, 部分數(shù)據(jù)結(jié)構(gòu)如下:
//定義水平平臺的長、寬、高
#define lengthlevel 1.7f
#define widthlevel 0.9f
#define heightlevel 0.015f
//定義傾斜平臺支柱的長、寬、高
#define lengthbrace 0.04f
#define widthbrace 0.04f
#define heightbrace 0.4f
//定義放料箱的長、寬、高
#define lengthbox 0.05f
#define widthbox 0.06f
#define heightbox 0.05f
//定義物料輪的半徑和高度
#define radiusdisk 0.14f
#define heightdisk 0.02f
//定義工件的半徑和高度
#define radiusworkpiece 0.025f
#define heightworkpiece 0.03f
//圓柱體:機械手的底座和支柱、工件、物料輪、聲腔、下料口、下料筒
void drawrobotsystem:: drawcylinder
(gldouble dtopradius, gldouble dbottomradius,
gldouble dlength, gldouble dxrotateptratio, int nslice, int mask,
glint* ptexptr, int ntype);
//立方體:水平平臺、傾斜平臺、機械手的臂和手、表盤、放料箱
void drawrobotsystem:: drawcube
(glfloat cx, glfloat cy, glfloat cz, int
mask, glint* ptexptr, int ntype) ;
附圖為完整的模擬系統(tǒng)界面。
4.2 應(yīng)用結(jié)果分析
該仿真系統(tǒng)以三維動畫的方式很好地仿真了機械手臂控制系統(tǒng)的整個過程。其中的動畫包括:物料輪和下料筒的轉(zhuǎn)動,聲腔的閃爍,機械手臂的運動。其中機械手臂的運動又包括:機械手臂的上移、下移、旋轉(zhuǎn)、夾取工件、釋放工件。在實現(xiàn)動畫時,我們采用的是雙緩存法。它是一種邊畫邊顯示的實時動畫技術(shù)。其基本思想是提供兩個基本緩沖區(qū),在顯示前臺緩存內(nèi)容中的一幀畫面時,后臺緩存正在繪制下一幀畫面,當繪制完畢,則后臺緩存內(nèi)容在屏幕上顯示出來。而前臺繪制下一副畫面內(nèi)容。這種方法受圖形生成速度的制約,圖形繪制越復(fù)雜,則速度越慢。由于該系統(tǒng)比較復(fù)雜且要求實時性較高,而opengl占用計算機的資源又比較大,所以不能做到對該系統(tǒng)的實時仿真。但對于機械手臂控制系統(tǒng)的整個工作過程還是模擬地很到位的。
5 結(jié)束語
本文提出了利用vc++6.0和opengl對實際系統(tǒng)進行仿真的方法。并給出了一個機械手臂控制系統(tǒng)的模擬實例,該實例現(xiàn)已應(yīng)用于濰坊市怡力達電聲有限公司的“ecm自動測試視覺識別與控制系統(tǒng)”,目前該系統(tǒng)運行良好。