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.

Move screen

Below is the step-by-step guide to this source code.

Program Configuration

The main class Move creates the following objects to have them control displays.

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 initGraphics method, 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);
    }

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.

Camera Object

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).

p

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.

Cube Object

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} ).

Display Text Using a Buffer

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).

Display Text Using SystemFont

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