3D Object Display |
Documentation Contents |
This is Move.java, a program that displays and moves cubes. It places two wire-frame cubes and moves one of them with arrow keys. By pressing the space key, you can switch the target between the cube and the view point. With the "+" and "-" ten keys, you can change the view angle. Press the "q" key to terminate. Coordinate information is kept on the screen.
Below is the step-by-step guide to this source code.
The main class Move creates the following objects to have them control displays.
camera: sets the view point and target, the view angle, etc.
cube1: the cube that can be moved with keys. cube2: the cube that is fixed on the point (0,0,0). The camera object sets the target to cube1. Therefore, even if
the position of camera or cube1 moves, cube1 always appears in the center of
the screen.
To draw text, onix.gfx.image.BufferedGLImage is used. This is used as a buffer for drawing text using the Java2D function and pasting to the screen.
The inner class Controller allows the move of the cube or camera, and the increase/decrease of the view angle with key operations. It makes both the Camera and Cube classes derived classes of the Material class that has a method to move the position. So, by switching the target, you can move objects in the same manner.
initGraphics Method
In the
initGraphicsmethod, some settings are set as follows.public void initGraphics(GLGraphics g) { g.glViewport(0, 0, width, height); g.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); g.glEnable(GLConstants.GL_BLEND); g.glBlendFunc(GLConstants.GL_SRC_ALPHA, GLConstants.GL_ONE_MINUS_SRC_ALPHA); }
glViewport(0, 0, width, height): sets full screen display.glClearColor(0.0f, 0.0f, 0.0f, 0.0f):sets the color filled in by glClear to transparent.g.glEnable(GLConstants.GL_BLEND);: set the display of overlaying text data on the cubes.
g.glBlendFunc(GLConstants.GL_SRC_ALPHA, GLConstants.GL_ONE_MINUS_SRC_ALPHA);
update Method
The update method clears the screen, sets the camera and displays the cubes and then text data (with the printMessage method mentioned later).
public void update(GLGraphics g) { g.glClear(GLConstants.GL_COLOR_BUFFER_BIT); g.glPushMatrix(); g.glMatrixMode(GLConstants.GL_PROJECTION); g.glLoadIdentity(); camera.update(g); g.glMatrixMode(GLConstants.GL_MODELVIEW); g.glLoadIdentity(); for (int i = 0; i < materials.length; i++) { g.glPushMatrix(); materials[i].update(g); g.glPopMatrix(); } g.glPopMatrix(); printMessage(g, new String[] { camera.toString(), "Cube1: " + cube1.toString(), "Cube2: " + cube2.toString(), }); }OpenGL has a few coordinate modes. Perform drawing changing the mode by glMatrixMode. Use GL_PROJECTION to set the view point and display 2D graphics, and GL_MODELVIEW to draw 3D graphics. After changing the mode by glMatrixMode, glLoadIdentity is called for initialization.
If you call glPushMatrix, the subsequent changes of coordinates or view point operations can be cleared by calling glPopMatrix. In cases like delegating drawing to another object like cube, the coordinate data are maintained by enclsoing them between glPushMatrix and glPopMatrix.
The Camera class holds the eye position (this), target location (target), view angel (viewAngle) and the aspect ratio of the screen (aspectRatio). As the view angle represents degrees, the target looks larger on the screen when the angle is closer to 0 (narrower), and it looks smaller on the screen when the angle is closer to 180 (broader).
Below is the update method.
public void update(GLGraphics g) { g.gluPerspective(viewAngle, aspectRatio, 1.0d, 1600.0d); g.gluLookAt( getX(), getY(), getZ(), target.getX(), target.getY(), target.getZ(), 0, 0, 1); }With gluPerspective, the view angle, near plane and far plane are defined. With gluLookAt, the view point and target are defined and the z-axis is set upward.
The Cube class represents a white cube. The cube has 8 vertices. Using these vertices, create 6 planes to form a cube. Below is the update method.
private double width = 2d; private int[][] faceList = { {0, 3, 2, 1}, {1, 2, 6, 5}, {5, 6, 7, 4}, {4, 7, 3, 0}, {4, 0, 1, 5}, {3, 7, 6, 2}, }; public void update(GLGraphics g) { double[][] vertexList = { {getX() - width, getY() - width, getZ() - width}, {getX() + width, getY() - width, getZ() - width}, {getX() + width, getY() + width, getZ() - width}, {getX() - width, getY() + width, getZ() - width}, {getX() - width, getY() - width, getZ() + width}, {getX() + width, getY() - width, getZ() + width}, {getX() + width, getY() + width, getZ() + width}, {getX() - width, getY() + width, getZ() + width}, }; g.glColor3f(1.0f, 1.0f, 1.0f); for (int i = 0; i < faceList.length; i++) { int[] face = faceList[i]; g.glBegin(GLConstants.GL_LINE_LOOP); for (int j = 0; j < face.length; j++) { int vertexIndex = face[j]; g.glVertex3dv(vertexList[vertexIndex]); } g.glEnd(); } }The vertexList is a list of the cube's vertices (x,y,z). The faceList is a list of the cube's square surfaces, and its values are indexes of the vertexList. GL_LINE_LOOP is a series of instructions to draw lines between vertices and ends up with drawing a line between the starting and the end vertices. This example draws an outlined square that is one of the cube's surfaces. Each vertex is specified by glVertex3dv (arguments are {x,y,z} ).
The printMessage method writes text data to a buffer, and then writes the buffer to the screen.
private void printMessage(GLGraphics g, String[] messages) { Graphics2D g2d = image.getBufferedImage().createGraphics(); g2d.setTransform(new AffineTransform(1, 0, 0, -1, 0, height)); g2d.setBackground(new Color(0, 0, 0, 0)); g2d.clearRect(0, 0, width, height); g2d.setFont(g2d.getFont().deriveFont(Font.PLAIN, (float) fontSize)); g2d.setColor(Color.blue); int margin = fontSize / 2; int x = margin; int y = height - (fontSize + margin) * (messages.length - 1) - margin; for (int i = 0; i < messages.length; i++) { g2d.drawString(messages[i], x, y); y += fontSize + margin; } g.glPushMatrix(); g.glMatrixMode(GLConstants.GL_PROJECTION); g.glLoadIdentity(); image.draw(g); g.glPopMatrix(); }With setTransform, the buffer's coordinate system is transformed to match that of OpenGL (i.e. to x = x, y = height - y). With setBackground, the background color is set to transparent in order to write this buffer over the cubes. Thereafter, the text is drawn in the same manner as common drawing with Java2D.
After writing the text to the buffer, the image on the buffer is drawn on the screen by calling image.draw(g).
You can write text without using Java2D classes. Move2.java provides such method.
You use onix.gfx.font.SystemFont. Here it is created by passing AWT's font object to the argument in the constructor of Move2.
font = new SystemFont(new Font("System", Font.PLAIN, fontSize));printMessage should be as follows. The initGraphics and update methods other than that have the code identical to Move.
private void printMessage(GLGraphics g, String[] messages) { g.glPushMatrix(); g.glMatrixMode(GLConstants.GL_PROJECTION); g.glLoadIdentity(); g.gluOrtho2D(0, width, 0, height); g.glScaled(1, -1, 1); g.glTranslated(0, -height, 0); g.glColor3d(0.0, 0.0, 1.0); int margin = fontSize / 2; int x = margin; int y = height - (margin + fontSize) * (messages.length - 1) - margin; g.glEnable(GLConstants.GL_TEXTURE_2D); for (int i = 0; i < messages.length; i++) { font.draw(messages[i], x, y, g); y += fontSize + margin; } g.glDisable(GLConstants.GL_TEXTURE_2D); g.glPopMatrix(); }Start with gluOrtho2D to project the text in 2D, and use glScaled and glTranslated to transform the coordinate so that the upper left comes to (0,0).
The text is drawn with the draw method of SystemFont. GL_TEXTURE_2D must be enabled before calling the draw method and disabled after that.
|
Copyright © 2001-2002 CyberStep, Inc. All Rights Reserved. |
Oni Software |