Java - 如何在LWJGL中使用顶点缓冲区对象?

时间:2013-10-13 14:32:05

标签: java opengl lwjgl slick2d

我正在尝试使用顶点缓冲区对象。

起初,在我遇到这种令人讨厌的情况之前没有任何问题:

glPointSize(2.0f);
glBegin(GL_POINTS);
for (Entity p : points) {
    glVertex3f(p.x, p.y, p.z);
}
glEnd();

如何将其转换为Vertex缓冲区对象渲染?

我的意思是,你可以看到,数据(x,y,z)每次都为每个点改变(它是一个循环)。

那么如何实现Vertex Buffers Object渲染呢?

3 个答案:

答案 0 :(得分:8)

基本上你想要它将所有顶点数据放入FloatBuffer,然后将它传递给OpenGL。我创建了一个VBO的小例子,它存储三角形的顶点和颜色并渲染它,以及如何删除它!

创建VBO

这是您创建实际的顶点和颜色缓冲区并将它们绑定到VBO的代码。

int vertices = 3;

int vertex_size = 3; // X, Y, Z,
int color_size = 3; // R, G, B,

FloatBuffer vertex_data = BufferUtils.createFloatBuffer(vertices * vertex_size);
vertex_data.put(new float[] { -1f, -1f, 0f, });
vertex_data.put(new float[] { 1f, -1f, 0f, });
vertex_data.put(new float[] { 1f, 1f, 0f, });
vertex_data.flip();

FloatBuffer color_data = BufferUtils.createFloatBuffer(vertices * color_size);
color_data.put(new float[] { 1f, 0f, 0f, });
color_data.put(new float[] { 0f, 1f, 0f, });
color_data.put(new float[] { 0f, 0f, 1f, });
color_data.flip();

int vbo_vertex_handle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex_handle);
glBufferData(GL_ARRAY_BUFFER, vertex_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

int vbo_color_handle = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo_color_handle);
glBufferData(GL_ARRAY_BUFFER, color_data, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

如果您愿意,您当然可以向vertex_datacolor_data添加更多顶点和颜色!但要始终记住顶点数据量,需要与颜色数据量相匹配,反之亦然!

重要事项:只创建一次VBO,并且只在必要时更新它们!不要为每个帧创建它们,因为它们的帧速率会比使用立即模式渲染时更差!

渲染VBO

这是您需要调用的代码,用于渲染VBO。

glBindBuffer(GL_ARRAY_BUFFER, vbo_vertex_handle);
glVertexPointer(vertex_size, GL_FLOAT, 0, 0l);

glBindBuffer(GL_ARRAY_BUFFER, vbo_color_handle);
glColorPointer(color_size, GL_FLOAT, 0, 0l);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glDrawArrays(GL_TRIANGLES, 0, vertices);

glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);

删除VBO

然后,当您完成VBO并且不再需要它时,您可以通过执行以下操作将其删除。

glDeleteBuffers(vbo_vertex_handle);
glDeleteBuffers(vbo_color_handle);

答案 1 :(得分:1)

以下是关于缓冲区的好教程:

关于你的问题:

我建议创建一个最大点数的VBO(或者可能的点数是常数)。然后用NULL填充此缓冲区。

如果要渲染点,则需要map缓冲并更新其内容。

float *data = (float *)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
update_points(data); // write new positions for all points
glUnmapBuffer(GL_ARRAY_BUFFER); 

然后通过以下方式绘制:

bind_and_set_your_buffer();
glDrawArrays(GL_POINTS, 0, VertexCount);
  • 更新你可以考虑使用:glBufferSubData,或glMapBufferRange

答案 2 :(得分:1)

我遇到了同样的麻烦,Vallentin的回答非常令人满意。因此,为了JOGL,我想与公众分享整个代码。

package alican_tuts.VBO;

import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.FloatBuffer;

import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

import com.jogamp.common.nio.Buffers;
import com.jogamp.opengl.util.FPSAnimator;

public class VBO_Example extends GLCanvas implements GLEventListener {
    private static final long serialVersionUID = 1L;

    private static String TITLE = "AliCan VBO EXAMPLE";
    private static final int CANVAS_WIDTH = 800;
    private static final int CANVAS_HEIGHT = 600;
    private static final int FPS = 60;

    private GLU glu;

    // VBO related variables
    int vertices = 3; // Triangle vertices

    int vertex_size = 3; // X,Y,Z
    int color_size = 3; // R, G, B

    private FloatBuffer vertex_data;
    private FloatBuffer color_data;

    private int[] vbo_vertex_handle = new int[1];
    private int[] vbo_color_handle = new int[1];

    // ===========================================================
    // GUI creation and program's main function
    // ===========================================================
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                GLCanvas canvas = new VBO_Example();
                canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));

                final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);

                final JFrame frame = new JFrame();

                frame.getContentPane().add(canvas);
                frame.addWindowListener(new WindowAdapter() {
                    @Override
                    public void windowClosing(WindowEvent e) {

                        new Thread() {
                            @Override
                            public void run() {
                                if (animator.isStarted())
                                    animator.stop();
                                System.exit(0);
                            }
                        }.start();
                    }
                });
                frame.setTitle(TITLE);
                frame.pack();
                frame.setVisible(true);
                animator.start();
            }
        });
    }

    public VBO_Example() {
        this.addGLEventListener(this);
    }

    // ===========================================================
    // VBO Related Functions
    // ===========================================================

    private void initVBOs(GL2 gl) {
        vertex_data = Buffers.newDirectFloatBuffer(vertices * vertex_size);
        // vertex_data = FloatBuffer.allocate(vertices * vertex_size);
        vertex_data.put(new float[] { 0.0f, 1.0f, 0f });
        vertex_data.put(new float[] { -1.0f, -1.0f, 0f });
        vertex_data.put(new float[] { 1.0f, -1.0f, 0f });
        vertex_data.flip();

        color_data = Buffers.newDirectFloatBuffer(vertices * color_size);
        // color_data = FloatBuffer.allocate(vertices * color_size);
        color_data.put(new float[] { 1f, 0f, 0f });
        color_data.put(new float[] { 0f, 1f, 0f });
        color_data.put(new float[] { 0f, 0f, 1f });
        color_data.flip();

        gl.glGenBuffers(1, vbo_vertex_handle, 0);
        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo_vertex_handle[0]);

        gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertices * vertex_size * Buffers.SIZEOF_FLOAT, vertex_data,
                GL2.GL_STATIC_DRAW);
        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);

        gl.glGenBuffers(1, vbo_color_handle, 0);
        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo_color_handle[0]);
        gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertices * vertex_size * Buffers.SIZEOF_FLOAT, color_data,
                GL2.GL_STATIC_DRAW);
        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, 0);

    }

    private void renderVBOs(GL2 gl) {
        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo_vertex_handle[0]);
        gl.glVertexPointer(vertex_size, GL2.GL_FLOAT, 0, 0l);

        gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vbo_color_handle[0]);
        gl.glColorPointer(color_size, GL2.GL_FLOAT, 0, 0l);

        gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL2.GL_COLOR_ARRAY);

        gl.glDrawArrays(GL2.GL_TRIANGLES, 0, vertices);

        gl.glDisableClientState(GL2.GL_COLOR_ARRAY);
        gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
    }

    // ===========================================================
    // OpenGL Callback Functions
    // ===========================================================
    @Override
    public void init(GLAutoDrawable drawable) {
        GL2 gl = drawable.getGL().getGL2();
        glu = new GLU();
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        gl.glClearDepth(1.0f);
        gl.glEnable(GL2.GL_DEPTH_TEST);
        gl.glDepthFunc(GL2.GL_LEQUAL);
        gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST);

        gl.glShadeModel(GL2.GL_SMOOTH);

        initVBOs(gl);
    }

    @Override
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        GL2 gl = drawable.getGL().getGL2();

        if (height == 0)
            height = 1;
        float aspect = (float) width / height;

        gl.glViewport(0, 0, width, height);

        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0, aspect, 0.1, 100.0);

        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    @Override
    public void display(GLAutoDrawable drawable) {
        GL2 gl = drawable.getGL().getGL2();
        gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);

        gl.glLoadIdentity();

        gl.glTranslatef(0.0f, 0.0f, -6.0f);
        renderVBOs(gl);
    }

    @Override
    public void dispose(GLAutoDrawable drawable) {
    }

}