我正在开发一种软件,其中使用glSelect
在pyqt5
GUI中的鼠标单击事件上选择对象。
这是可以正常工作的代码。
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from PyQt5.QtCore import QSize, Qt
from math import *
from PyQt5 import QtCore, QtGui, QtWidgets
class MyGL(QtWidgets.QOpenGLWidget):
def __init__(self, *args):
super().__init__(*args)
self.ratio = 1
self.width, self.height = 1, 1
self.coord = [
[0,0,0], [1,0,0], [2,0,0],
[0,1,0], [1,1,0], [2,1,0],
[0,2,0], [1,2,0], [2,2,0]
]
self.radialD, self.xzAngle, self.xAngle = 30, 0, 90
self.xCam = self.radialD*cos(self.xzAngle*pi/180)*cos(self.xAngle*pi/180)
self.yCam = self.radialD*sin(self.xzAngle*pi/180)
self.zCam = self.radialD*cos(self.xzAngle*pi/180)*sin(self.xAngle*pi/180)
def initializeGL(self):
self.setFocusPolicy(Qt.StrongFocus)
glutInit()
def resizeGL(self, w, h):
if h==0:
h=1
self.ratio = w * 1.0 / h
self.width, self.height = w, h
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glViewport(0, 0, w, h)
gluPerspective(45.0, self.ratio, 0.1, 100.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# glClearDepth(1)
glLoadIdentity()
glClearColor(1.0,1.0,1.0,1.0)
self.xCam = self.radialD*cos(self.xzAngle*pi/180)*cos(self.xAngle*pi/180)
self.yCam = self.radialD*sin(self.xzAngle*pi/180)
self.zCam = self.radialD*cos(self.xzAngle*pi/180)*sin(self.xAngle*pi/180)
gluLookAt(self.xCam, self.yCam, self.zCam, 0, 0, 0, 0.0, 1.0, 0.0)
self.draw(GL_RENDER)
def draw(self, mode):
i=1
for p in self.coord:
glColor3f(0,0,0)
glPushMatrix()
glTranslatef(p[0], p[1], p[2])
if mode == GL_SELECT:
glLoadName(i)
i+=1
glutSolidSphere(0.1, 30, 30)
glPopMatrix()
def mousePressEvent(self, event):
self.makeCurrent()
viewport = glGetIntegerv(GL_VIEWPORT)
selectBuf = glSelectBuffer(100)
glRenderMode(GL_SELECT)
glInitNames()
glPushName(-1)
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
gluPickMatrix( event.x(), (viewport[3] - event.y()), 50.0, 50.0, viewport)
gluPerspective(45.0, self.ratio, 0.1, 100.0)
self.draw(GL_SELECT)
glPopMatrix()
glFlush()
hits = glRenderMode(GL_RENDER)
for x in hits:
print(x.names)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
self.doneCurrent()
self.update()
def mouseReleaseEvent(self, event):
self.update()
def keyPressEvent(self, event):
if event.key() == Qt.Key_Down:
self.xzAngle -= 1
if self.xzAngle < 0:
self.xzAngle = 359
if event.key() == Qt.Key_Up:
self.xzAngle += 1
if self.xzAngle > 360:
self.xzAngle = 1
if event.key() == Qt.Key_Left:
self.xAngle += 1
if self.xAngle > 360:
self.xAngle = 1
if event.key() == Qt.Key_Right:
self.xAngle -= 1
if self.xAngle < 0:
self.xAngle = 359
if event.key() == Qt.Key_Plus:
self.radialD -= 0.3
if event.key() == Qt.Key_Plus:
self.radialD += 0.3
self.update()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(400, 300)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralWidget)
self.verticalLayout.setContentsMargins(11, 11, 11, 11)
self.verticalLayout.setSpacing(6)
self.verticalLayout.setObjectName("verticalLayout")
self.openGLWidget = MyGL(self.centralWidget)
self.openGLWidget.setObjectName("openGLWidget")
self.verticalLayout.addWidget(self.openGLWidget)
MainWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
但是当我移动相机时,它停止工作。问题在于,由于选择在 Projection Matrix 中起作用,并且未考虑 ModelView Matrix ,即未考虑旋转,角度移动,因此对象仍处于原始位置。
我已经在 ModelView矩阵中进行了尝试,但是在这种情况下,甚至在进行任何转换之前它都无法正常工作。
请任何人都可以告诉我该怎么办,以便即使在相机移动或进行任何其他转换后它也能正常工作?
答案 0 :(得分:0)
绘制模型时,请确保已设置矩阵模式GL_MODELVIEW
:
df %>%
arrange(species,scenario) %>% group_by(species) %>%
mutate(diff1=amount-lag(amount)) %>%
filter(diff1>0)
df %>%
arrange(species,scenario) %>% group_by(species) %>%
mutate(diff1=amount-lag(amount)) %>%
mutate(diff.incr=ifelse(diff1>0,'increase','no increase'))
gluPickMatrix
区域的选择参数似乎很大。减少它(例如10);
def draw(self, mode):
for i, p in enumerate(self.coord):
glMatrixMode(GL_MODELVIEW) # <------
glPushMatrix()
glTranslatef(p[0], p[1], p[2])
if mode == GL_SELECT:
glLoadName(i+1)
glColor3f(0,0,0)
glutSolidSphere(0.1, 30, 30)
glPopMatrix()
必须在两个模型(GL_RENDER
/GL_SELECT
)中使用相同的模型视图矩阵和投影矩阵来绘制模型。创建一个将投影矩阵相乘的函数:
gluPickMatrix(event.x(), viewport[3] - event.y(), 10.0, 10.0, viewport)
和清除视图矩阵的方法:
def setProjection(self):
gluPerspective(45.0, self.ratio, 0.1, 100.0)
由于将gluPickMatrix
与当前矩阵相乘,因此在调用def setView(self):
glLoadIdentity()
self.xCam = self.radialD*cos(self.xzAngle*pi/180)*cos(self.xAngle*pi/180)
self.yCam = self.radialD*sin(self.xzAngle*pi/180)
self.zCam = self.radialD*cos(self.xzAngle*pi/180)*sin(self.xAngle*pi/180)
gluLookAt(self.xCam, self.yCam, self.zCam, 0, 0, 0, 0.0, 1.0, 0.0)
之前,请设置模式GL_PROJECTION
并清除当前矩阵。在调用gluPickMatrix
之后,将投影矩阵(setProjection
)相乘并设置视图矩阵(setView
):
gluPickMatrix
def mousePressEvent(self, event):
self.makeCurrent()
# store and cleare projection matrix
glMatrixMode(GL_PROJECTION)
glPushMatrix()
glLoadIdentity()
# s4t render mode and pick matrix
selectBuf = glSelectBuffer(100)
glRenderMode(GL_SELECT)
glInitNames()
glPushName(-1)
viewport = glGetIntegerv(GL_VIEWPORT)
gluPickMatrix(event.x(), viewport[3] - event.y(), 10.0, 10.0, viewport)
# multiply projection matrix
self.setProjection()
# store and set current view matrix
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
self.setView()
# draw
self.draw(GL_SELECT)
# restore current matrices
glMatrixMode(GL_PROJECTION)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)
glPopMatrix()
glFlush()
hits = glRenderMode(GL_RENDER)
if hits:
print([x.names for x in hits])
self.doneCurrent()
类:
MyGL