使用Eclipse RCP進(jìn)行桌面程序開發(fā)(六):向OpenGL進(jìn)軍
Posted on 2006-12-09 10:48 京山游俠 閱讀(17193) 評(píng)論(17) 編輯 收藏 所屬分類: 擁抱Eclipse RCP
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(一):快速起步
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(二):菜單、工具欄和對(duì)話框
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(三):視圖和透視圖
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(四):在Windows中使用Active X控件
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(五):2D繪圖
看完這一篇,我們應(yīng)該可以使用OpenGL繪制如下圖的場景了。該場景是一個(gè)旋轉(zhuǎn)的三菱錐矩陣,下面是旋轉(zhuǎn)到不同方位的截圖:



我整整花了一個(gè)星期的時(shí)間來研究SWT中的OpenGL,遇到的第一個(gè)困難是找不到傳說中的GL類和GLU類,最后,通過搜索引擎終于找到了,原來使用Eclipse進(jìn)行OpenGL開發(fā),還需要另外下載OpenGL插件,如下圖:

這里有OpenGL的類庫,還有一個(gè)示例,把類庫下載下來,解壓,放到Eclipse的Plugin目錄下,然后在我們的項(xiàng)目中添加依賴項(xiàng),就可以看到我們需要使用的類了,如下圖:

我們需要對(duì)OpenGL編程的一些基本概念有點(diǎn)了解,在OpenGL中,3D場景不是直接繪制到操作系統(tǒng)的窗口上的,而是有一個(gè)稱為著色描述表(Rendering Context)的東西,我們這里簡稱它為context,OpenGL的繪圖命令都是在當(dāng)前context上進(jìn)行繪制,然后再把它渲染到操作系統(tǒng)的設(shè)備描述表(Device Context)上,這里,我們可以簡單的理解成把它渲染到窗口控件上(其實(shí)也可以渲染到全屏幕)。
在Windows中使用OpenGL編程比較麻煩,因?yàn)槲覀冃枰O(shè)置一個(gè)叫做象素格式的東西,大家只要看看下面的這段C代碼,就知道我為什么說它麻煩了:
static PIXELFORMATDESCRIPTOR?pfd= //pfd?告訴窗口我們所希望的東東

{
sizeof(PIXELFORMATDESCRIPTOR), //上訴格式描述符的大小
1,? ?//?版本號(hào)
PFD_DRAW_TO_WINDOW?| //?格式必須支持窗口
PFD_SUPPORT_OPENGL?| //?格式必須支持OpenGL
PFD_DOUBLEBUFFER, ?//?必須支持雙緩沖
PFD_TYPE_RGBA, //?申請(qǐng)?RGBA?格式
bits, ?//?選定色彩深度
0,?0,?0,?0,?0,?0, ?//?忽略的色彩位
0, //?無Alpha緩存
0, //?忽略Shift?Bit
0, //?無聚集緩存
0,?0,?0,?0, ?//?忽略聚集位
16, ?//?16位?Z-緩存?(深度緩存)?
0, //?無模板緩存
0, //?無輔助緩存
PFD_MAIN_PLANE, ?//?主繪圖層
0, //?保留
0,?0,?0 ?//?忽略層遮罩
?};

if?(!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) //?Windows?找到相應(yīng)的象素格式了嗎?

{
KillGLWindow(); //?重置顯示區(qū)
MessageBox(NULL,"Can't?Find?A?Suitable?PixelFormat.",
?"ERROR",MB_OK|MB_ICONEXCLAMATION);
return?FALSE; //?返回?FALSE
}

if(!SetPixelFormat(hDC,PixelFormat,&pfd)) ?//?能夠設(shè)置象素格式么?

{
KillGLWindow(); ?//?重置顯示區(qū)
MessageBox(NULL,"Can't?Set?The?PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return?FALSE; ?//?返回?FALSE
}

if?(!(hRC=wglCreateContext(hDC))) //?能否取得著色描述表?

{
KillGLWindow(); //?重置顯示區(qū)
MessageBox(NULL,"Can't?Create?A?GL?Rendering?Context.",
"ERROR",MB_OK|MB_ICONEXCLAMATION);
return?FALSE; //?返回?FALSE
}

在SWT中,我們開發(fā)OpenGL應(yīng)用就要簡單得多,這全部要?dú)w功于org.eclipse.swt.opengl包下面的GLCanvas類和GLData類,使用GLCanvas類可以直接創(chuàng)建一個(gè)用于OpenGL渲染的控件,至于設(shè)置象素格式這樣復(fù)雜的問題,它已經(jīng)幫我們解決了,不信你看GLCanvas類的構(gòu)造函數(shù)的實(shí)現(xiàn)。
GLCanvas類中的幾個(gè)方法代表了我一開始提到的OpenGL的幾個(gè)基本概念,setCurrent()方法就是為了把該控件的context設(shè)置為OpenGL的當(dāng)前著色描述表,然后使用GL和GLU類中的方法在當(dāng)前context上進(jìn)行繪圖,繪制完圖形以后,再使用GLCanvas類的swapBuffers()方法交換緩沖區(qū),也就是把context中的3D場景渲染到控件上。
寫到這里,大家肯定認(rèn)為一切問題都應(yīng)該迎刃而解了,然而,我卻碰到了另外一個(gè)困難,這個(gè)困難就是SWT的OpenGL表現(xiàn)怪異,怎么個(gè)怪異呢?請(qǐng)看下面視圖類的代碼:
public?void?createPartControl(Composite?parent)?
{
????????//?TODO?自動(dòng)生成方法存根
????????GLData?data?=?new?GLData();
????????data.depthSize?=?1;
????????data.doubleBuffer?=?true;
????????GLCanvas?canvas?=?new?GLCanvas(parent,?SWT.NO_BACKGROUND,?data);
????????//設(shè)置該canvas的context為OpenGL的當(dāng)前context

????????if(!canvas.isCurrent())
{
????????????canvas.setCurrent();
????????}
????????//這里可以進(jìn)行OpenGL繪圖
????????
????????//交換緩存,將圖形渲染到控件上
????????canvas.swapBuffers();
????}
按道理,我們應(yīng)該可以得到一個(gè)經(jīng)典的3D的黑色場景,但是,我得到的卻是這樣的效果:

相當(dāng)?shù)挠魫灠。褪沁@個(gè)問題困擾了我至少一個(gè)星期。我把官方網(wǎng)站上的示例看了有看,就是找不到問題的關(guān)鍵所在。直到最后,我用了另外一個(gè)線程,每100ms都調(diào)用canvas.swapBuffers()把場景渲染一遍問題才解決。由此可見,之所以回出現(xiàn)上面的問題,主要是因?yàn)槲覀冧秩镜膱鼍昂芸鞎?huì)被操作系統(tǒng)的其他繪圖操作所覆蓋,只有不斷的渲染我們才能看到連續(xù)的3D圖形。
我是這樣實(shí)現(xiàn)讓3D場景連續(xù)渲染的:

public?void?createPartControl(Composite?parent)?
{
????????//?TODO?自動(dòng)生成方法存根
????????GLData?data?=?new?GLData();
????????data.depthSize?=?1;
????????data.doubleBuffer?=?true;
????????GLCanvas?canvas?=?new?GLCanvas(parent,?SWT.NO_BACKGROUND,?data);
????????//將繪圖代碼轉(zhuǎn)移到定時(shí)器中
????????Refresher?rf?=?new?Refresher(canvas);
????????rf.run();
????}
Refresher類的代碼如下:

class?Refresher?implements?Runnable?
{
????public?static?final?int?DELAY?=?100;
????
????private?GLCanvas?canvas;
????

????public?Refresher(GLCanvas?canvas)?
{
????????this.canvas?=?canvas;
????}
????

????public?void?run()?
{

????????if?(this.canvas?!=?null?&&?!this.canvas.isDisposed())?
{

????????????if(!canvas.isCurrent())
{
????????????????canvas.setCurrent();
????????????}
????????????//這里添加OpenGL繪圖代碼
????????????canvas.swapBuffers();
????????????this.canvas.getDisplay().timerExec(DELAY,?this);
????????}
????}
??
}
問題解決,得到的效果圖如下:

OK,下面的任務(wù)就是完完全全的使用OpenGL的繪圖功能了,不管你的OpenGL教材使用的是什么操作系統(tǒng)什么編程語言,你都能很簡單的把它的概念拿到這里來使用。
使用OpenGL的第一件事,就是要設(shè)置投影矩陣、透視圖和觀察者矩陣,如果你不知道為什么要這么做,請(qǐng)查看OpenGL的基礎(chǔ)教材,在這里,照搬就行了。為了讓我們的控件在每次改變大小的時(shí)候都能夠做這些設(shè)置,我們使用事件監(jiān)聽器,如下:

public?void?createPartControl(Composite?parent)?
{
????????//?TODO?自動(dòng)生成方法存根
????????GLData?data?=?new?GLData();
????????data.depthSize?=?1;
????????data.doubleBuffer?=?true;
????????canvas?=?new?GLCanvas(parent,?SWT.NO_BACKGROUND,?data);

????????canvas.addControlListener(new?ControlAdapter()?
{

????????????public?void?controlResized(ControlEvent?e)?
{
????????????????Rectangle?rect?=?canvas.getClientArea();
????????????????GL.glViewport(0,?0,?rect.width,?rect.height);
????????????????
????????????????//選擇投影矩陣
????????????????GL.glMatrixMode(GL.GL_PROJECTION);
????????????????//重置投影矩陣
????????????????GL.glLoadIdentity();
????????????????//設(shè)置窗口比例和透視圖
????????????????GLU.gluPerspective(45.0f,?(float)?rect.width?/?(float)?rect.height,?0.1f,?100.0f);
????????????????//選擇模型觀察矩陣
????????????????GL.glMatrixMode(GL.GL_MODELVIEW);
????????????????//重置模型觀察矩陣
????????????????GL.glLoadIdentity();
????????????????
????????????????//黑色背景
????????????????GL.glClearColor(0.0f,?0.0f,?0.0f,?0.0f);
????????????????//設(shè)置深度緩存
????????????????GL.glClearDepth(1.0f);
????????????????//啟動(dòng)深度測試
????????????????GL.glEnable(GL.GL_DEPTH_TEST);
????????????????//選擇深度測試類型
????????????????GL.glDepthFunc(GL.GL_LESS);
????????????????//啟用陰影平滑
????????????????GL.glShadeModel(GL.GL_SMOOTH);
????????????????//精細(xì)修正透視圖
????????????????GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT,?GL.GL_NICEST);
????????????????//清除屏幕和深度緩存
????????????????GL.glClear(GL.GL_COLOR_BUFFER_BIT?|?GL.GL_DEPTH_BUFFER_BIT);
????????????????//重置當(dāng)前的模型觀察矩陣
????????????????GL.glLoadIdentity();
????????????}
????????});??

????????canvas.addDisposeListener(new?DisposeListener()?
{

????????????public?void?widgetDisposed(DisposeEvent?e)?
{
????????????????dispose();
????????????}
????????});
調(diào)用glLoadIdentity()之后,實(shí)際上將當(dāng)前點(diǎn)移到了屏幕中心,X坐標(biāo)軸從左至右,Y坐標(biāo)軸從下至上,Z坐標(biāo)軸從里至外。OpenGL屏幕中心的坐標(biāo)值是X和Y軸上的0.0f 點(diǎn)。中心左面的坐標(biāo)值是負(fù)值,右面是正值。移向屏幕頂端是正值,移向屏幕底端是負(fù)值。移入屏幕深處是負(fù)值,移出屏幕則是正值。
glTranslatef(x, y, z)是將當(dāng)前點(diǎn)沿著X,Y和Z軸移動(dòng),當(dāng)我們繪圖的時(shí)候,不是相對(duì)于屏幕中間,而是相對(duì)于當(dāng)前點(diǎn)。
glBegin(GL.GL_TRIANGLES)的意思是開始繪制三角形,glEnd()告訴OpenGL三角形已經(jīng)創(chuàng)建好了。通常當(dāng)我們需要畫3個(gè)頂點(diǎn)時(shí),可以使用GL_TRIANGLES。在絕大多數(shù)的顯卡上,繪制三角形是相當(dāng)快速的。如果要畫四個(gè)頂點(diǎn),使用GL_QUADS的話會(huì)更方便。但據(jù)我所知,絕大多數(shù)的顯卡都使用三角形來為對(duì)象著色。最后,如果想要畫更多的頂點(diǎn)時(shí),可以使用GL_POLYGON。
glVertex(x,y,z)用來設(shè)置頂點(diǎn),如果繪制三角形,這些頂點(diǎn)需要三個(gè)一組,如果繪制四邊形,則是四個(gè)為一組。如果我們要為頂點(diǎn)著色,就需要glColor3f (r,g,b)方法,記住,每次設(shè)置以后,這個(gè)顏色就是當(dāng)前顏色,直到再次調(diào)用該方法重新設(shè)置為止。
最后需要介紹的是glRotatef(Angle,Xvector,Yvector,Zvector)方法,該方法負(fù)責(zé)讓對(duì)象圍繞指定的軸旋轉(zhuǎn),Angle參數(shù)指轉(zhuǎn)動(dòng)的角度,注意是浮點(diǎn)數(shù)哦。
下面是我的視圖類的全部代碼,我把3D繪圖的任務(wù)全部放到了另外一個(gè)線程中,并且定義了一個(gè)遞歸方法public void drawPyramid(float x, float y, float z, int n)用來繪制三菱錐矩陣。如下:
package?cn.blogjava.youxia.views;

import?org.eclipse.opengl.GL;
import?org.eclipse.opengl.GLU;
import?org.eclipse.swt.events.ControlAdapter;
import?org.eclipse.swt.events.ControlEvent;
import?org.eclipse.swt.events.DisposeEvent;
import?org.eclipse.swt.events.DisposeListener;
import?org.eclipse.swt.graphics.Rectangle;
import?org.eclipse.swt.opengl.GLData;
import?org.eclipse.swt.widgets.Composite;
import?org.eclipse.ui.part.ViewPart;
import?org.eclipse.swt.opengl.GLCanvas;
import?org.eclipse.swt.SWT;


public?class?OpenGLView?extends?ViewPart?
{

????GLCanvas?canvas;
????@Override

????public?void?createPartControl(Composite?parent)?
{
????????//?TODO?自動(dòng)生成方法存根
????????GLData?data?=?new?GLData();
????????data.depthSize?=?1;
????????data.doubleBuffer?=?true;
????????canvas?=?new?GLCanvas(parent,?SWT.NO_BACKGROUND,?data);

????????canvas.addControlListener(new?ControlAdapter()?
{

????????????public?void?controlResized(ControlEvent?e)?
{
????????????????Rectangle?rect?=?canvas.getClientArea();
????????????????GL.glViewport(0,?0,?rect.width,?rect.height);
????????????????
????????????????//選擇投影矩陣
????????????????GL.glMatrixMode(GL.GL_PROJECTION);
????????????????//重置投影矩陣
????????????????GL.glLoadIdentity();
????????????????//設(shè)置窗口比例和透視圖
????????????????GLU.gluPerspective(45.0f,?(float)?rect.width?/?(float)?rect.height,?0.1f,?100.0f);
????????????????//選擇模型觀察矩陣
????????????????GL.glMatrixMode(GL.GL_MODELVIEW);
????????????????//重置模型觀察矩陣
????????????????GL.glLoadIdentity();
????????????????
????????????????//黑色背景
????????????????GL.glClearColor(0.0f,?0.0f,?0.0f,?0.0f);
????????????????//設(shè)置深度緩存
????????????????GL.glClearDepth(1.0f);
????????????????//啟動(dòng)深度測試
????????????????GL.glEnable(GL.GL_DEPTH_TEST);
????????????????//選擇深度測試類型
????????????????GL.glDepthFunc(GL.GL_LESS);
????????????????//啟用陰影平滑
????????????????GL.glShadeModel(GL.GL_SMOOTH);
????????????????//精細(xì)修正透視圖
????????????????GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT,?GL.GL_NICEST);
????????????????//清除屏幕和深度緩存
????????????????GL.glClear(GL.GL_COLOR_BUFFER_BIT?|?GL.GL_DEPTH_BUFFER_BIT);
????????????????//重置當(dāng)前的模型觀察矩陣
????????????????GL.glLoadIdentity();
????????????}
????????});??

????????canvas.addDisposeListener(new?DisposeListener()?
{

????????????public?void?widgetDisposed(DisposeEvent?e)?
{
????????????????dispose();
????????????}
????????});

????????/**//*
????????
????????*/
????????
????????
????????Refresher?rf?=?new?Refresher(canvas);
????????rf.run();
????}

????@Override

????public?void?setFocus()?
{
????????//?TODO?自動(dòng)生成方法存根

????}

}


class?Refresher?implements?Runnable?
{
????public?static?final?int?DELAY?=?100;
????
????private?GLCanvas?canvas;
????private?float?rotate?=?0.0f;
????

????public?Refresher(GLCanvas?canvas)?
{
????????this.canvas?=?canvas;
????}
????

????public?void?run()?
{

????????if?(this.canvas?!=?null?&&?!this.canvas.isDisposed())?
{

????????????if(!canvas.isCurrent())
{
????????????????canvas.setCurrent();
????????????}
????????????//這里添加OpenGL繪圖代碼
????????????GL.glLoadIdentity();
????????????GL.glClear(GL.GL_COLOR_BUFFER_BIT?|?GL.GL_DEPTH_BUFFER_BIT);
????????????GL.glTranslatef(0,?4.5f,?-11);
????????????//圍繞y軸轉(zhuǎn)起來
????????????rotate?+=?0.5;
????????????GL.glRotatef(rotate,?0,?1.0f,?0);
????????????//調(diào)用遞歸函數(shù),繪制三菱錐矩陣
????????????drawPyramid(0,0,0,4);
????????????canvas.swapBuffers();
????????????this.canvas.getDisplay().timerExec(DELAY,?this);
????????}
????}
????????

????????public?void?drawPyramid(float?x,?float?y,?float?z,?int?n)
{
????????????if(n?==?0)return;
????????????//畫一個(gè)三菱錐
????????????GL.glBegin(GL.GL_TRIANGLES);
????????????????//畫背面
????????????????GL.glColor3f(1.0f,0.0f,0.0f);
????????????????GL.glVertex3f(?x,?y,?z);
????????????????GL.glColor3f(0.0f,1.0f,0.0f);
????????????????GL.glVertex3f(x+1.0f,y-1.63f,z-0.57f);
????????????????GL.glColor3f(0.0f,0.0f,1.0f);
????????????????GL.glVertex3f(?x-1.0f,y-1.63f,z-0.57f);
????????????????//畫底面
????????????????GL.glColor3f(1.0f,0.0f,0.0f);
????????????????GL.glVertex3f(?x,y-1.63f,z+1.15f);
????????????????GL.glColor3f(0.0f,1.0f,0.0f);
????????????????GL.glVertex3f(x-1.0f,y-1.63f,z-0.57f);
????????????????GL.glColor3f(0.0f,0.0f,1.0f);
????????????????GL.glVertex3f(?x+1.0f,y-1.63f,z-0.57f);
????????????????//畫左側(cè)面
????????????????GL.glColor3f(1.0f,0.0f,0.0f);
????????????????GL.glVertex3f(?x,y,z);
????????????????GL.glColor3f(0.0f,1.0f,0.0f);
????????????????GL.glVertex3f(x-1.0f,y-1.63f,z-0.57f);
????????????????GL.glColor3f(0.0f,0.0f,1.0f);
????????????????GL.glVertex3f(?x,y-1.63f,z+1.15f);
????????????????//畫右側(cè)面
????????????????GL.glColor3f(1.0f,0.0f,0.0f);
????????????????GL.glVertex3f(?x,y,z);
????????????????GL.glColor3f(0.0f,1.0f,0.0f);
????????????????GL.glVertex3f(x,y-1.63f,z+1.15f);
????????????????GL.glColor3f(0.0f,0.0f,1.0f);
????????????????GL.glVertex3f(?x+1.0f,y-1.63f,z-0.57f);
????????????GL.glEnd();
????????????//遞歸調(diào)用,畫多個(gè)三菱錐
????????????drawPyramid(x,y-1.63f,z+1.15f,n-1);
????????????drawPyramid(x-1.0f,y-1.63f,z-0.57f,n-1);
????????????drawPyramid(x+1.0f,y-1.63f,z-0.57f,n-1);
????????}
}
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(二):菜單、工具欄和對(duì)話框
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(三):視圖和透視圖
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(四):在Windows中使用Active X控件
使用Eclipse RCP進(jìn)行桌面程序開發(fā)(五):2D繪圖
看完這一篇,我們應(yīng)該可以使用OpenGL繪制如下圖的場景了。該場景是一個(gè)旋轉(zhuǎn)的三菱錐矩陣,下面是旋轉(zhuǎn)到不同方位的截圖:
我整整花了一個(gè)星期的時(shí)間來研究SWT中的OpenGL,遇到的第一個(gè)困難是找不到傳說中的GL類和GLU類,最后,通過搜索引擎終于找到了,原來使用Eclipse進(jìn)行OpenGL開發(fā),還需要另外下載OpenGL插件,如下圖:
這里有OpenGL的類庫,還有一個(gè)示例,把類庫下載下來,解壓,放到Eclipse的Plugin目錄下,然后在我們的項(xiàng)目中添加依賴項(xiàng),就可以看到我們需要使用的類了,如下圖:
我們需要對(duì)OpenGL編程的一些基本概念有點(diǎn)了解,在OpenGL中,3D場景不是直接繪制到操作系統(tǒng)的窗口上的,而是有一個(gè)稱為著色描述表(Rendering Context)的東西,我們這里簡稱它為context,OpenGL的繪圖命令都是在當(dāng)前context上進(jìn)行繪制,然后再把它渲染到操作系統(tǒng)的設(shè)備描述表(Device Context)上,這里,我們可以簡單的理解成把它渲染到窗口控件上(其實(shí)也可以渲染到全屏幕)。
在Windows中使用OpenGL編程比較麻煩,因?yàn)槲覀冃枰O(shè)置一個(gè)叫做象素格式的東西,大家只要看看下面的這段C代碼,就知道我為什么說它麻煩了:





















































在SWT中,我們開發(fā)OpenGL應(yīng)用就要簡單得多,這全部要?dú)w功于org.eclipse.swt.opengl包下面的GLCanvas類和GLData類,使用GLCanvas類可以直接創(chuàng)建一個(gè)用于OpenGL渲染的控件,至于設(shè)置象素格式這樣復(fù)雜的問題,它已經(jīng)幫我們解決了,不信你看GLCanvas類的構(gòu)造函數(shù)的實(shí)現(xiàn)。
GLCanvas類中的幾個(gè)方法代表了我一開始提到的OpenGL的幾個(gè)基本概念,setCurrent()方法就是為了把該控件的context設(shè)置為OpenGL的當(dāng)前著色描述表,然后使用GL和GLU類中的方法在當(dāng)前context上進(jìn)行繪圖,繪制完圖形以后,再使用GLCanvas類的swapBuffers()方法交換緩沖區(qū),也就是把context中的3D場景渲染到控件上。
寫到這里,大家肯定認(rèn)為一切問題都應(yīng)該迎刃而解了,然而,我卻碰到了另外一個(gè)困難,這個(gè)困難就是SWT的OpenGL表現(xiàn)怪異,怎么個(gè)怪異呢?請(qǐng)看下面視圖類的代碼:



















按道理,我們應(yīng)該可以得到一個(gè)經(jīng)典的3D的黑色場景,但是,我得到的卻是這樣的效果:
相當(dāng)?shù)挠魫灠。褪沁@個(gè)問題困擾了我至少一個(gè)星期。我把官方網(wǎng)站上的示例看了有看,就是找不到問題的關(guān)鍵所在。直到最后,我用了另外一個(gè)線程,每100ms都調(diào)用canvas.swapBuffers()把場景渲染一遍問題才解決。由此可見,之所以回出現(xiàn)上面的問題,主要是因?yàn)槲覀冧秩镜膱鼍昂芸鞎?huì)被操作系統(tǒng)的其他繪圖操作所覆蓋,只有不斷的渲染我們才能看到連續(xù)的3D圖形。
我是這樣實(shí)現(xiàn)讓3D場景連續(xù)渲染的:












Refresher類的代碼如下:































問題解決,得到的效果圖如下:
OK,下面的任務(wù)就是完完全全的使用OpenGL的繪圖功能了,不管你的OpenGL教材使用的是什么操作系統(tǒng)什么編程語言,你都能很簡單的把它的概念拿到這里來使用。
使用OpenGL的第一件事,就是要設(shè)置投影矩陣、透視圖和觀察者矩陣,如果你不知道為什么要這么做,請(qǐng)查看OpenGL的基礎(chǔ)教材,在這里,照搬就行了。為了讓我們的控件在每次改變大小的時(shí)候都能夠做這些設(shè)置,我們使用事件監(jiān)聽器,如下:























































調(diào)用glLoadIdentity()之后,實(shí)際上將當(dāng)前點(diǎn)移到了屏幕中心,X坐標(biāo)軸從左至右,Y坐標(biāo)軸從下至上,Z坐標(biāo)軸從里至外。OpenGL屏幕中心的坐標(biāo)值是X和Y軸上的
glTranslatef(x, y, z)是將當(dāng)前點(diǎn)沿著X,Y和Z軸移動(dòng),當(dāng)我們繪圖的時(shí)候,不是相對(duì)于屏幕中間,而是相對(duì)于當(dāng)前點(diǎn)。
glBegin(GL.GL_TRIANGLES)的意思是開始繪制三角形,glEnd()告訴OpenGL三角形已經(jīng)創(chuàng)建好了。通常當(dāng)我們需要畫3個(gè)頂點(diǎn)時(shí),可以使用GL_TRIANGLES。在絕大多數(shù)的顯卡上,繪制三角形是相當(dāng)快速的。如果要畫四個(gè)頂點(diǎn),使用GL_QUADS的話會(huì)更方便。但據(jù)我所知,絕大多數(shù)的顯卡都使用三角形來為對(duì)象著色。最后,如果想要畫更多的頂點(diǎn)時(shí),可以使用GL_POLYGON。
glVertex(x,y,z)用來設(shè)置頂點(diǎn),如果繪制三角形,這些頂點(diǎn)需要三個(gè)一組,如果繪制四邊形,則是四個(gè)為一組。如果我們要為頂點(diǎn)著色,就需要glColor
最后需要介紹的是glRotatef(Angle,Xvector,Yvector,Zvector)方法,該方法負(fù)責(zé)讓對(duì)象圍繞指定的軸旋轉(zhuǎn),Angle參數(shù)指轉(zhuǎn)動(dòng)的角度,注意是浮點(diǎn)數(shù)哦。
下面是我的視圖類的全部代碼,我把3D繪圖的任務(wù)全部放到了另外一個(gè)線程中,并且定義了一個(gè)遞歸方法public void drawPyramid(float x, float y, float z, int n)用來繪制三菱錐矩陣。如下:















































































































































































