如何有效地绘制点

ors*_*onl 3 c++ opengl point-cloud-library

我的程序接收 PCL 点云并使用以下方法一一绘制每个点:

glBegin(GL_POINTS);
glVertex3f(point.x, point.y, point].z);
glEnd();
Run Code Online (Sandbox Code Playgroud)

它有效,但由于点数很多,程序速度很慢。有没有更有效的方法来做到这一点?

gen*_*ult 7

当点云发生变化时,将所有点都塞到一个大的VBO 中,并使用一次glDrawArrays()调用一次性将它们全部绘制出来。这样的OpenGL可以移动的顶点数据,所有GPU一次,而你填鸭式司机几何一个glVertex()同时每一帧

哎呀,即使是顶点数组也会通过避免对 GL 驱动程序进行数十万次函数调用来为您带来巨大的加速。

编辑:比较:

1000 万个随机点,使用顶点缓冲对象:

顶点缓冲对象

顶点数组:

顶点数组

显示列表:

显示列表

并使用立即模式:

立即模式

代码(点击“n”在绘制方法之间循环):

// http://glew.sourceforge.net/
#include <GL/glew.h>

// http://freeglut.sourceforge.net/
#include <GL/freeglut.h>

// http://glm.g-truc.net/
#include <glm/glm.hpp>
#include <glm/gtc/random.hpp>
#include <glm/gtc/type_ptr.hpp>

#include <vector>
#include <sstream>
#include <chrono>
#include <cstddef>

struct Vertex
{
    glm::vec4 pos;
    glm::vec4 color;
};
std::vector< Vertex > verts;
GLuint vbo = 0;
GLuint dlist = 0;

void init()
{
    // init geometry
    for( size_t i = 0; i < 10000000; i++ )
    {
        Vertex vert;
        vert.pos = glm::vec4( glm::linearRand( glm::vec3( -1.0f, -1.0f, -1.0f ), glm::vec3( 1.0f, 1.0f, 1.0f ) ), 1.0f );
        vert.color = glm::vec4( glm::linearRand( glm::vec3( 0.00f, 0.0f, 0.0f ), glm::vec3( 1.0f, 1.0f, 1.0f ) ), 1.0f );
        verts.push_back( vert );
    }

    // create display list
    dlist = glGenLists( 1 );
    glNewList( dlist, GL_COMPILE );
    glBegin( GL_POINTS );
    for( size_t i = 0; i < verts.size(); ++i )
    {
        glColor4fv( glm::value_ptr( verts[i].color) );
        glVertex4fv( glm::value_ptr( verts[i].pos) );
    }
    glEnd();
    glEndList();

    // create VBO
    glGenBuffers( 1, &vbo );
    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, sizeof( Vertex ) * verts.size(), verts.data(), GL_STATIC_DRAW );
}

unsigned int method = 0;
void keyboard( unsigned char key, int x, int y )
{
    if( 'n' == key )
    {
        method++;
        if( method > 3 ) method = 0;
    }
}

void display()
{
    // timekeeping
    static std::chrono::steady_clock::time_point prv = std::chrono::steady_clock::now();
    std::chrono::steady_clock::time_point cur = std::chrono::steady_clock::now();
    const float dt = std::chrono::duration< float >( cur - prv ).count();
    prv = cur;

    glClearColor( 0, 0, 0, 1 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    double w = glutGet( GLUT_WINDOW_WIDTH );
    double h = glutGet( GLUT_WINDOW_HEIGHT );
    gluPerspective( 60.0, w / h, 0.1, 10.0 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    gluLookAt( 2, 2, 2, 0, 0, 0, 0, 0, 1 );

    static float angle = 0.0f;
    angle += dt * 6.0f;
    glRotatef( angle, 0, 0, 1 );

    // render
    switch( method )
    {
    case 0:
        // VBO
        glBindBuffer( GL_ARRAY_BUFFER, vbo );
        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_COLOR_ARRAY );
        glVertexPointer( 4, GL_FLOAT, sizeof( Vertex ), (void*)offsetof( Vertex, pos ) );
        glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), (void*)offsetof( Vertex, color ) );
        glDrawArrays( GL_POINTS, 0, verts.size() );
        glDisableClientState( GL_VERTEX_ARRAY );
        glDisableClientState( GL_COLOR_ARRAY );
        glBindBuffer( GL_ARRAY_BUFFER, 0 );
        break;

    case 1:
        // vertex array
        glEnableClientState( GL_VERTEX_ARRAY );
        glEnableClientState( GL_COLOR_ARRAY );
        glVertexPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].pos );
        glColorPointer( 4, GL_FLOAT, sizeof( Vertex ), &verts[0].color );
        glDrawArrays( GL_POINTS, 0, verts.size() );
        glDisableClientState( GL_VERTEX_ARRAY );
        glDisableClientState( GL_COLOR_ARRAY );
        break;

    case 2:
        // display list
        glCallList( dlist );
        break;

    case 3:
        // immediate mode
        glBegin( GL_POINTS );
        for( size_t i = 0; i < verts.size(); ++i )
        {
            glColor4fv( glm::value_ptr( verts[i].color) );
            glVertex4fv( glm::value_ptr( verts[i].pos) );
        }
        glEnd();
        break;
    }

    // info/frame time output
    std::stringstream msg;
    msg << "Using ";
    switch( method )
    {
    case 0: msg << "vertex buffer object"; break;
    case 1: msg << "vertex array"; break;
    case 2: msg << "display list"; break;
    case 3: msg << "immediate mode"; break;
    }
    msg << std::endl;
    msg << "Frame time: " << (dt * 1000.0f) << " ms";
    glColor3ub( 255, 255, 0 );
    glWindowPos2i( 10, 25 );
    glutBitmapString( GLUT_BITMAP_9_BY_15, (unsigned const char*)( msg.str().c_str() ) );

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "GLUT" );
    glewInit();
    init();
    glutDisplayFunc( display );
    glutKeyboardFunc( keyboard );
    glutIdleFunc( display );
    glutMainLoop();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


小智 -1

是的,您所展示的代码来自相当旧的 OpenGL 版本。在较新的版本中,您可以将数据打包在一起并通过一次调用将其发送到 GPU。代码变得有点复杂,但这是值得的。我建议你看看这个网站: https: //learnopengl.com/ 它收集了开始使用现代 opengl 所需的一切。希望有帮助。