pyQt5 中的 pyOpenGL - 点云渲染中的相机位置
pyOpenGL in pyQt5 - camera position in point cloud rendering
这是我在 Whosebug 上的第一个问题,对于任何错误,我深表歉意,但我现在不知道如何处理我的问题。我正在编写一个在 pyQt5 中使用 OpenGl 渲染点云的应用程序。我可以使用 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)
但是如何改变...请帮助我!
您在视口上看到的是 3 维观看体积的投影。
投影矩阵定义了投影到视口上的观察者(观察者)的面积(体积)。
在您的情况下,您使用 Orthographic projection。在正交投影中,该区域(体积)由到观察者位置的 6 个距离(左、右、下、上、近和远)定义。 space(体积)中的所有对象(点)在视口上都是 "visible"。 space 之外的所有对象(点)都在体积的边界处被剪裁。
[...] but the only way to see points is by normalizing its coordinates to -0.5 - 0.5 values [...]
其实你做错了。您更改顶点坐标(点)的比例,而不是扩大查看体积。
正射投影可以通过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
) 并定义一个正交投影,它定义了一个长方体体积,该体积足够大以包含与其方向无关的所有点 (Euclidean distance):
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)
计算边界框的中心并定义相反方向的初始平移。翻译必须 "move" 点云的中心到世界的原点:
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
and 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)
# [...]
这是我在 Whosebug 上的第一个问题,对于任何错误,我深表歉意,但我现在不知道如何处理我的问题。我正在编写一个在 pyQt5 中使用 OpenGl 渲染点云的应用程序。我可以使用 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)
但是如何改变...请帮助我!
您在视口上看到的是 3 维观看体积的投影。
投影矩阵定义了投影到视口上的观察者(观察者)的面积(体积)。
在您的情况下,您使用 Orthographic projection。在正交投影中,该区域(体积)由到观察者位置的 6 个距离(左、右、下、上、近和远)定义。 space(体积)中的所有对象(点)在视口上都是 "visible"。 space 之外的所有对象(点)都在体积的边界处被剪裁。
[...] but the only way to see points is by normalizing its coordinates to -0.5 - 0.5 values [...]
其实你做错了。您更改顶点坐标(点)的比例,而不是扩大查看体积。
正射投影可以通过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
) 并定义一个正交投影,它定义了一个长方体体积,该体积足够大以包含与其方向无关的所有点 (Euclidean distance):
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)
计算边界框的中心并定义相反方向的初始平移。翻译必须 "move" 点云的中心到世界的原点:
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
and 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)
# [...]