使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

看完这一篇,我们应该可以使用OpenGL绘制如下图的场景了。该场景是一个旋转的三菱锥矩阵,下面是旋转到不同方位的截图:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

我整整花了一个星期的时间来研究SWT中的OpenGL,遇到的第一个困难是找不到传说中的GL类和GLU类,最后,通过搜索引擎终于找到了,原来使用Eclipse进行OpenGL开发,还需要另外下载OpenGL插件,如下图:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

这里有OpenGL的类库,还有一个示例,把类库下载下来,解压,放到Eclipse的Plugin目录下,然后在我们的项目中添加依赖项,就可以看到我们需要使用的类了,如下图:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

我们需要对OpenGL编程的一些基本概念有点了解,在OpenGL中,3D场景不是直接绘制到操作系统的窗口上的,而是有一个称为着色描述表(Rendering Context)的东西,我们这里简称它为context,OpenGL的绘图命令都是在当前context上进行绘制,然后再把它渲染到操作系统的设备描述表(Device Context)上,这里,我们可以简单的理解成把它渲染到窗口控件上(其实也可以渲染到全屏幕)。

在Windows中使用OpenGL编程比较麻烦,因为我们需要设置一个叫做象素格式的东西,大家只要看看下面的这段C代码,就知道我为什么说它麻烦了:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军static PIXELFORMATDESCRIPTOR pfd=     //pfd 告诉窗口我们所希望的东东
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
     {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军         sizeof(PIXELFORMATDESCRIPTOR),   //上诉格式描述符的大小
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         1,                  // 版本号
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         PFD_DRAW_TO_WINDOW |        // 格式必须支持窗口
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         PFD_SUPPORT_OPENGL |        // 格式必须支持OpenGL
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         PFD_DOUBLEBUFFER,          // 必须支持双缓冲
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         PFD_TYPE_RGBA,           // 申请 RGBA 格式
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         bits,                // 选定色彩深度
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0, 0, 0, 0, 0, 0,          // 忽略的色彩位
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0,                 // 无Alpha缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0,                 // 忽略Shift Bit
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0,                 // 无聚集缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0, 0, 0, 0,             // 忽略聚集位
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         16,                 // 16位 Z-缓存 (深度缓存) 
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0,                 // 无模板缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0,                 // 无辅助缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         PFD_MAIN_PLANE,           // 主绘图层
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0,                 // 保留
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
         0, 0, 0               // 忽略层遮罩
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
     }
;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))   // Windows 找到相应的象素格式了吗?
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
    {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        KillGLWindow();               // 重置显示区
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        MessageBox(NULL,"Can't Find A Suitable PixelFormat.",
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            "ERROR",MB_OK|MB_ICONEXCLAMATION);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        return FALSE;                // 返回 FALSE
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军if(!SetPixelFormat(hDC,PixelFormat,&pfd))      // 能够设置象素格式么?
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
    {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        KillGLWindow();               // 重置显示区
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        return FALSE;                // 返回 FALSE
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军if (!(hRC=wglCreateContext(hDC)))         // 能否取得着色描述表?
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
    {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        KillGLWindow();              // 重置显示区
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        MessageBox(NULL,"Can't Create A GL Rendering Context.",
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军           "ERROR",MB_OK|MB_ICONEXCLAMATION);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        return FALSE;               // 返回 FALSE
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

在SWT中,我们开发OpenGL应用就要简单得多,这全部要归功于org.eclipse.swt.opengl包下面的GLCanvas类和GLData类,使用GLCanvas类可以直接创建一个用于OpenGL渲染的控件,至于设置象素格式这样复杂的问题,它已经帮我们解决了,不信你看GLCanvas类的构造函数的实现。

GLCanvas类中的几个方法代表了我一开始提到的OpenGL的几个基本概念,setCurrent()方法就是为了把该控件的context设置为OpenGL的当前着色描述表,然后使用GL和GLU类中的方法在当前context上进行绘图,绘制完图形以后,再使用GLCanvas类的swapBuffers()方法交换缓冲区,也就是把context中的3D场景渲染到控件上。

写到这里,大家肯定认为一切问题都应该迎刃而解了,然而,我却碰到了另外一个困难,这个困难就是SWT的OpenGL表现怪异,怎么个怪异呢?请看下面视图类的代码:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军public void createPartControl(Composite parent) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        // TODO 自动生成方法存根
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        GLData data = new GLData();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.depthSize = 1;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.doubleBuffer = true;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        GLCanvas canvas = new GLCanvas(parent, SWT.NO_BACKGROUND, data);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        //设置该canvas的context为OpenGL的当前context
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        if(!canvas.isCurrent()){
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            canvas.setCurrent();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        //这里可以进行OpenGL绘图
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
//交换缓存,将图形渲染到控件上
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        canvas.swapBuffers();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

按道理,我们应该可以得到一个经典的3D的黑色场景,但是,我得到的却是这样的效果:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

相当的郁闷啊,就是这个问题困扰了我至少一个星期。我把官方网站上的示例看了有看,就是找不到问题的关键所在。直到最后,我用了另外一个线程,每100ms都调用canvas.swapBuffers()把场景渲染一遍问题才解决。由此可见,之所以回出现上面的问题,主要是因为我们渲染的场景很快会被操作系统的其他绘图操作所覆盖,只有不断的渲染我们才能看到连续的3D图形。

我是这样实现让3D场景连续渲染的:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军public void createPartControl(Composite parent) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        // TODO 自动生成方法存根
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        GLData data = new GLData();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.depthSize = 1;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.doubleBuffer = true;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        GLCanvas canvas = new GLCanvas(parent, SWT.NO_BACKGROUND, data);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        //将绘图代码转移到定时器中
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        Refresher rf = new Refresher(canvas);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        rf.run();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

Refresher类的代码如下:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军class Refresher implements Runnable {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public static final int DELAY = 100;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    private GLCanvas canvas;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public Refresher(GLCanvas canvas) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        this.canvas = canvas;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public void run() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        if (this.canvas != null && !this.canvas.isDisposed()) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            if(!canvas.isCurrent()){
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                canvas.setCurrent();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            //这里添加OpenGL绘图代码
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
            canvas.swapBuffers();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            this.canvas.getDisplay().timerExec(DELAY, this);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军  
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军}

问题解决,得到的效果图如下:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

OK,下面的任务就是完完全全的使用OpenGL的绘图功能了,不管你的OpenGL教材使用的是什么操作系统什么编程语言,你都能很简单的把它的概念拿到这里来使用。

使用OpenGL的第一件事,就是要设置投影矩阵、透视图和观察者矩阵,如果你不知道为什么要这么做,请查看OpenGL的基础教材,在这里,照搬就行了。为了让我们的控件在每次改变大小的时候都能够做这些设置,我们使用事件监听器,如下:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军public void createPartControl(Composite parent) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        // TODO 自动生成方法存根
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        GLData data = new GLData();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.depthSize = 1;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.doubleBuffer = true;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        canvas = new GLCanvas(parent, SWT.NO_BACKGROUND, data);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        canvas.addControlListener(new ControlAdapter() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            public void controlResized(ControlEvent e) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                Rectangle rect = canvas.getClientArea();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glViewport(0, 0, rect.width, rect.height);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //选择投影矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glMatrixMode(GL.GL_PROJECTION);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //重置投影矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //设置窗口比例和透视图
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GLU.gluPerspective(45.0f, (float) rect.width / (float) rect.height, 0.1f, 100.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //选择模型观察矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glMatrixMode(GL.GL_MODELVIEW);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //重置模型观察矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //黑色背景
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //设置深度缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glClearDepth(1.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //启动深度测试
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glEnable(GL.GL_DEPTH_TEST);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //选择深度测试类型
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glDepthFunc(GL.GL_LESS);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //启用阴影平滑
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glShadeModel(GL.GL_SMOOTH);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //精细修正透视图
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //清除屏幕和深度缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //重置当前的模型观察矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }
);  
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        canvas.addDisposeListener(new DisposeListener() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            public void widgetDisposed(DisposeEvent e) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                dispose();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }
);


调用glLoadIdentity()之后,实际上将当前点移到了屏幕中心,X坐标轴从左至右,Y坐标轴从下至上,Z坐标轴从里至外。OpenGL屏幕中心的坐标值是XY轴上的0.0f点。中心左面的坐标值是负值,右面是正值。移向屏幕顶端是正值,移向屏幕底端是负值。移入屏幕深处是负值,移出屏幕则是正值。

glTranslatef(x, y, z)是将当前点沿着XYZ轴移动,当我们绘图的时候,不是相对于屏幕中间,而是相对于当前点。

glBegin(GL.GL_TRIANGLES)的意思是开始绘制三角形,glEnd()告诉OpenGL三角形已经创建好了。通常当我们需要画3个顶点时,可以使用GL_TRIANGLES。在绝大多数的显卡上,绘制三角形是相当快速的。如果要画四个顶点,使用GL_QUADS的话会更方便。但据我所知,绝大多数的显卡都使用三角形来为对象着色。最后,如果想要画更多的顶点时,可以使用GL_POLYGON

glVertex(x,y,z)用来设置顶点,如果绘制三角形,这些顶点需要三个一组,如果绘制四边形,则是四个为一组。如果我们要为顶点着色,就需要glColor3f(r,g,b)方法,记住,每次设置以后,这个颜色就是当前颜色,直到再次调用该方法重新设置为止。

最后需要介绍的是glRotatef(Angle,Xvector,Yvector,Zvector)方法,该方法负责让对象围绕指定的轴旋转,Angle参数指转动的角度,注意是浮点数哦。

下面是我的视图类的全部代码,我把3D绘图的任务全部放到了另外一个线程中,并且定义了一个递归方法public void drawPyramid(float x, float y, float z, int n)用来绘制三菱锥矩阵。如下:
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军package cn.blogjava.youxia.views;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.opengl.GL;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.opengl.GLU;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.events.ControlAdapter;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.events.ControlEvent;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.events.DisposeEvent;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.events.DisposeListener;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.graphics.Rectangle;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.opengl.GLData;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.widgets.Composite;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.ui.part.ViewPart;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.opengl.GLCanvas;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军import org.eclipse.swt.SWT;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军public class OpenGLView extends ViewPart {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    GLCanvas canvas;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    @Override
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public void createPartControl(Composite parent) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        // TODO 自动生成方法存根
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
        GLData data = new GLData();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.depthSize = 1;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        data.doubleBuffer = true;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        canvas = new GLCanvas(parent, SWT.NO_BACKGROUND, data);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        canvas.addControlListener(new ControlAdapter() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            public void controlResized(ControlEvent e) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                Rectangle rect = canvas.getClientArea();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glViewport(0, 0, rect.width, rect.height);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //选择投影矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glMatrixMode(GL.GL_PROJECTION);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //重置投影矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //设置窗口比例和透视图
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GLU.gluPerspective(45.0f, (float) rect.width / (float) rect.height, 0.1f, 100.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //选择模型观察矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glMatrixMode(GL.GL_MODELVIEW);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //重置模型观察矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //黑色背景
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //设置深度缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glClearDepth(1.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //启动深度测试
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glEnable(GL.GL_DEPTH_TEST);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //选择深度测试类型
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glDepthFunc(GL.GL_LESS);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //启用阴影平滑
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glShadeModel(GL.GL_SMOOTH);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //精细修正透视图
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //清除屏幕和深度缓存
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //重置当前的模型观察矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }
);  
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        canvas.addDisposeListener(new DisposeListener() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            public void widgetDisposed(DisposeEvent e) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                dispose();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }
);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        /*
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
*/

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        Refresher rf = new Refresher(canvas);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        rf.run();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    @Override
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public void setFocus() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        // TODO 自动生成方法存根
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军}

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军class Refresher implements Runnable {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public static final int DELAY = 100;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    private GLCanvas canvas;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    private float rotate = 0.0f;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public Refresher(GLCanvas canvas) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        this.canvas = canvas;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    public void run() {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        if (this.canvas != null && !this.canvas.isDisposed()) {
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            if(!canvas.isCurrent()){
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                canvas.setCurrent();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            //这里添加OpenGL绘图代码
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
            GL.glLoadIdentity();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            GL.glTranslatef(0, 4.5f, -11);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            //围绕y轴转起来
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
            rotate += 0.5;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            GL.glRotatef(rotate, 0, 1.0f, 0);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            //调用递归函数,绘制三菱锥矩阵
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
            drawPyramid(0,0,0,4);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            canvas.swapBuffers();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            this.canvas.getDisplay().timerExec(DELAY, this);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军    }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        public void drawPyramid(float x, float y, float z, int n){
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            if(n == 0)return;
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            //画一个三菱锥
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
            GL.glBegin(GL.GL_TRIANGLES);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //画背面
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glColor3f(1.0f,0.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x, y, z);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,1.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f(x+1.0f,y-1.63f,z-0.57f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,0.0f,1.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x-1.0f,y-1.63f,z-0.57f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //画底面
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glColor3f(1.0f,0.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x,y-1.63f,z+1.15f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,1.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f(x-1.0f,y-1.63f,z-0.57f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,0.0f,1.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x+1.0f,y-1.63f,z-0.57f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //画左侧面
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glColor3f(1.0f,0.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x,y,z);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,1.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f(x-1.0f,y-1.63f,z-0.57f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,0.0f,1.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x,y-1.63f,z+1.15f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                //画右侧面
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
                GL.glColor3f(1.0f,0.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x,y,z);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,1.0f,0.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f(x,y-1.63f,z+1.15f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glColor3f(0.0f,0.0f,1.0f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军                GL.glVertex3f( x+1.0f,y-1.63f,z-0.57f);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            GL.glEnd();
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            //递归调用,画多个三菱锥
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军
            drawPyramid(x,y-1.63f,z+1.15f,n-1);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            drawPyramid(x-1.0f,y-1.63f,z-0.57f,n-1);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军            drawPyramid(x+1.0f,y-1.63f,z-0.57f,n-1);
使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军        }

使用Eclipse RCP进行桌面程序开发(六):向OpenGL进军}