使用现代 OpenGL 绘图时的点云失真

我找到了使用 PyQt 和现代 OpenGL 绘制和旋转立方体的精彩教程。我的目标是通过执行以下操作来为点云调整脚本(另请参见下面的代码):

  1. 使用 Open3D 加载点云并将坐标和颜色提取为 numpy 数组

  2. 从数组创建顶点缓冲区对象 (VBO)

  3. 将绘图功能更改为gl.glDrawElements(gl.GL_POINTS, ...)

不幸的是,点云非常扭曲和稀薄(见截图)。它实际上应该是一个有椅子和墙壁的房间。

你看我是否在 VBO 或绘图上犯了错误?还是有更好的加载点云的方法?

http://img4.mukewang.com/64128cb60001adb002960324.jpg

我用旧的固定管道(glBegin(GL_POINTS)... glEnd())测试了这个例子,点云被正确绘制(但性能也很差!)。

小怪兽爱吃肉
浏览 82回答 1
1回答

慕慕森

经过长时间的搜索,我发现了这个stackoverflow-post。gl.glGenBuffers(1)我通过将点坐标和颜色一起存储在一个 vbo 对象 ( )中来调整我的代码以适应该答案。然后我用特定的步幅和偏移量定义顶点和颜色指针:gl.glVertexPointer(3, gl.GL_FLOAT, 6*4, None)步幅= 24 字节:[x, y, z, r, g, b] * sizeof(float)gl.glColorPointer(3, gl.GL_FLOAT, 6*4, ctypes.c_void_p(3*4))offset= 12 bytes:rgb颜色从3个坐标x,y,z之后开始最后我用来gl.glDrawArrays(gl.GL_POINTS, 0, noOfVertices)绘制点云。完整代码如下(标有### NEW ###注释):from PyQt5 import QtCore      # core Qt functionalityfrom PyQt5 import QtGui       # extends QtCore with GUI functionalityfrom PyQt5 import QtOpenGL    # provides QGLWidget, a special OpenGL QWidgetfrom PyQt5 import QtWidgetsimport OpenGL.GL as gl        # python wrapping of OpenGLfrom OpenGL import GLU        # OpenGL Utility Library, extends OpenGL functionalityfrom OpenGL.arrays import vboimport numpy as npimport open3d as o3dimport ctypes import sys                    # we'll need this later to run our Qt applicationclass MainWindow(QtWidgets.QMainWindow):    def __init__(self):        QtWidgets.QMainWindow.__init__(self)    # call the init for the parent class        self.resize(300, 300)        self.setWindowTitle('Hello OpenGL App')                self.glWidget = GLWidget(self)        self.initGUI()                timer = QtCore.QTimer(self)        timer.setInterval(20)   # period, in milliseconds        timer.timeout.connect(self.glWidget.updateGL)        timer.start()            def initGUI(self):        central_widget = QtWidgets.QWidget()        gui_layout = QtWidgets.QVBoxLayout()        central_widget.setLayout(gui_layout)        self.setCentralWidget(central_widget)        gui_layout.addWidget(self.glWidget)        sliderX = QtWidgets.QSlider(QtCore.Qt.Horizontal)        sliderX.valueChanged.connect(lambda val: self.glWidget.setRotX(val))        sliderY = QtWidgets.QSlider(QtCore.Qt.Horizontal)        sliderY.valueChanged.connect(lambda val: self.glWidget.setRotY(val))        sliderZ = QtWidgets.QSlider(QtCore.Qt.Horizontal)        sliderZ.valueChanged.connect(lambda val: self.glWidget.setRotZ(val))        gui_layout.addWidget(sliderX)        gui_layout.addWidget(sliderY)        gui_layout.addWidget(sliderZ)        class GLWidget(QtOpenGL.QGLWidget):    def __init__(self, parent=None):        self.parent = parent        QtOpenGL.QGLWidget.__init__(self, parent)    def initializeGL(self):        self.qglClearColor(QtGui.QColor(100, 100, 100))     # initialize the screen to blue        gl.glEnable(gl.GL_DEPTH_TEST)                       # enable depth testing        self.initGeometry()        self.rotX = 0.0        self.rotY = 0.0        self.rotZ = 0.0    def setRotX(self, val):        self.rotX = val    def setRotY(self, val):        self.rotY = val    def setRotZ(self, val):        self.rotZ = val            def resizeGL(self, width, height):        gl.glViewport(0, 0, width, height)        gl.glMatrixMode(gl.GL_PROJECTION)        gl.glLoadIdentity()        aspect = width / float(height)        GLU.gluPerspective(45.0, aspect, 1.0, 100.0)        gl.glMatrixMode(gl.GL_MODELVIEW)            def paintGL(self):        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)        gl.glPushMatrix()    # push the current matrix to the current stack        gl.glTranslate(0.0, 0.0, -3.0)    # third, translate cube to specified depth        #gl.glScale(20.0, 20.0, 20.0)       # second, scale cube        gl.glRotate(self.rotX, 1.0, 0.0, 0.0)        gl.glRotate(self.rotY, 0.0, 1.0, 0.0)        gl.glRotate(self.rotZ, 0.0, 0.0, 1.0)        gl.glTranslate(-0.5, -0.5, -0.5)   # first, translate cube center to origin        # Point size        gl.glPointSize(3)                ### NEW ###        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)        stride = 6*4 # (24 bates) : [x, y, z, r, g, b] * sizeof(float)        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)        gl.glVertexPointer(3, gl.GL_FLOAT, stride, None)        gl.glEnableClientState(gl.GL_COLOR_ARRAY)        offset = 3*4 # (12 bytes) : the rgb color starts after the 3 coordinates x, y, z         gl.glColorPointer(3, gl.GL_FLOAT, stride, ctypes.c_void_p(offset))                noOfVertices = self.noPoints        gl.glDrawArrays(gl.GL_POINTS, 0, noOfVertices)        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)        gl.glDisableClientState(gl.GL_COLOR_ARRAY)        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)        ### NEW ###        gl.glPopMatrix()    # restore the previous modelview matrix            def initGeometry(self):            vArray = self.LoadVertices()        self.noPoints  = len(vArray) // 6        print("No. of Points: %s" % self.noPoints)                self.vbo = self.CreateBuffer(vArray)            ### NEW ###    def LoadVertices(self):                pcd = o3d.io.read_point_cloud("../pointclouds/0004.ply")        print(pcd)        print("Pointcloud Center: " + str(pcd.get_center()))            points = np.asarray(pcd.points).astype('float32')        colors = np.asarray(pcd.colors).astype('float32')                attributes = np.concatenate((points, colors),axis=1)        print("Attributes shape: " + str(attributes.shape))                return attributes.flatten()    def CreateBuffer(self, attributes):        bufferdata = (ctypes.c_float*len(attributes))(*attributes) # float buffer        buffersize = len(attributes)*4                             # buffer size in bytes         vbo = gl.glGenBuffers(1)        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, vbo)        gl.glBufferData(gl.GL_ARRAY_BUFFER, buffersize, bufferdata, gl.GL_STATIC_DRAW)         gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)        return vbo            ### NEW ###if __name__ == '__main__':    app = QtWidgets.QApplication(sys.argv)    win = MainWindow()    win.show()    sys.exit(app.exec_())但是,我仍然没有为上面的初始方法找到正确的参数,其中两个单独的 VBO 用于坐标和颜色。所以我很高兴收到进一步的评论。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python