I need to render a lot of dynamic poligons.
After some searching i found that VBO would be the right solution to do this.
Now there are some tutorials about VBO (http://lwjgl.org/wiki/doku.php/lwjgl/tutorials/opengl/basicvbo and http://lwjgl.org/wiki/doku.php/lwjgl/tutorials/opengl/speedyvbo), but they tell me i should understand vertex arrays first.
So i googled for lwjgl vertex array, but can't find any tutorial about how to do the vertex arrays in lwjgl.
Is there somewhere a tutorial i couldn't find, or can someone give me an instruction?
Here is an example of using vertex array to draw a Cube. With LWJGL you have to use nio buffers for the arrays.
private void initGL() {
GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
GL11.glShadeModel(GL11.GL_SMOOTH); // Enable Smooth Shading
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
GL11.glClearDepth(1.0); // Depth Buffer Setup
GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(
45.0f,
(float) WINDOW_WIDTH / (float) WINDOW_HEIGHT,
0.1f,
100.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
// Really Nice Perspective Calculations
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
vertices = BufferUtils.createFloatBuffer(3 * 4 * 6);
vertices.put(new float[] {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f});
}
/**
* Render the current frame
*/
private void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
GL11.glLoadIdentity(); // Reset The Current Modelview Matrix
GL11.glTranslatef(0.0f, 0.0f, z); // Move Into The Screen 5 Units
GL11.glRotatef(xrot, 1.0f, 0.0f, 0.0f); // Rotate On The X Axis
GL11.glRotatef(yrot, 0.0f, 1.0f, 0.0f); // Rotate On The Y Axis
GL11.glRotatef(zrot, 0.0f, 0.0f, 1.0f); // Rotate On The Z Axis
GL11.glColor3f(1.0f, 1.0f, 1.0f);
// Enable vertex arrays
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
// Setup vertex array pointer
vertices.rewind();
GL11.glVertexPointer(3, 0, vertices);
// Draw using vertex array
GL11.glDrawArrays(GL11.GL_QUADS, 0, 24);
// Disable vertex arrays
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
}
Thanks, this helps me :)
Next thing: how can i add normals?
i now finished implementing the vertexarrays in my engine, it works fine on smaller arrays, but if it's a large array (lets say 150000) it crashes:
#
# An unexpected error has been detected by Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0xb7ed19ac, pid=9665, tid=2897963920
#
# Java VM: Java HotSpot(TM) Client VM (1.6.0_03-b05 mixed mode)
# Problematic frame:
# C [libc.so.6+0x6e9ac] memcpy+0x1c
#
# An error report file with more information is saved as hs_err_pid9665.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#
should i divide it into several smaller arrays, or doesn't this problem exist if i change it to vbo?
I now tried to do the VBO, I followed the above mentioned tutorial.
I have a Problem at:
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, indexBufferID);
GL12.glDrawRangeElements(GL11.GL_TRIANGLES, 0, maxIndex, indexBufferSize,
GL11.GL_UNSIGNED_INT, 0);
How do i have to do the Rendering? What is the indexBudderID and where do i get it?
indexBufferID is the texture id
public static int createVBOID() {
if (GLContext.getCapabilities().GL_ARB_vertex_buffer_object) {
IntBuffer buffer = BufferUtils.createIntBuffer(1);
ARBVertexBufferObject.glGenBuffersARB(buffer);
return buffer.get(0);
}
return 0;
}
int indexBufferID = createVBOID();
Well, now i have no errors anymore, and some nice FPS count, only problem: my landscape completly disappeared :D
Is there somewhere a complete piece of code how to create the VBO?
I can't get it to work :(
Btw.. in my last post I meant to say its the vertex buffer object ID. Its like a texture ID. Below is working VBO example
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.ARBVertexBufferObject;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GLContext;
import org.lwjgl.opengl.Util;
import org.lwjgl.opengl.glu.GLU;
public class CubeDemo {
private static final String TITLE = "Cube Demo";
private static final int FRAMERATE = 60;
private static final int WINDOW_WIDTH = 640;
private static final int WINDOW_HEIGHT = 480;
private volatile boolean isPaused = false;
private volatile boolean isRunning = false;
private float xrot = 0f; // X Rotation
private float yrot = 0f; // Y Rotation
private float zrot = 0f; // Z Rotation
private float xspeed = 0.3f; // X Rotation Speed
private float yspeed = 0.2f; // Y Rotation Speed
private float zspeed = 0.4f; // Z Rotation Speed
private float z = -5.0f; // Depth Into The Screen
/**
* Application init
*
* @param args
* Commandline arguments
*/
public static void main(String[] args) {
CubeDemo animation = null;
try {
animation = new CubeDemo();
animation.run();
} catch (Exception e) {
e.printStackTrace(System.err);
Sys.alert(TITLE, "An error occured and the game will exit.");
} finally {
if(animation != null) animation.cleanup();
}
System.exit(0);
}
/**
* Determine an available display that matches the specified paramaters.
*
* @param width
* The desired width of the screen
* @param height
* The desired height of the screen
* @param bpp
* The desired colour depth (bits per pixel) of the screen
* @return The display mode matching the requirements or null if none could
* be found
* @throws LWJGLException
* Indicates a failure interacting with the LWJGL library.
*/
private static DisplayMode findDisplayMode(int width, int height, int bpp)
throws LWJGLException {
DisplayMode[] modes = Display.getAvailableDisplayModes();
DisplayMode mode = null;
for (int i = 0; i < modes.length; i++) {
if ((modes[i].getBitsPerPixel() == bpp) || (mode == null)) {
if ((modes[i].getWidth() == width)
&& (modes[i].getHeight() == height)) {
mode = modes[i];
}
}
}
return mode;
}
/**
* Initialise the animation
*
* @throws Exception
* if init fails
*/
public CubeDemo() throws Exception {
// find out what the current bits per pixel of the desktop is
int currentBpp = Display.getDisplayMode().getBitsPerPixel();
// find a display mode at 800x600
DisplayMode mode = findDisplayMode(WINDOW_WIDTH, WINDOW_HEIGHT, currentBpp);
// if can't find a mode, notify the user the give up
if (mode == null) {
Sys.alert("Error", WINDOW_WIDTH + "x" + WINDOW_HEIGHT + "x" + currentBpp
+ " display mode unavailable");
return;
}
Display.setTitle(TITLE);
Display.setDisplayMode(mode);
Display.setFullscreen(false);
// Enable vsync if we can
Display.setVSyncEnabled(true);
Display.create();
initGL();
}
/** The time since the last record of fps */
private long lastFpsTime = 0;
/** The recorded fps */
private int fps = 0;
/**
* Runs the animation (the "main loop")
*/
private void run() {
long lastLoopTime, delta;
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
isRunning = true;
lastLoopTime = System.nanoTime();
while (isRunning) {
delta = System.nanoTime() - lastLoopTime;
lastLoopTime = System.nanoTime();
lastFpsTime += delta;
fps++;
// update our FPS counter if a second has passed
if (lastFpsTime >= 1000000000L) {
Display.setTitle(TITLE +" (FPS: " + fps + ")");
lastFpsTime = 0;
fps = 0;
}
// Always call Display.update(), all the time
Display.update();
if (Display.isCloseRequested()) {
// Check for O/S close requests
isRunning = false;
} else if (Display.isActive()) {
// The window is in the foreground, so we should play the game
logic(delta);
render();
Display.sync(FRAMERATE);
} else {
// The window is not in the foreground, so we can allow other
// stuff to run and
// infrequently update
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
logic(delta);
if (Display.isVisible() || Display.isDirty()) {
// Only bother rendering if the window is visible or dirty
render();
}
}
}
}
private boolean pausePressed = false;
private boolean resetPressed = false;
/**
* Do all calculations, handle input, etc.
*/
private void logic(long delta) {
if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
isRunning = false;
}
if (Keyboard.isKeyDown(Keyboard.KEY_P) && !pausePressed) {
pausePressed = true;
isPaused = !isPaused;
}
if (!Keyboard.isKeyDown(Keyboard.KEY_P)) {
pausePressed = false;
}
if (isPaused) return;
if (Keyboard.isKeyDown(Keyboard.KEY_R) && !resetPressed) {
resetPressed = true;
// Reset speeds
xspeed = 0.3f;
yspeed = 0.2f;
zspeed = 0.4f;
}
if (!Keyboard.isKeyDown(Keyboard.KEY_R)) {
resetPressed = false;
}
if (Keyboard.isKeyDown(Keyboard.KEY_PRIOR)) {
z -= 0.02f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_NEXT)) {
z += 0.02f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
xspeed -= 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
xspeed += 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT)) {
yspeed += 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_LEFT)) {
yspeed -= 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
zspeed -= 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_Z)) {
zspeed += 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_COMMA)) {
xspeed -= 0.01f;
yspeed -= 0.01f;
zspeed -= 0.01f;
}
if (Keyboard.isKeyDown(Keyboard.KEY_PERIOD)) {
xspeed += 0.01f;
yspeed += 0.01f;
zspeed += 0.01f;
}
xrot += xspeed; // X Axis Rotation
yrot += yspeed; // Y Axis Rotation
zrot += zspeed; // Z Axis Rotation
}
private void initGL() {
GL11.glEnable(GL11.GL_TEXTURE_2D); // Enable Texture Mapping
GL11.glShadeModel(GL11.GL_SMOOTH); // Enable Smooth Shading
GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background
GL11.glClearDepth(1.0); // Depth Buffer Setup
GL11.glEnable(GL11.GL_DEPTH_TEST); // Enables Depth Testing
GL11.glDepthFunc(GL11.GL_LEQUAL); // The Type Of Depth Testing To Do
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(
45.0f,
(float) WINDOW_WIDTH / (float) WINDOW_HEIGHT,
0.1f,
100.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
// Really Nice Perspective Calculations
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
vertices = BufferUtils.createFloatBuffer(3 * 4 * 6);
vertices.put(new float[] {
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f});
vertices.rewind();
vertexBufferID = createVBOID();
bufferData(vertexBufferID, vertices);
}
private int vertexBufferID;
private FloatBuffer vertices;
public static int createVBOID() {
if (GLContext.getCapabilities().GL_ARB_vertex_buffer_object) {
IntBuffer buffer = BufferUtils.createIntBuffer(1);
ARBVertexBufferObject.glGenBuffersARB(buffer);
return buffer.get(0);
}
return 0;
}
public static void bufferData(int id, FloatBuffer buffer) {
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, id);
ARBVertexBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, buffer, ARBVertexBufferObject.GL_STATIC_DRAW_ARB);
}
/**
* Render the current frame
*/
private void render() {
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
GL11.glLoadIdentity(); // Reset The Current Modelview Matrix
GL11.glTranslatef(0.0f, 0.0f, z); // Move Into The Screen 5 Units
GL11.glRotatef(xrot, 1.0f, 0.0f, 0.0f); // Rotate On The X Axis
GL11.glRotatef(yrot, 0.0f, 1.0f, 0.0f); // Rotate On The Y Axis
GL11.glRotatef(zrot, 0.0f, 0.0f, 1.0f); // Rotate On The Z Axis
GL11.glColor3f(1.0f, 1.0f, 1.0f);
vertices.rewind();
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, vertexBufferID);
GL11.glVertexPointer(3, GL11.GL_FLOAT, 0, 0);
GL11.glDrawArrays(GL11.GL_QUADS, 0, 24);
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
}
/**
* Do any animation-specific cleanup
*/
private void cleanup() {
// Close the window
Display.destroy();
}
}
Thanks :)
Got it to work now, at similar speeds as the DisplayList before.
Now the next thing todo is to add the array with the normals...
Everything is working now :)
Here's what i did: http://xphase.nerds-paradise.de/files/download_now.pl?version=latest
Hi there :)
Thanks for your post, it helped me much to learn the glDrawArrays thing
Cheers