pyOpenGL in pyQt5 - положение камеры при рендеринге облака точек - PullRequest
1 голос
/ 13 апреля 2020

Это мой первый вопрос о переполнении стека, так что извините за любые ошибки, но я сейчас не знаю, как справиться с моей проблемой. Я пишу приложение, которое визуализирует облако точек с использованием OpenGl в pyQt5. Я могу отрисовать все точки, используя VBO, но единственный способ увидеть точки - нормализовать их координаты до значений -0,5 - 0,5. Не могли бы вы помочь мне с этим справиться?

Это мой код:

def initializeGL(self):
    self.setClearColor(self.backgroundColor)
    self.object = self.makeDefaultObject()
    if not self.drawDefaultData and self.pts.size == 0: self.pts = default.pointCloud
    gl.glShadeModel(gl.GL_FLAT)
    gl.glEnable(gl.GL_DEPTH_TEST)
    gl.glEnable(gl.GL_CULL_FACE)
    self.reloadPoints()
def reloadPoints(self):
    if self.pts.size == 0:
        self.pts = default.pointCloud 
    self.vbo_disp, self.vbo_disp_clr, self.disp_count = self.loadVBO()
    self.xPos = -np.mean(self.pts, axis=0)[0]
    self.yPos = np.mean(self.pts, axis=0)[1]
    self.zPos = np.min(self.pts, axis=0)[2] -10
def paintGL(self):
    gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
    gl.glLoadIdentity()
    gl.glTranslated(self.xPos, self.yPos, self.zPos)
    gl.glScaled(self.zoomScale, self.zoomScale, self.zoomScale)
    gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)
    gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
    gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
    gl.glCallList(self.object)
    if self.pts.size != 0: self.drawPointCloud()
def resizeGL(self, width, height):
    side = min(width, height)
    if side < 0:
        return

    gl.glViewport((width - side) // 2, (height - side) // 2, side,
                  side)

    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.glLoadIdentity()
    gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0)
    gl.glMatrixMode(gl.GL_MODELVIEW)
def drawPointCloud(self):
    gl.glPushMatrix()
    gl.glPointSize(self.pointSize)   
    glEnableClientState(gl.GL_VERTEX_ARRAY)
    glEnableClientState(gl.GL_COLOR_ARRAY)

    vtx_disp = self.vbo_disp[0]
    clr_disp = self.vbo_disp_clr[0]
    cnt_disp = self.disp_count[0]

    vtx_disp.bind()
    gl.glVertexPointer(3, gl.GL_FLOAT, 0, vtx_disp)
    vtx_disp.unbind()

    clr_disp.bind()
    gl.glColorPointer(3, gl.GL_FLOAT, 0, clr_disp)
    clr_disp.unbind()

    gl.glDrawArrays(gl.GL_POINTS, 0, cnt_disp)

    glDisableClientState(gl.GL_VERTEX_ARRAY)
    glDisableClientState(gl.GL_COLOR_ARRAY)

    gl.glPopMatrix()
def loadVBO(self):
    vtx_list = [ [] for _ in range(1) ]
    clr_list = [ [] for _ in range(1) ]        
    vtx_count = np.zeros( 1, dtype=np.int32 ) 

    vtx_count[0] = len(self.pts)
    vtx_list[0] = qlVBO.VBO( self.pts[:,:3].copy().astype(np.float32) )
    if (np.size(self.pts, 1) == 6):
        clr_list[0] = qlVBO.VBO( self.pts[:,3:].copy().astype(np.float32) / 255.0 )
    elif (np.size(self.pts, 1) == 3):
        clr_list[0] = qlVBO.VBO( np.ones([vtx_count[0],3]).astype(np.float32) )
    else:
        print("Internal error")
    vtx_count[0] = len(self.pts)

    return vtx_list, clr_list, vtx_count

Я пытался изменить положение камеры, но безрезультатно. На мой взгляд, проблема в:

gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0)

Но как это изменить ... Пожалуйста, помогите мне с этим!

1 Ответ

0 голосов
/ 13 апреля 2020

То, что вы видите в окне просмотра, является проекцией трехмерного объема просмотра. Матрица проекции определяет область (объем) относительно наблюдателя (зрителя), который проецируется на область просмотра.
В вашем случае вы используете проекцию Orthographi c . В проекции orthographi c эта область (объем) определяется 6 расстояниями (слева, справа, снизу, сверху, близко и далеко) к позиции зрителя. Все объекты (точки), находящиеся в пространстве (объеме), «видны» в области просмотра. Все объекты (точки), находящиеся вне этого пространства, обрезаются по границам объема.

[...], но единственный способ увидеть точки - нормализовать их координаты до -0,5. - 0,5 значения [...]

На самом деле вы делаете это неправильно. Вы изменяете масштаб координат вершин (точек), а не расширяете объем просмотра.
Проекция orthographi c может быть установлена ​​с помощью glOrtho:

gl.glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0)

Эта настройка определяет кубоидный объем с левым, нижним, около od (-0,5, -0,5, 4,0) и правым, верхним, далеко (0,5, 0,5, 15,0).
Увеличение этот объем, а не масштабирование координат:

gl.glOrtho(min_x, max_x, max_y, min_y, min_z, max_z)

Я рекомендую сделать следующее:

Вычислить ограничивающий прямоугольник, ограниченный осью облака точек, из (self.min_x , self._min_y, self.min_z) до (self.max_x, self._max_y, self.max_z) и определите проекцию orthgrphi c, которая определяет объем кубоида, достаточно большой, чтобы охватить все точки независимо от его ориентации ( Евклидово расстояние ):

ef resizeGL(self, width, height):
    side = min(width, height)
    if side < 0:
        return
    gl.glViewport((width - side) // 2, (height - side) // 2, side, side)

    dx = self.max_x - self.min_x
    dy = self.max_y - self.min_y
    dz = self.max_z - self.min_z
    dia = math.sqrt(dx*dx + dy*dy + dz*dz)

    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.glLoadIdentity()
    gl.glOrtho(-dia/2, dia/2, dia/2, -dia/2, -dia/2, dia/2)
    gl.glMatrixMode(gl.GL_MODELVIEW)

Вычислить центр ограничительной рамки и определить начальный перевод в противоположном направлении. Перевод должен «переместить» центр облака точек к источнику мира:

self.center_x = (self.min_x + self.max_x) / 2
self.center_y = (self.min_y + self.max_y) / 2
self.center_z = (self.min_z + self.max_z) / 2
self.xPos = 0
self.yPos = 0
self.zPos = 0

Объем просмотра достаточно велик, поэтому нет необходимости масштабировать точки (self.zoomScale = 1). Важно сначала масштабировать облако точек, затем перевести его и окончательно повернуть, поэтому ось вращения является центром облака точек:

modelview = translate * rotation * scale * translateToOrigin 

Операции преобразования матрицы, такие как glRotate, glScale и glTranslate, определяют новую матрицу и умножают текущую матрицу на новую матрицу. Следовательно, порядок операций должен быть 1. glTranslate 2. glRotate, 3. glScale, 4. glTranslate(-center),:

def paintGL(self):
    gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
    gl.glLoadIdentity()

    gl.glTranslated(self.xPos, self.yPos, self.zPos)

    gl.glRotated(self.zRot / 16.0, 0.0, 0.0, 1.0)
    gl.glRotated(self.yRot / 16.0, 0.0, 1.0, 0.0)
    gl.glRotated(self.xRot / 16.0, 1.0, 0.0, 0.0)

    gl.glScaled(self.zoomScale, self.zoomScale, self.zoomScale)

    gl.glTranslated(-self.center_x, -self.center_y, -self.center_z)

    # [...]
...