0

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

起初没有任何问题,直到我陷入这种令人讨厌的情况:

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

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

我的意思是,如您所见,数据 (x, y, z) 每次都针对每个点进行更改(这是一个循环)。

那么我怎样才能实现顶点缓冲区对象渲染呢?

4

3 回答 3

8

基本上你想要的是将所有顶点数据放入 aFloatBuffer中,然后将其传递给 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_data当然,color_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);
于 2013-10-13T15:33:07.527 回答
1

I had same trouble and Vallentin's answer is very satisfying. So, for sake of JOGL, I want to share whole code with public.

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

}
于 2015-02-10T14:36:14.853 回答
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
于 2013-10-13T14:39:52.517 回答