java left logo
java middle logo
java right logo
 

Home arrow Other API Tips
 
 
Main Menu
Home
Java Tutorials
Book Reviews
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Java Network
Java Forums
Java Blog




Most Visited Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews
Top Rated Tips
Java SE Tips
Java ME Tips
Java EE Tips
Other API Tips
Java Applications
Java Libraries
Java Games
Book Reviews


Statistics
Registered Users: 3942
Java SE Tips: 614
Java ME Tips: 202
Java EE Tips: 183
Other API Tips: 779
Java Applications: 298
Java Libraries: 209
Java Games: 16
Book Reviews:
 
 
 
Vertex buffer objects - NeHe Tutorial JOGL Port E-mail
User Rating: / 12
PoorBest 

When you need raw polygon-pushing power, you can always utilize the optimizations provided by OpenGL. Vertex Arrays are one good way to do that. For even more boost you can use a recent extension to graphics cards called 'Vertex Buffer Objects'. The extension, ARB_vertex_buffer_object, works just like vertex arrays, except that it loads the data into the graphics card's high-performance memory, significantly lowering rendering time.

This is the Java port of the one of the NeHe OpenGL tutorials.

You can get complete IntelliJ IDEA project structure (all source, resources, build script, ) by downloading the source distribution from here.

The original post of the programmer who ported the examples can be found here.


Image

package demos.nehe.lesson45;

import demos.common.GLDisplay;

public class Lesson45 {
    public static void main(String[] args) {
        GLDisplay neheGLDisplay = GLDisplay.createGLDisplay(
                "Lesson 45: Vertex buffer objects");
        Renderer renderer = new Renderer(neheGLDisplay);
        neheGLDisplay.addGLEventListener(renderer);
        neheGLDisplay.start();
    }
}


package demos.nehe.lesson45;

import demos.common.GLDisplay;
import demos.common.TextureReader;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

import javax.swing.*;
import java.io.IOException;
import java.nio.FloatBuffer;

import com.sun.opengl.util.BufferUtil;

class Renderer implements GLEventListener {
    // Mesh Generation Paramaters
    private static final float MESH_RESOLUTION = 4.0f;  // Pixels Per Vertex
    private static final float MESH_HEIGHTSCALE = 1.0f;  // Mesh Height Scale

    private Mesh mesh = null;    // Mesh Data
    private float yRotation = 0.0f;  // Rotation
    private long previousTime = System.currentTimeMillis();
    private GLDisplay glDisplay;
    private GLU glu = new GLU();

    public Renderer(GLDisplay glDisplay) {
        this.glDisplay = glDisplay;
    }

    public void init(GLAutoDrawable drawable) {
        GL gl = drawable.getGL();

        // Check For VBO support
        final boolean VBOsupported = gl.isFunctionAvailable("glGenBuffersARB"&&
                gl.isFunctionAvailable("glBindBufferARB"&&
                gl.isFunctionAvailable("glBufferDataARB"&&
                gl.isFunctionAvailable("glDeleteBuffersARB");

        // Load The Mesh Data
        mesh = new Mesh();  // Instantiate Our Mesh
        try {
            mesh.loadHeightmap(gl, "demos/data/images/Terrain.bmp"// Load Our Heightmap
                    MESH_HEIGHTSCALE,
                    MESH_RESOLUTION,
                    VBOsupported);
        catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                String title = glDisplay.getTitle() " - " 
                        mesh.getVertexCount() " triangles";
                if (VBOsupported) {
                    title += ", using VBO";
                else {
                    title += ", not using VBO";
                }
                glDisplay.setTitle(title);
            }
        });


        // Setup GL States
        gl.glClearColor(0.0f0.0f0.0f0.5f);  // Black Background
        gl.glClearDepth(1.0f);        // Depth Buffer Setup
        gl.glDepthFunc(GL.GL_LEQUAL);  // The Type Of Depth Testing (Less Or Equal)
        gl.glEnable(GL.GL_DEPTH_TEST);      // Enable Depth Testing
        gl.glShadeModel(GL.GL_SMOOTH);      // Select Smooth Shading
        // Set Perspective Calculations To Most Accurate
        gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);      
        gl.glEnable(GL.GL_TEXTURE_2D);      // Enable Textures
        gl.glColor4f(1.0f1.0f1.0f1.0f);    // Set The Color To White
    }

    private void update(long milliseconds) {    // Perform Motion Updates Here
        // Consistantly Rotate The Scenery
        yRotation += (float) (milliseconds1000.0f 25.0f;  
    }

    public void display(GLAutoDrawable drawable) {
        long time = System.currentTimeMillis();
        update(time - previousTime);
        previousTime = time;
        GL gl = drawable.getGL();

        // Clear Screen And Depth Buffer
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);    
        gl.glLoadIdentity();  // Reset The Modelview Matrix

        // Move The Camera
        gl.glTranslatef(0, -220 * MESH_HEIGHTSCALE, 0)// Move above the terrain
        gl.glRotatef(10.0f1.0f0.0f0.0f);    // Look Down Slightly
        gl.glRotatef(yRotation, 0.0f1.0f0.0f);  // Rotate The Camera

        // Render the mesh
        mesh.render(gl);
    }

    public void reshape(GLAutoDrawable drawable,
                        int xstart,
                        int ystart,
                        int width,
                        int height) {
        GL gl = drawable.getGL();

        height = (height == 0: height;

        gl.glViewport(00, width, height);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();

        glu.gluPerspective(45(floatwidth / height, 11000);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void displayChanged(GLAutoDrawable drawable,
                               boolean modeChanged,
                               boolean deviceChanged) {
    }

    private class Mesh {
        // Mesh Data
        private int vertexCount;    // Vertex Count
        private FloatBuffer vertices;    // Vertex Data
        private FloatBuffer texCoords;    // Texture Coordinates
        private int[] textureId = new int[1];  // Texture ID

        // Vertex Buffer Object Names
        private int[] VBOVertices = new int[1];  // Vertex VBO Name
        private int[] VBOTexCoords = new int[1];// Texture Coordinate VBO Name
        private boolean fUseVBO;

        public int getVertexCount() {
            return vertexCount;
        }

        public boolean loadHeightmap(GL gl, String szPath, float flHeightScale, 
                float flResolution, boolean useVBOthrows IOException {
            TextureReader.Texture texture = null;
            texture = TextureReader.readTexture(szPath);

            // Generate Vertex Field
            vertexCount = (int) (texture.getWidth() * texture.getHeight() 
                    (flResolution * flResolution));
            // Allocate Vertex Data
            vertices = BufferUtil.newFloatBuffer(vertexCount * 3);
            // Allocate Tex Coord Data
            texCoords = BufferUtil.newFloatBuffer(vertexCount * 2);        
            for (int nZ = 0; nZ < texture.getHeight(); nZ += (intflResolution) {
                for (int nX = 0; nX < texture.getWidth(); nX += (intflResolution) {
                    for (int nTri = 0; nTri < 6; nTri++) {
                        // Using This Quick Hack, Figure The X,Z Position Of The Point
                        float flX = (floatnX + 
                                ((nTri == || nTri == || nTri == 5
                                    flResolution : 0.0f);
                        float flZ = (floatnZ + 
                                ((nTri == || nTri == || nTri == 5
                                    flResolution : 0.0f);

                        // Set The Data, Using PtHeight To Obtain The Y Value
                        vertices.put(flX - (texture.getWidth() 2f));
                        vertices.put(pointHeight(texture, (intflX, (intflZ
                                flHeightScale);
                        vertices.put(flZ - (texture.getHeight() 2f));

                        // Stretch The Texture Across The Entire Mesh
                        texCoords.put(flX / texture.getWidth());
                        texCoords.put(flZ / texture.getHeight());
                    }
                }
            }
            vertices.flip();
            texCoords.flip();

            // Load The Texture Into OpenGL
            gl.glGenTextures(1, textureId, 0);      // Get An Open ID
            gl.glBindTexture(GL.GL_TEXTURE_2D, textureId[0]);  // Bind The Texture
            gl.glTexImage2D(GL.GL_TEXTURE_2D, 03, texture.getWidth()
                    texture.getHeight()0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, 
                    texture.getPixels());
            
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, 
                    GL.GL_LINEAR);
            
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, 
                    GL.GL_LINEAR);

            if (useVBO) {
                // Load Vertex Data Into The Graphics Card Memory
                buildVBOs(gl);  // Build The VBOs
            }

            return true;
        }

        public void render(GL gl) {
            // Enable Pointers
            gl.glEnableClientState(GL.GL_VERTEX_ARRAY);  // Enable Vertex Arrays
            // Enable Texture Coord Arrays
            gl.glEnableClientState(GL.GL_TEXTURE_COORD_ARRAY);  

            // Set Pointers To Our Data
            if (fUseVBO) {
                gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, mesh.VBOTexCoords[0]);
                // Set The TexCoord Pointer To The TexCoord Buffer
                gl.glTexCoordPointer(2, GL.GL_FLOAT, 00);    
                gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, mesh.VBOVertices[0]);
                // Set The Vertex Pointer To The Vertex Buffer
                gl.glVertexPointer(3, GL.GL_FLOAT, 00);    
            else {
                // Set The Vertex Pointer To Our Vertex Data
                gl.glVertexPointer(3, GL.GL_FLOAT, 0, mesh.vertices)
                // Set The Vertex Pointer To Our TexCoord Data
                gl.glTexCoordPointer(2, GL.GL_FLOAT, 0, mesh.texCoords)
            }

            // Render
            // Draw All Of The Triangles At Once
            gl.glDrawArrays(GL.GL_TRIANGLES, 0, mesh.vertexCount);  

            // Disable Pointers
            // Disable Vertex Arrays
            gl.glDisableClientState(GL.GL_VERTEX_ARRAY);  
            // Disable Texture Coord Arrays
            gl.glDisableClientState(GL.GL_TEXTURE_COORD_ARRAY);        
        }

        private float pointHeight(TextureReader.Texture texture, int nX, int nY) {
            // Calculate The Position In The Texture, Careful Not To Overflow
            int nPos = ((nX % texture.getWidth()) ((nY % texture.getHeight()) 
                    texture.getWidth())) 3;
            // Get The Red Component
            float flR = unsignedByteToInt(texture.getPixels().get(nPos));      
            // Get The Green Component
            float flG = unsignedByteToInt(texture.getPixels().get(nPos + 1));    
            // Get The Blue Component
            float flB = unsignedByteToInt(texture.getPixels().get(nPos + 2));    
            // Calculate The Height Using The Luminance Algorithm
            return (0.299f * flR + 0.587f * flG + 0.114f * flB);    
        }

        private int unsignedByteToInt(byte b) {
            return (intb & 0xFF;
        }

        private void buildVBOs(GL gl) {
            // Generate And Bind The Vertex Buffer
            gl.glGenBuffersARB(1, VBOVertices, 0);  // Get A Valid Name
            gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOVertices[0]);  // Bind The Buffer
            // Load The Data
            gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, vertexCount * 
                    BufferUtil.SIZEOF_FLOAT, vertices, GL.GL_STATIC_DRAW_ARB);

            // Generate And Bind The Texture Coordinate Buffer
            gl.glGenBuffersARB(1, VBOTexCoords, 0);  // Get A Valid Name
            gl.glBindBufferARB(GL.GL_ARRAY_BUFFER_ARB, VBOTexCoords[0])// Bind The Buffer
            // Load The Data
            gl.glBufferDataARB(GL.GL_ARRAY_BUFFER_ARB, vertexCount * 
                    BufferUtil.SIZEOF_FLOAT, texCoords, GL.GL_STATIC_DRAW_ARB);

            // Our Copy Of The Data Is No Longer Necessary, It Is Safe In The Graphics Card
            vertices = null;
            texCoords = null;
            fUseVBO = true;
        }
    }
}

 Related Tips

 
< Prev   Next >

Page 1 of 0 ( 0 comments )

You can share your information about this topic using the form below!

Please do not post your questions with this form! Thanks.


Name (required)


E-Mail (required)

Your email will not be displayed on the site - only to our administrator
Homepage(optional)



Comment Enable HTML code : Yes No



 
       
         
     
 
 
 
   
 
 
java bottom left
java bottom middle
java bottom right
RSS 0.91 FeedRSS 1.0 FeedRSS 2.0 FeedATOM FeedOPML Feed

Home - About Us - Privacy Policy
Copyright 2005 - 2008 www.java-tips.org
Java is a trademark of Sun Microsystems, Inc.