JOGLv4中文版

JOGLv4中文版
JOGLv4中文版

两个JOGL的编程框架

本章介绍,为3D的Java包装JOGL(https://https://www.360docs.net/doc/2115925934.html,)(2D)图形库的OpenGL (https://www.360docs.net/doc/2115925934.html,)。我将实现一个简单的例如,一个旋转的多种颜色的立方体,使用两种编程框架,一个用人回调,其他利用积极的渲染。一种方式,我将比较他们是看到他们如何处理多维数据集的动画不同的帧速率。

下一章将探讨在更详细的JOGL的功能,当我开发应用程序包含许多你已经看到了在Java 3D编码的元素,包括格子地板,一个旋转的纹理领域,天空盒,一个广告牌,重叠,并键盘导航。第三章探讨如何负载的OBJ模型,实施碰撞检测,并播放3D音效。

1。JOGL的是什么?

JOGL的游戏技术发起的开源技术之一早在2003年在Sun Microsystems的集团(其他JInput和JOAL,我章11-14覆盖?)。JOGL提供了OpenGL的API的完全访问2.0规范,以及供应商扩展,并可以结合AWT和Swing组件。它支持两个主要的着色语言,GLSL和Nvidia的CG。JOGL的有相同的焦点和OpenGL,2D和3D渲染。它不包括支持游戏元素,如声音或输入设备,这是很好的处理与JOAL 和JInput。

JOGL目前流行的OpenGL GLU和GLUT库的大多数功能。GLU(OpenGL实用库)支持包括渲染球体,圆柱体和磁盘,摄像定位,镶嵌,纹理MIP贴图。JOGL的版本GLUT(OpenGL实用工具包),不包括其窗口功能,这是由Java处理,但确实提供了几何图元(无论是在固体和线框模式)。JOGL的实用工具类包括基于帧的动画,纹理加载,文件IO,和截图功能。

JOGL的已演变成的JSR - 231规范的参考实现具有约束力的OpenGL的Java (https://www.360docs.net/doc/2115925934.html,/en/jsr/detail?id=231)。JOGL 1.1.1JSR - 231取代2005年10月,第一个JSR - 231的发布版本,1.0.0,2006年9月出来。在下面的章节中,我将使用该版本,但继续使用的名称JOGL的。

成为JSR - 231兼容,许多JOGL的类,方法,并包有被修改,主要是在未成年人的方式。这意味着旧的例子需要一些调整,以让他们编译和运行。有关修改的详情,可发现JOGL的论坛线程https://www.360docs.net/doc/2115925934.html,/forums/index.php?topic=11189.0。

新GLDrawable和GLContext类是本章最重要的,因为它们允许直接访问OpenGL的绘图表面和状态信息。

这些新类支持一个新的编码风格,被称为积极的渲染,我将使用第二个编程框架的基础上。

访问OpenGL API是通过Java本地接口(JNI)调用,导致一个非常API的C函数和JOGL的Java 方法之间的直接映射。作为一个因此,它非常容易转化为JOGL的大多数OpenGL的例子。“缺点是基于OpenGL的编程风格是围绕一个全球性的影响图形状态,这使得它很难组织成有意义的类Java代码和对象。JOGL没有提供OpenGL API的类结构,但绝大多数其方法大多数是在非常大的GL和GLU类。

OpenGL是一个庞大,复杂和强大的,整本书的API,其专用解释。在接下来的三个章节,我将只解释我需要的OpenGL特性我的例子。一个全面的知识,你需要其他的来源,我点你对一些在本章结束。

1.1。安装JOGL

JOGL的工作与J2SE 1.4.2或更高版本,我用我的测试的Java 1.6.0 Beta 2中,并下载的JOGL的JSR - 231 1.0.0释放https://https://www.360docs.net/doc/2115925934.html,版本。我选择的Windows版本,从9月14日,JOGL - 1_0_0 window i586.zip其中包含一个lib \子目录控股jogl.jar和三个DLL,jogl.dll,jogl_awt.dll,jogl_cg.dll。

建议jogl.jar和JOGL的用户指南(这是ZIP文件的一部分)三个DLL应安装在自己的目录,而不是内部的JRE目录。因此,我提取的lib \目录下,更名为它JOGL \和存储它在我的测试机的D:驱动器(即D:\ JOGL \)。

在编译和运行时提供合适的JAR和DLL可以利用在命令行的classpath的java.library.path参数。例如,当我编译JOGL的演示PrintExt.java,I型:

javac -classpath "d:\jogl\jogl.jar;." PrintExt.java

其执行要求:

java -cp "d:\jogl\jogl.jar;."

-Djava.library.path="d:\jogl"

-Dsun.java2d.noddraw=true PrintExt

java.exe命令是单行线,我已经重新格式化,以便更容易阅读。

“sun.java2d.noddraw”属性禁用的Java 2D的DirectDraw的使用视窗。这之间的DirectDraw和OpenGL,避免任何讨厌的相互作用可能会导致应用程序崩溃,表现不佳,和闪烁。该物业只如果你在Windows平台上工作。

另一个有用的命令行选项是“Dsun.java2d.opengl =真正的”开关Java2D的OpenGL管线。这条管道提供硬件加速许多Java 2D渲染的操作(如文本,图像,线条,填充,复杂的转换,复合材料,剪辑)。这是至关重要JOGL的GLJPanel类是作为聘用时绘图表面(如下所述)。

如果你不喜欢冗长的命令行参数,那么另一种方法是修改CLASSPATH环境变量PATH(Windows)中,

LD_LIBRARY_PATH(Solaris和Linux),或DYLD_LIBRARY_PATH键(Mac OSX)更多细节,可以发现在JOGL的用户指南。

而懒,我打包compileGL.bat在编译命令行:

@echo off

echo Compiling %1 with JOGL...

javac -classpath “d:\jogl\jogl.jar;.” %1

echo Finished.

到调用的java.exe是runGL.bat:

@echo off

echo Executing %1 with JOGL...

java -cp "d:\jogl\jogl.jar;."

-Djava.library.path="d:\jogl"

-Dsun.java2d.noddraw=true %1 %2

echo Finished.

批处理变量(1%和2%),允许最多两个参数被传递给runGL.bat。

2。回调框架

JOGL的两个主要的GUI类GLCanvas和GLJPanel,实施GLAutoDrawable接口,使他们成为“绘画面的”利用OpenGL命令。

GLCanvas是采用了AWT的Canvas类以类似的方式。这是一个重量级的与Swing相结合时,组件,因此必须小心。然而,执行OpenGL的操作速度非常快,由于硬件加速。撤消修改GLJPanel是一个轻量级的部件无缝工作与Swing。在过去,它的获得一个慢,因为它复制到OpenGL的帧缓冲的声誉BufferedImage的前显示它。然而,它的速度显着提高Java SE 6中,我将在稍后一些时间测试显示。

GLJPanel超过GLCanvas的一个关键优势在于,它允许三维图形(礼貌OpenGL的)和Swing中的2D元素在新的,令人振奋的方式相结合。

2.1。使用GLCanvas

一个GLCanvas对象是一个GLEventListener监听器,这是为了响应配对在画布上的变化,并绘制请求。

帆布是第一次创建时,GLEventListener的init()方法被调用;方法可用于初始化OpenGL状态。

每当画布大小,包括它的第一个绘制,GLEventListenerreshape()执行。它可以覆盖初始化OpenGL 的视口和

投影矩阵(即如何看待3D场景)。reshape()也援引画布上移动相对于它的父组件。

每当在画布的display()方法被调用时,GLEventListener的display()方法是执行的。应放置在渲染的3D场景的代码里的该方法。

除了canvas和listener,大多数游戏需要一个触发机制在画布上的定期更新。此功能可通过JOGLFPSAnimator实用工具类,它可以安排调用canvas的display()方法由用户设置的频率。所有这些元素如图1所示。

图1。与GLCanvas的回调应用。

GLCanvas可以直接放在里面的JFrame的,但在包装的JPanel,JFrame中可以包含其他(轻量级)的GUI组件以及。

GLEventListener回调包括displayChanged(),它应该被称为当显示模式或设备发生了变化。可能发生这种情况时,显示器的显示设置被更改或应用程序时拖在另一台监视器多显示器配置。displayChanged()目前尚未在JOGL的实施。

从图1中缺少的是如何的用户交互,如鼠标和键盘活动,在画布上的影响。基本技术是建立在鼠标和键盘监听器通常的Java方式,并让他们改变中GLEventListener的全局变量。当其display()方法被调用时,它可以检查这些全局,以决定如何采取行动。下章有一个扩展的例子,采用这种方法。

与JOGL的编码错误的一个常见原因是有一个鼠标或键盘监听器直接调用OpenGL函数,这通常会导致崩溃的应用程序。“OpenGL的状态只能通过GLAutoDrawable接口安全地操纵这是暴露在GLEventListener的回调方法。许多厂商的OpenGL司机都不是可靠的,当面对多线程,所以不喜欢从监听器线程访问。

2.2。使用GLJPanel

由于GLJPanel是一个轻量级的Swing组件,它可以直接添加到封闭的JFrame,如图2所示。

图2。与GLJPanel回调应用。

回调框架的其余部分是相同的图1:FPSAnimator驱动器动画,GLEventListener捕捉到绘图区域的变化。这意味着它只是一个改变几行代码之间切换GLCanvas问题GLJPanel,我会在旋转立方体的例子表明,在下面的章节。

图2常用的一个变种是里面放置一个JPanel GLJPanel呈现一个“背景”的形象,作为一个渐变填充或图片。对于背景可见,GLJPanel自己的背景必须是透明的。我将解释如何这样旋转的立方体应用。

3。旋转与回调GLCanvas立方GLCanvas和回调技术,在最后一节所述是用在CubeGL应用旋转的X,Y,Z -轴周围的彩色立方体。图3显示了在行动中的多维数据集的截图。

图3。CubeGL与GLCanvas和回调。

该窗口由一个中心举行的GLCanvas的JPanel,一个TextField在底部报告当前的X,Y,Z轴旋转的立方体。

应用程序的类图在图4中,只有公共的方法。

图4。CubeGL类图GLCanvas和回调。

CubeGL是顶层的JFrame创建GLCanvas和FPSAnimator对象。CubeGLListener是在画布上的监听器,一个子类GLEventListener实现回调的init(),reshape(),并display()。(displayChanged

()是空的因为JOGL的不支持。)CubeGL是一个GLCanvas回调如图1所示的编码风格的例子。

3.1。大厦顶层窗口

CubeGL的构造函数生成GUI,并设置为应对一个窗口监听器窗口关闭事件。

/ / globals

private FPSAnimator animator;

private JTextField rotsTF; / /显示的立方体旋转

public CubeGL(int fps)

{

super("CubeGL (Callback)");

Container c = getContentPane();

c.setLayout( new BorderLayout() );

c.add(makeRenderPanel(fps), BorderLayout.CENTER);

rotsTF = new JTextField("Rotations: ");

rotsTF.setEditable(false);

c.add(rotsTF, BorderLayout.SOUTH);

addWindowListener( new WindowAdapter() {

public void windowClosing(WindowEvent e)

{ new Thread( new Runnable() {

public void run() {

animator.stop();

System.exit(0);

}

}).start();

} // end of windowClosing()

});

pack();

setVisible(true);

animator.start();

} // end of CubeGL()

来自命令行或默认的帧/秒的输入参数(fps)的值为80。其目的是更新在指定的速度旋转的立方体。

windowClosing()终止FPSAnimator对象(动画),并使得应用程序退出。该代码是在其自己的线程,不是一个开展相关的窗口监听器,以确保在动画停止之前System.exit()的调用。

3.2。连接画布

GLCanvas是嵌入一个makeRenderPanel()的JPanel,并连接到其动画和监听:

/ / globals

private static final int PWIDTH = 512; / /初始面板的大小

private static final int PHEIGHT = 512;

private CubeGLListener listener;

private JPanel makeRenderPanel(int fps)

{

JPanel renderPane = new JPanel();

renderPane.setLayout( new BorderLayout() );

renderPane.setOpaque(false);

renderPane.setPreferredSize( new Dimension(PWIDTH, PHEIGHT));

GLCanvas canvas = new GLCanvas(); // the canvas

listener = new CubeGLListener(this, fps); // the listener

canvas.addGLEventListener(listener);

animator = new FPSAnimator(canvas, fps, true);

// the animator uses fixed rate scheduling

renderPane.add(canvas, BorderLayout.CENTER);

return renderPane;

} // end of makeRenderPanel()

画布“封闭的Jpanel给出一个初始大小(512 512像素),但窗口的大小可以调整后,影响了画布。

FPSAnimator构造函数需要一个参考的GLAutoDrawable实例(即在画布上)。它的显示()方法将被调用的fps设置频率参数。FPSAnimator的第三个参数设置为true表明,固定利率将用于调度。每一个任务是预定的计划执行的相对初始任务的时间。如果一个任务被延迟,以任何理由(如垃圾回收),两个或两个以上的任务将出现在连续快速赶上。

3.3。建立监听器

旋转的彩色立方体内的OpenGL函数调用实现GLEventListener的init()回调方法,重塑(),并显示()。

如何以及应用程序的监听器还包括统计数据收集代码报告符合要求的帧频。

CubeGLListener构造函数创建的各种统计数据的数据结构。然后,它等待要显示的画布上,这将触发调用的init()。

3.3.1。初始化OpenGL的OpenGL的初始化在init()的代码通常包括Z -(深度)的设置缓冲区,灯光,纹理加载,并显示列表建设创造。这个例子不使用灯光或纹理。

// globals

private static final float INCR_MAX = 10.0f; // rotation increments

private GLU glu;

private int cubeDList; // display list for displaying the cube

// rotation variables

private float rotX, rotY, rotZ; // total rotations in x,y,z axes

private float incrX, incrY, incrZ; // increments for x,y,z rotations

public void init(GLAutoDrawable drawable)

{

GL gl = drawable.getGL(); // don't make this gl a global!

glu = new GLU(); /* this is okay as a global, but

only use it in callbacks */

// gl.setSwapInterval(0);

// switch off vertical synchronization, for extra speed (maybe)

// initialize the rotation variables

rotX = 0; rotY = 0; rotZ = 0;

Random random = new Random();

incrX = random.nextFloat()*INCR_MAX; // 0 - INCR_MAX degrees

incrY = random.nextFloat()*INCR_MAX;

incrZ = random.nextFloat()*INCR_MAX;

gl.glClearColor(0.17f, 0.65f, 0.92f, 0.0f); //sky color background

// z- (depth) buffer initialization for hidden surface removal

gl.glEnable(GL.GL_DEPTH_TEST);

// create a display list for drawing the cube

cubeDList = gl.glGenLists(1);

gl.glNewList(cubeDList, GL.GL_COMPILE);

drawColourCube(gl);

gl.glEndList();

} // end of init()

init()中GLAutoDrawable输入参数是程序员的切入点OpenGL的。GLAutoDrawable.getGL()的调用返回的GL对象,可以调用OpenGL的例程。

JOGL的文档建议对GL实例的全局,因为它可能诱使程序员调用OpenGL函数从鼠标和键盘听众,或其他线程。这几乎肯定会导致应用程序崩溃,因为OpenGL上下文(其内部状态)绑到GLEventListener。然而,它是好的,使GLU的实例,一个全球性的,但只应在使用回调方法。

GL.setSwapInterval()调用关闭垂直同步开关,这可能增加取决于显示卡及其设置的帧速率。它没有我的三个试验机可辨别的差异,所以这里注释掉。

多维数据集的当前x,Y,Z -旋转存储在全局ROTX,ROTY,和ROTZ。旋转增量是随机生成的,但有值之间0和10度之间。

OpenGL显示列表行为OpenGL渲染和国家的存储空间命令。的命令是“编译”成一个优化的形式,这使得他们更迅速地执行。显示列表的好处是,它可以被称为不用OpenGL的情况下不必重新编译命令多次,从而节省处理时间。cubeDList显示列表,在init()创建的组的命令绘制立方体。

3.3.2。绘制彩色立方

彩色立方体是由6个不同颜色的方块;不变渲染任务,这是一个不错的选择显示列表。

图5显示了立方体的顶点,这是框中心的定位,使血统,长度为2的两侧。每个顶点分配一个数字,它是用在下面的代码。

图5。彩色立方的编号的顶点。

顶点存储在一个全局数组:

private float[][] verts = {

{-1.0f,-1.0f, 1.0f}, // vertex 0

{-1.0f, 1.0f, 1.0f}, // 1

{ 1.0f, 1.0f, 1.0f}, // 2

{ 1.0f,-1.0f, 1.0f}, // 3

{-1.0f,-1.0f,-1.0f}, // 4

{-1.0f, 1.0f,-1.0f}, // 5

{ 1.0f, 1.0f,-1.0f}, // 6

{ 1.0f,-1.0f,-1.0f}, // 7

};

顶点的数组位置drawPolygon()用于绘制一个立方体的脸。drawPolygon()是从drawColourCube ()的6倍。

private void drawColourCube(GL gl)

// six-sided cube, with a different color on each face

{

gl.glColor3f(1.0f, 0.0f, 0.0f); // red

drawPolygon(gl, 0, 3, 2, 1); // front face

gl.glColor3f(0.0f, 1.0f, 0.0f); // green

drawPolygon(gl, 2, 3, 7, 6); // right

gl.glColor3f(0.0f, 0.0f, 1.0f); // blue

drawPolygon(gl, 3, 0, 4, 7); // bottom

gl.glColor3f(1.0f, 1.0f, 0.0f); // yellow

drawPolygon(gl, 1, 2, 6, 5); // top

gl.glColor3f(0.0f, 1.0f, 1.0f); // light blue

drawPolygon(gl, 4, 5, 6, 7); // back

gl.glColor3f(1.0f, 0.0f, 1.0f); // purple

drawPolygon(gl, 5, 4, 0, 1); // left

} // end of drawColourCube()

private void drawPolygon(GL gl, int vIdx0, int vIdx1,

int vIdx2, int vIdx3)

// the polygon vertices come from the verts[] array

{

gl.glBegin(GL.GL_POLYGON);

gl.glVertex3f(verts[vIdx0][0],verts[vIdx0][1], verts[vIdx0][2] );

gl.glVertex3f(verts[vIdx1][0],verts[vIdx1][1], verts[vIdx1][2] );

gl.glVertex3f(verts[vIdx2][0],verts[vIdx2][1], verts[vIdx2][2] );

gl.glVertex3f(verts[vIdx3][0],verts[vIdx3][1], verts[vIdx3][2] );

gl.glEnd();

} // end of drawPolygon()

GL.glBegin()和GL.glEnd()括号内的顶点定义的序列,并glBegin()的参数指定的顶点“集体造型。其它的模式包括GL.GL_POINTS(集合点)和GL.GL_LINES(线设置)。

3.3.3。重塑画布

reshape()被称为在画布上移动或调整大小时,其中包括它的第一个时屏幕上绘制。这使得重塑()的天然场所举行OpenGL命令设置视口和投影矩阵。

public void reshape(GLAutoDrawable drawable, int x, int y,

int width, int height)

{

GL gl = drawable.getGL();

if (height == 0)

height = 1; // to avoid division by 0 in aspect ratio below

gl.glViewport(x, y, width, height); // size of drawing area

gl.glMatrixMode(GL.GL_PROJECTION);

gl.glLoadIdentity();

glu.gluPerspective(45.0, (float)width/(float)height, 1, 100);

// FOV, aspect ratio, near & far clipping planes

gl.glMatrixMode(GL.GL_MODELVIEW);

gl.glLoadIdentity();

} // end of reshape()

reshape()'S(X,Y)输入参数指定的画布“,其封闭的相对位置容器。在这个例子中,他们总是(0,0)。

一个GL对象是新创建的GLAutoDrawable输入参数。

GL.glViewport()调用定义在3D绘图窗口(视口)的大小一个左下角(X,Y),宽度,和高度。

矩阵模式切换到投影(OpenGL的投影矩阵),所以从三维场景映射到2D屏幕可以指定。

GL.glLoadIdentity()复位矩阵,并GLU.gluPerspective()创建一个映射的角度影响(反映在一个现实世界的摄像头中发生的事情)。视野是相机的视角。

切换到模型视图矩阵模式的reshape()的结束,所以OpenGL的从那时起,可以利用模型视图矩阵。它定义了场景的坐标系统,用于定位时,或移动,3D物体。它的成立结束reshape()因为显示(),绘制现场,将被称为未来。

3.3.4。场景绘制

FPSAnimator“蜱”,它要求在画布上显示(),触发调用显示()CubeGLListener。它的display ()方法保存代码,更新和重绘现场。

// global

private static final double Z_DIST = 7.0; // for camera position

public void display(GLAutoDrawable drawable)

{

// update the rotations

rotX = (rotX + incrX) % 360.0f;

rotY = (rotY + incrY) % 360.0f;

rotZ = (rotZ + incrZ) % 360.0f;

top.setRots(rotX, rotY, rotZ); // report at top-level

GL gl = drawable.getGL();

// clear color and depth buffers

gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

gl.glLoadIdentity();

glu.gluLookAt(0,0,Z_DIST, 0,0,0, 0,1,0); // position camera

// apply rotations to the x,y,z axes

gl.glRotatef(rotX, 1.0f, 0.0f, 0.0f);

gl.glRotatef(rotY, 0.0f, 1.0f, 0.0f);

gl.glRotatef(rotZ, 0.0f, 0.0f, 1.0f);

gl.glCallList(cubeDList); //execute display list for drawing cube

// drawColourCube(gl);

reportStats();

} // end of display

多维数据集的X,Y,和Z旋转ROTX,ROTY,和ROTZ更新。新的价值观写在顶层JFrame的文本字段(见屏幕上的报告图3)。

新的旋转后已应用于世界坐标,绘制立方体是通过其显示列表。另外,显示()drawColourCube()直接调用。

3.4。FPS的精度测量

reportStats()被调用显示()。它打印出的平均帧速率值大约每二,如以下CubeGL执行所示。

>runGL CubeGL

Executing CubeGL with JOGL...

fps: 80

period: 12 ms

54.4

64.18

68.42

70.93

72.63

73.84

74.78

75.53

76.13

Finished.

>

平均计算从以前10的FPS值(或更少,如果10个数字没有被计算)。这种加权方法的折扣较早,缓慢的帧率的数据。

在上面的例子中,开始与80个请求的帧速率,这是CubeGL转换成一个毫秒级的时间使用整数除法期间:

int period = (int) 1000.0/fps; // in ms

这是后来改回一个一十二分之一千,这是83.333帧速率。这意味着优化运行的应用程序应报告平均帧速率约83新鲜粮食店。例子是慢慢接近,达到约30秒后83。

reportStats()的实现没有任何与JOGL的或OpenGL的,所以我将跳过它的解释。

表1显示了不同版本的Windows报告的平均新鲜粮食店,当要求新鲜粮食店,20,50,80和100。Windows XP中出现了两次,因为我跑了两个不同的机器上使用XP的测试。

Requested FPS 20 50 80 100

Windows 2000 20 50 79 80

Windows XP (1) 20 50 83 100

Windows XP (2) 20 50 81 99

表1。GLCanvas CubeGL平均新鲜粮食店FPSAnimator(固定利率调度)。

每个测试运行三次,负载较轻的机器上运行了几分钟。

平均帧速率是优秀的80 FPS,虽然平均隐藏了一个事实,它需要一个帧速率分钟左右,对平均上升。另外,JVM的垃圾收集可以减少几秒钟的FPS每次发生。Windows 2000机器是不是能达到100的FPS,由于其缓慢硬件。

FPSAnimator构造函数也可以指示调度使用固定期限而不是固定利率调度。这仅需要改变的布尔FPSAnimator makeRenderPanel构造函数()的参数:

// makeRenderPanel() in CubeGL

animator = new FPSAnimator(canvas, fps, false);

// the animator uses fixed period scheduling

再次运行时间测试相同的机器上,在相同的负载条件。结果如表2所示。

Requested FPS 20 50 80 100

Windows 2000 19 49 49 98

Windows XP (1) 16 32 63 62

Windows XP (2) 16 31 62 62

表2。GLCanvas CubeGL平均新鲜粮食店和FPSAnimator(固定期限调度)。

结果表明:在FPS的准确性差异很大,但为80 FPS的结果请求(在我的测试机器上的刷新率)是相当差。

固定期限FPSAnimator调度使用java.util.Timer.schedule()多次触发动作。不幸的是,定时器的频率漂移,因为额外的延迟推出由垃圾收集器,或长时间运行的游戏更新和渲染。

最好的结果是获得通过FPSAnimator的固定利率调度的,如表1显示。

4。旋转与回调GLJPanel立方GLCanvas替代GLJPanel,一个轻量级部件。它的界面几乎是作为GLCanvas相同,所以两个组件可以很容易互换。这是GLCanvas和GLJPanel回调框架图1和图所示2。

GLJPanel已历来比GLCanvas慢得多,但它的速度在J2SE 5和Java SE 6显著提高。它的关键的优势超过GLCanvas它允许Java 2D和JOGL的以新的方式结合起来。

图6显示了一个这样的组合,一个由提供一个背景GLJPanel封闭的Jpanel。

图6。与GLJPanel和JPanel背景的回调应用。

回调框架是相同的,如图2;,只有背景的JPanel新。

图7显示了旋转立方体的例子,实现图6的方法。呈现在GLJPanel具有透明背景的3D零件。由Java 2D绘制渐变填充和“Hello World”文本在封闭的JPanelGLJPanel。

图7。旋转的立方体内GLJPanel和JPanel的背景。

从GLCanvas转换到GLJPanel所需的代码变化相当小,下面我将概述。

一个基本的命令行的变化是包括“Dsun.java2d.opengl = true”,以Java2D的OpenGL管线开关等增加的Java 2D的渲染速度。我的runGL.bat批处理文件就变成了:

echo Executing %1 with JOGL...

java -cp "d:\jogl\jogl.jar;."

-Djava.library.path="d:\jogl"

-Dsun.java2d.noddraw=true

-Dsun.java2d.opengl=true %1 %2

echo Finished.

4.1。建设展板

现在makeRenderPanel(中CubeGL)GLJPanel而不是创建一个对象GLCanvas的实例,并嵌入一个背景面板内。

private JPanel makeRenderPanel(int fps)

{

// JPanel renderPane = new JPanel();

JPanel renderPane = createBackPanel(); // for the GLJPanel

renderPane.setLayout( new BorderLayout() );

renderPane.setOpaque(false);

renderPane.setPreferredSize( new Dimension(PWIDTH, PHEIGHT));

// GLCanvas canvas = new GLCanvas();

// create the GLJPanel

GLCapabilities caps = new GLCapabilities();

caps.setAlphaBits(8);

GLJPanel canvas = new GLJPanel(caps);

canvas.setOpaque(false);

listener = new CubeGLListener(this, fps);

canvas.addGLEventListener(listener);

animator = new FPSAnimator(canvas, fps, true);

renderPane.add(canvas, BorderLayout.CENTER);

return renderPane;

} // end of makeRenderPanel()

创建GLCanvas对象和它的JPanel的旧代码已出来。

一个透明GLJPanel需要一个非零的α深度,设置使用一个GLCapabilities对象,并调用GLJPanel.setOpaque()。

4.2。背景面板

作为背景的JPanel绘制一个渐变填充和文本。

// global

private Font font;

private JPanel createBackPanel()

{

font = new Font("SansSerif", Font.BOLD, 48);

JPanel p = new JPanel() {

public void paintComponent(Graphics g)

{

Graphics2D g2d = (Graphics2D) g;

int width = getWidth();

int height = getHeight();

g2d.setPaint( new GradientPaint(0, 0, Color.YELLOW,

width, height, Color.BLUE));

g2d.fillRect(0, 0, width, height);

g2d.setPaint(Color.BLACK);

g2d.setFont(font);

g2d.drawString("Hello World", width/4, height/4);

} // end of paintComponent()

};

return p;

} // end of createBackPanel()

填充和文本改变位置时调整应用程序,因为他们利用目前面板的宽度和高度值。

4.3。3D背景透明

绘制成的GLJPanel OpenGL的背景必须是透明的(或至少半透明),所以背景的JPanel的渐变填充和文本将是可见的的。

旋转立方体的背景(浅蓝色)设立内部的init()里面CubeGLListener。它被更改为透明(或半透明)。

如图7所示的效果是:

gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // no OpenGL background

重要的论点是第四,设置为RGB颜色的Alpha值它前面。0.0f意味着完全透明,1.0f是不透明的。在0.0f价值例如意味着所有的背景颜色从背景面板。

一个半透明的效果(混合的背景面板和OpenGL的背景颜色)获得:

gl.glClearColor(0.17f, 0.65f, 0.92f, 0.3f);

// translucent OpenGL sky

0.3f的alpha值,使得OpenGL的天空透亮。

结果如图8所示。

图8。旋转的立方体内GLJPanel一个蓝色的JPanel背景。

效果是很难看到,但Jpanel的渐变填充的黄色部分已经转向绿色由于蓝色的OpenGL背景。

4.4。定时的GLJPanel

相同负载下使用相同的WinXP机器运行时间测试固定利率调度GLCanvas回调代码的条件。结果表3所示。

Requested FPS 20 50 80 100

Windows XP (1) 20 50 71 87

Windows XP (2) 20 50 75 90

表3。GLJPanel CubeGL平均新鲜粮食店和FPSAnimator(固定利率调度)。

结果都非常好,但在更高的帧速率比GLCanvas代码慢。

的速度大大低于未启用OpenGL管线时(即当“Dsun.java2d.opengl =真正的”没有命令行的一部分)。例如,应用程序只能管理大约25时80 FPS的要求的FPS。没有结果显示的背景,因为我陈旧的Windows 2000机器渲染没有工作,与老的ATI显卡;背景总是绘制黑色。

4.5。更多的视觉效果与GLJPanel

克里斯坎贝尔的博客条目,“易2D/3D混合在Swing”(https://www.360docs.net/doc/2115925934.html,/blog/campbell/archive/2006/10/easy_2d3d_mixin.html),是一个如何整合在2D和3D效果的例子很好的起点图形用户界面。

他PhotoCube应用程序包括一个CompositeGLJPanel类,它提供常见的类型2D/3D混合的方法(例如render2DBackground(),render3DScene(),和render2DForeground())。还有其他物品的指针和网上的代码。

5。回调摘要

回调技术(GLCanvas和GLJPanel)提供绝佳的帧速率,只要固定利率调度运用,硬件足够快。GLJPanel的成功运作是特别敏感的底层硬件和图形驱动程序。

JOGL的回调编码风格的一个重要优势是它的相似在GLUT回调机制。这使得许多OpenGL的例子移植到JOGL的最小的变化。

回调方法的一个缺点是应用程序生命周期的方式,(初始化,调整,基于帧的动画,和终止)除以跨多重,不相交的方法。此外,使用定时器(Animator类内)使得在运行时难以不同的应用程序的时序行为,并分开从应用程序的更新率(UPS)的帧速率(fps)。积极渲染在下一节中描述的框架解决这些问题。

6。活动渲染架构

积极渲染架构采用直接在JSR - 231的新功能访问绘图表面和上下文(OpenGL的内部状态)。这意味着

不再有任何需要使用GUI组件实现了GLAutoDrawable接口,如GLCanvas。应用程序可以采用子类

AWT的画布,用自己的渲染线程,由图9所示。

图9。主动渲染应用程序。

使用下面的伪代码,渲染线程可以概括:

make the context current for this thread;

initialize rendering;

while game isRunning {

update game state;

render scene;

put the scene onto the canvas;

sleep a while;

maybe do game updates without rendering them;

gather statistics;

}

discard the rendering context;

print the statistics;

exit;

棘手的方面是要记住此代码应操纵的OpenGL从渲染线程。必须处理任何鼠标键,或窗口事件有,而不是在不同的听众。

OpenGL的回调代码,位于GLEventListener的init(),重塑()和显示(),可以移动到积极的渲染线程没有太多的变化。“init()的代码进行的“初始化渲染”阶段,而重塑()中和内部处理“渲染场景”显示()。

积极的渲染方法的主要优点是,它允许程序员更直接地控制应用程序的执行。例如,它的直接添加代码暂停时,应用程序图标或更新无效(即最顶层的窗口时,它不是)。此外,进入到计时代码里面的动画循环允许分离帧速率处理应用程序更新。我将说明这些点,通过实施“旋转的立方体应用程序再次。

7。与Active渲染旋转立方体

积极渲染CubeGL看起来GLCanvas回调版本相同,如图10所示。

图10。与主动呈现CubeGL

应用已呈现活跃,礼貌的新功能:当窗口图标或停用,立方体停止转动,直至取消图标或窗口再次激活。

这个CubeGL版本的类图图11。

图11。与Active渲染CubeGL类图。

CubeGL创建图形用户界面,嵌入内螺纹的画布,CubeCanvasGLJPanel的。它还捕获窗口事件和组件的调整大小,并调用方法CubeCanvasGL来对付他们。

7.1。构建应用程序

CubeGL创建makeRenderPanel()内螺纹帆布:

// globals

private static final int PWIDTH = 512; // size of panel

private static final int PHEIGHT = 512;

private CubeCanvasGL canvas;

private JPanel makeRenderPanel(long period)

// construct the canvas inside a JPanel

{

JPanel renderPane = new JPanel();

renderPane.setLayout( new BorderLayout() );

renderPane.setOpaque(false);

renderPane.setPreferredSize( new Dimension(PWIDTH, PHEIGHT));

canvas = makeCanvas(period);

renderPane.add(canvas, BorderLayout.CENTER);

canvas.setFocusable(true);

canvas.requestFocus(); //canvas has focus, so receives key events

// detect window resizes, and reshape the canvas accordingly

renderPane.addComponentListener( new ComponentAdapter() {

public void componentResized(ComponentEvent evt)

{ Dimension d = evt.getComponent().getSize();

canvas.reshape(d.width, d.height);

}

});

return renderPane;

} // end of makeRenderPanel()

该小组有两个作用:它周围的画布,保护轻量级GUI部件从重量级的AWT画布,是一个方便的地方连接

组件的监听器,检测窗口大小调整。调整大小产生一个调用CubeCanvasGL.reshape(),它触发的重新计算和OpenGL的视的观点。

期间输入makeRenderPanel()来自上提供的帧速率命令行。它的计算公式为:

long period = (long) 1000.0/fps;

使画布

makeCanvas()获得最佳的图形配置画布。通过这信息螺纹的画布,CubeCanvasGL的一个实例。

private CubeCanvasGL makeCanvas(long period)

{

// get a configuration suitable for an AWT Canvas

GLCapabilities caps = new GLCapabilities();

AWTGraphicsDevice dev = new AWTGraphicsDevice(null);

AWTGraphicsConfiguration awtConfig =

(AWTGraphicsConfiguration)GLDrawableFactory.getFactory().

chooseGraphicsConfiguration(caps, null, dev);

GraphicsConfiguration config = null;

if (awtConfig != null)

config = awtConfig.getGraphicsConfiguration();

return new CubeCanvasGL(this, period, PWIDTH, PHEIGHT,

config, caps);

} // end of makeCanvas()

7.2。处理窗口事件CubeGL是一个窗口监听器:

public void windowActivated(WindowEvent e)

{ canvas.resumeGame(); }

public void windowDeactivated(WindowEvent e)

{ canvas.pauseGame(); }

public void windowDeiconified(WindowEvent e)

{ canvas.resumeGame(); }

public void windowIconified(WindowEvent e)

{ canvas.pauseGame(); }

public void windowClosing(WindowEvent e)

{ canvas.stopGame(); }

public void windowClosed(WindowEvent e) {}

public void windowOpened(WindowEvent e) {}

相关主题
相关文档
最新文档