如何有效地绘制积分

时间:2017-06-21 22:09:15

标签: c++ opengl point-cloud-library

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

glBegin(GL_POINTS);
glVertex3f(point.x, point.y, point].z);
glEnd();

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

2 个答案:

答案 0 :(得分:4)

当点云变化时,将所有点卡入一个大的VBO。使用单个glDrawArrays()调用一次性绘制它们。这样,OpenGL可以shift将所有顶点数据spoon-feeding一次{而不是vertex buffer object一次驱动几何glVertex() 每一帧

哎呀,即使是顶点阵列也可以通过避免GL驱动程序中的数十万个函数调用来为您带来巨大的加速。

编辑:比较:

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

vertex array

顶点数组:

display list

显示列表:

immediate-mode

使用立即模式:

Plunkr demonstrating the issue

代码(点击'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;
}

答案 1 :(得分:0)

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