我们使用三角形和四边形来创建3D物体,在这一课里我们将把三角形变成三菱锥也就是金字塔的形状,将四边形变成立方体。在上一节课的内容上做一些扩展,我们开始生成真正的3D物体,而不是前面几节课中的三维空间中的二维物体,我们给三角形增加一个左侧面,一个右侧面,一个后侧面来生成一个金字塔。给正方体添加左右上下后五个面。在金字塔中我们使用平滑着色(Smooth coloring) ,而正方体我们使用单一着色(flat coloring)进行渲染只是立方体的各个平面使用不通的颜色而已。
下面我们查看实现代码
package demos.nehe.lesson05; /* * Lesson05.java * * Created on July 15, 2003, 11:30 AM */ import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLEventListener; import javax.media.opengl.glu.GLU; /** Port of the NeHe OpenGL Tutorial (Lesson 5) * to Java using the Jogl interface to OpenGL. Jogl can be obtained * at http://jogl.dev.java.net/ * * @author Kevin Duling ([email protected]) */ class Renderer implements GLEventListener { //设置立方体的旋转控制变量 private float rquad = 0.0f; //设置三菱椎的旋转控制变量 private float rtri = 0.0f; //OpenGL绘制工具包类 private GLU glu = new GLU(); /** Called by the drawable to initiate OpenGL rendering by the client. * After all GLEventListeners have been notified of a display event, the * drawable will swap its buffers if necessary. * @param glDrawable The GLAutoDrawable object. */ public void display(GLAutoDrawable glDrawable) { //获取OpenGL操作对象 final GL2 gl = glDrawable.getGL().getGL2(); //清理屏幕和深度缓存 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); //重置模型观察矩阵 gl.glLoadIdentity(); //将绘制中心左移1.5个单位,向屏幕里移入6个单位 gl.glTranslatef(-1.5f, 0.0f, -6.0f); //设置旋转轴,以Y轴为旋转轴旋转rtri度 gl.glRotatef(rtri, 0.0f, 1.0f, 0.0f); /** * 下面的代码创建一个绕者其中心轴旋转的金字塔。 * 金字塔的上顶点高出原点一个单位,底面中心低于原点一个单位。 * 上顶点在底面的投影位于底面的中心. * 注意所有的面-三角形都是逆时针次序绘制的。 * 这点十分重要,在以后的课程中我会作出解释。 * 现在,您只需明白要么都逆时针,要么都顺时针, * 但永远不要将两种次序混在一起,除非您有足够的理由必须这么做。 * 下面我们开始绘制金字塔的各个面 */ gl.glBegin(GL2.GL_TRIANGLES); // Drawing Using Triangles /** * 开始绘制金字塔的的前侧面 */ //设置当前的颜色为红色,设置前侧面的上顶点 gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(0.0f, 1.0f, 0.0f); //设置当前的颜色为绿色,设置这个前侧面的左顶点 gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); //设置当前的颜色为蓝色,设置前侧面的右顶点 gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); /** * 绘制金字塔的右侧面 * 设置渲染颜色为红色,当前的点为右侧面的上顶点 */ gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(0.0f, 1.0f, 0.0f); //设置当前的颜色为蓝色,当前的点为右侧面的左顶点 gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); //设置当前的颜色为绿色,当前的点位右侧面右顶点 gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); /** * 绘制金字塔的背面 * 设置当前渲染颜色为红色,当前的点位背面的上顶点 */ gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(0.0f, 1.0f, 0.0f); //设置当前的颜色为绿色,当前的点为背面的左顶点 gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f); //设置当前的颜色为蓝色,当前的点为背面的右顶点 gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); /** * 绘制金字塔的左侧面 * 设置颜色为红色,设置左侧面的上顶点 */ gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(0.0f, 1.0f, 0.0f); //设置颜色为蓝色,设置左侧面的左顶点 gl.glColor3f(0.0f, 0.0f, 1.0f); gl.glVertex3f(-1.0f, -1.0f, -1.0f); //设置颜色为绿色,设置左侧面的右顶点 gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); //完成金字塔的绘制 gl.glEnd(); //重置模型观察矩阵 gl.glLoadIdentity(); //将绘制中心从当前的的位置右移1.5个单位,移入屏幕6个单位 gl.glTranslatef(1.5f, 0.0f, -6.0f); //设置立方体围绕轴坐标为(1.0 , 1.0 , 1.0)以rquad的角度旋转 gl.glRotatef(rquad, 1.0f, 1.0f, 1.0f); //开始绘制立方体 gl.glBegin(GL2.GL_QUADS); //开始绘制立方体体的各个面 //绘制立方体的顶面,设置颜色为绿色 gl.glColor3f(0.0f, 1.0f, 0.0f); gl.glVertex3f(1.0f, 1.0f, -1.0f); // 四边形的右上顶点 (顶面) gl.glVertex3f(-1.0f, 1.0f, -1.0f);// 四边形的左上顶点 (顶面) gl.glVertex3f(-1.0f, 1.0f, 1.0f);// 四边形的左下顶点 (顶面) gl.glVertex3f(1.0f, 1.0f, 1.0f);// 四边形的右下顶点 (顶面) //绘制立方体的底面,设置颜色为橙色 gl.glColor3f(1.0f, 0.5f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f);// 四边形的右上顶点(底面) gl.glVertex3f(-1.0f, -1.0f, 1.0f);// 四边形的左上顶点(底面) gl.glVertex3f(-1.0f, -1.0f, -1.0f);// 四边形的左下顶点(底面) gl.glVertex3f(1.0f, -1.0f, -1.0f);// 四边形的右下顶点(底面) //绘制立方体的前面, 颜色改成红色 gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f);// 四边形的右上顶点(前面) gl.glVertex3f(-1.0f, 1.0f, 1.0f);// 四边形的左上顶点(前面) gl.glVertex3f(-1.0f, -1.0f, 1.0f);// 四边形的左下顶点(前面) gl.glVertex3f(1.0f, -1.0f, 1.0f);// 四边形的右下顶点(前面) //绘制立方体的后面,设置颜色为黄色 gl.glColor3f(1.0f, 1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, -1.0f);// 四边形的右上顶点(后面) gl.glVertex3f(-1.0f, -1.0f, -1.0f);// 四边形的左上顶点(后面) gl.glVertex3f(-1.0f, 1.0f, -1.0f);// 四边形的左下顶点(后面) gl.glVertex3f(1.0f, 1.0f, -1.0f);// 四边形的右下顶点(后面) gl.glColor3f(0.0f, 0.0f, 1.0f); // 颜色改成蓝色 gl.glVertex3f(-1.0f, 1.0f, 1.0f);// 四边形的右上顶点(左面) gl.glVertex3f(-1.0f, 1.0f, -1.0f);// 四边形的左上顶点(左面) gl.glVertex3f(-1.0f, -1.0f, -1.0f);// 四边形的左下顶点(左面) gl.glVertex3f(-1.0f, -1.0f, 1.0f);// 四边形的右下顶点(左面) gl.glColor3f(1.0f, 0.0f, 1.0f); // 颜色改成紫罗兰色 gl.glVertex3f(1.0f, 1.0f, -1.0f);// 四边形的右上顶点(右面) gl.glVertex3f(1.0f, 1.0f, 1.0f);// 四边形的左上顶点(右面) gl.glVertex3f(1.0f, -1.0f, 1.0f);// 四边形的左下顶点(右面) gl.glVertex3f(1.0f, -1.0f, -1.0f);// 四边形的右下顶点(右面) gl.glEnd(); // Done Drawing The Quad gl.glFlush(); rtri += 0.2f;// 增加金字塔的旋转变量 rquad += 0.15f;// 增加立方体的旋转变量 } /** Called when the display mode has been changed. <B>!! CURRENTLY UNIMPLEMENTED IN JOGL !!</B> * @param glDrawable The GLAutoDrawable object. * @param modeChanged Indicates if the video mode has changed. * @param deviceChanged Indicates if the video device has changed. */ public void displayChanged(GLAutoDrawable glDrawable, boolean modeChanged, boolean deviceChanged) { } /** Called by the drawable immediately after the OpenGL context is * initialized for the first time. Can be used to perform one-time OpenGL * initialization such as setup of lights and display lists. * @param glDrawable The GLAutoDrawable object. */ public void init(GLAutoDrawable glDrawable) { //获取GL对象 GL2 gl = glDrawable.getGL().getGL2(); //启用阴影平滑 gl.glShadeModel(GL2.GL_SMOOTH); //设置背景颜色为黑色 gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //设置深度缓存 gl.glClearDepth(1.0f); //启用深度测试 gl.glEnable(GL.GL_DEPTH_TEST); //所作的深度测试的类型 gl.glDepthFunc(GL.GL_LEQUAL); // 告诉系统对透视进行修正 gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); // Really Nice Perspective Calculations } /** Called by the drawable during the first repaint after the component has * been resized. The client can update the viewport and view volume of the * window appropriately, for example by a call to * GL.glViewport(int, int, int, int); note that for convenience the component * has already called GL.glViewport(int, int, int, int)(x, y, width, height) * when this method is called, so the client may not have to do anything in * this method. * @param glDrawable The GLAutoDrawable object. * @param x The X Coordinate of the viewport rectangle. * @param y The Y coordinate of the viewport rectanble. * @param width The new width of the window. * @param height The new height of the window. */ public void reshape(GLAutoDrawable glDrawable, int x, int y, int width, int height) { final GLU glu = new GLU(); final GL2 gl = glDrawable.getGL().getGL2(); //防止被零除 if (height <= 0) // avoid a divide by zero error! height = 1; final float h = (float) width / (float) height; //设置视窗的大小 gl.glViewport(0, 0, width, height); //选择投影矩阵 ,投影矩阵负责为我们的场景增加透视。 gl.glMatrixMode(GL2.GL_PROJECTION); //重置投影矩阵; gl.glLoadIdentity(); //设置视口的大小 glu.gluPerspective(45.0f, h, 1.0, 20.0); //启用模型观察矩阵;模型观察矩阵中存放了我们的物体讯息。 gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); } public void dispose(GLAutoDrawable arg0) { throw new UnsupportedOperationException("Not supported yet."); } }
程序运行的主类