python - QGLWidget无法正常初始化

标签 python opengl pyqt5 qglwidget

这是我的 QGLWidget 类,用于通过 openGL 绘制 3d 网格

class OpenGLWidget1(QGLWidget):

#def init(self,fdir,filename,swapyz=False):
    #self.fdir=fdir
    #self.filename=filename
    #self.swapyz=swapyz
    #self.initializeObj()

def initializeObj(self):

    self.vertices=[]
    self.normals=[]
    self.texcoords=[]
    self.faces=[]
    self.mtl=[self.fdir,"no_mtllib_file"]

    self.material="color0"

    for line in open(self.fdir+self.filename,"r"):
        if line.startswith('#'):continue
        values=line.split()
        if not values:continue
        if values[0] == 'v' :
            v=[float(values[1]),float(values[2]),float(values[3])]
            if self.swapyz:
                v = v[0],v[2],v[1]
            self.vertices.append(v)

        elif values[0] == 'vn':
            v=[float(values[1]),float(values[2]),float(values[3])]
            if self.swapyz:
                v = v[0],v[2],v[1]
            self.normals.append(v)

        elif values[0] == 'vt':
            v=[float(values[1]),float(values[2])]
            self.texcoords.append(v)

        elif values[0] == 'usemtl':
            self.material=values[1]

        elif values[0] == 'mtllib':
            self.mtl=[self.fdir,values[1]]

        elif values[0] == 'f':
            face=[]
            texcoords=[]
            norms=[]
            for v in values[1:]:
                w=v.split('/')
                face.append(int(w[0]))
                if len(w)>=2 and len(w[1])>0:`
                    texcoords.append(int(w[1]))
                else:
                    texcoords.append(0)
                if len(w)>=3 and len(w[2])>0:
                    norms.append(int(w[2]))
                else:
                    norms.append(0)
            self.faces.append((face,norms,texcoords,self.material))

def create_bbox(self):
    ps=np.array(self.vertices)
    vmin=ps.min(axis=0)
    vmax=ps.max(axis=0)

    self.bbox_center=(vmax+vmin)/2
    self.bbox_half_r=np.max(vmax-vmin)/2

def create_gl_list(self):
    self.mtl=MTL(*self.mtl)
    self.gl_list=glGenLists(1)
    glNewList(self.gl_list,GL_COMPILE)
    glEnable(GL_TEXTURE_2D)
    glFrontFace(GL_CCW)

    for face in self.faces:
        vertices,normals,texture_coords,material=face

        mtl=self.mtl[material]
        glColor(*mtl['kd'])

        glBegin(GL_POLYGON)
        for i in range(len(vertices)):
            if normals[i]>0:
                glNormal3fv(self.normals[normals[i]-1])
            if texture_coords[i]>0:
                glTexCoord2fv(self.texcoords[texture_coords[i]-1])
            glVertex3fv(self.vertices[vertices[i]-1])
        glEnd()

    glDisable(GL_TEXTURE_2D)
    glEndList()

def initializeGL(self):
    self.fdir = "/home/pczebra/pig9/outModel/"
    self.filename = "model101_out.obj"
    self.swapyz = True
    self.initializeObj()
    glViewport(0, 0, self.geometry().width(), self.geometry().height())
    self.create_bbox()
    light.setup_lighting()
    glLightfv(GL_LIGHT0,GL_POSITION,(0,0,-1000,0.0))
    glEnable(GL_DEPTH_TEST)
    glShadeModel(GL_SMOOTH)
    self.create_gl_list()
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    cam=light.camera
    cam.Ortho.bbox[:]=cam.Ortho.bbox * 13
    cam.Ortho.nf[:]=cam.Ortho.nf * 20
    glOrtho(*cam.Ortho.params)
    glEnable(GL_DEPTH_TEST)
    glMatrixMode(GL_MODELVIEW)

    self.rx,self.ry=(0,0)
    self.tx,self.ty=(0,0)
    self.zpos=5




def paintGL(self):

    #glViewport(0,0,self.geometry().width(),self.geometry().height())
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()

    glTranslate(self.tx/20. , self.ty/20. , - self.zpos)
    glRotate(self.ry/5,1,0,0)
    glRotate(self.rx/5,0,0,1)

    s=[10/self.bbox_half_r]*3
    glScale(*s)

    t=-self.bbox_center
    glTranslate(*t)

    glCallList(self.gl_list)


def resizeGL(self, width, height):
    glViewport(0,0,width,height)

def mousePressEvent(self, QMouseEvent):
    if Qt.LeftButton == QMouseEvent.button():
        self.lastPos=QMouseEvent.pos()
    if Qt.RightButton == QMouseEvent.button():
        self.lastPos=QMouseEvent.pos()

def mouseMoveEvent(self, QMouseEvent):
    if QMouseEvent.buttons() and Qt.LeftButton:
        a=QMouseEvent.pos()
        dx=a.x()-self.lastPos.x()
        dy=a.y()-self.lastPos.y()

        dx=dx/2
        dy=dy/2

        self.rx -=dx
        self.ry -=dy

        self.updateGL()

    if QMouseEvent.buttons() and Qt.RightButton:
        a=QMouseEvent.pos()
        dx = a.x() - self.lastPos.x()
        dy = a.y() - self.lastPos.y()

        dx = dx / 2
        dy = dy / 20

        self.tx += dx
        self.ty -= dy

        self.updateGL()
    self.lastPos=QMouseEvent.pos()

然后我在 pyqt 中有两个 QGLWidgets,以实例化类

def w1(self):
    self.glWidget = OpenGLWidget1(self)
    self.glWidget.setGeometry(QRect(30, 540, 651, 401))
    self.glWidget.show()
def w2(self):
    self.glWidget_raw = OpenGLWidget1(self)
    #self.glWidget_raw.init(fdir,filename, swapyz=True)
    self.glWidget_raw.setGeometry(QRect(30, 50, 651, 401))
    self.glWidget_raw.show()
def visualization(self, checked):
    self.w1()
    self.w2()

并显示

image of runing result

第二个QGLWidget和后面的QGLWidget总是gl size出问题,反正不能正常显示!我该如何解决这个问题。

最佳答案

大多数此类扩展问题都归结为未遵循最佳实践。由于某些原因,几乎所有关于 OpenGL 的早期教程,在 OpenGL 本身还很新的时候编写,都将设置视口(viewport)大小和设置投影矩阵放在 reshape 处理程序中。同样在初始化代码中做了很多事情,实际上属于显示代码。

这些教程并没有受到影响,因为这些教程是完全独立的,不需要与更大的程序交互。您使用的是 Qt 框架,它在内部利用 OpenGL 来绘制东西。因此,您必须准备好接受这一点。

以下是使用 OpenGL 的基本规则:

  • 初始化代码:将只执行不会对生成的图像产生任何可观察到的影响的操作。任何影响渲染过程的数据流的东西,即渲染管线状态不应该在初始化代码中设置。 在初始化代码中要做的事情是加载 Assets ,即模型、纹理,以及(在您的情况下)设置显示列表¹。

  • 渲染目标 reshape 代码:像初始化代码一样,这不应该做任何影响实际渲染数据流的事情。您使用它来初始化资源,这些参数取决于渲染目标的大小和位置。 视口(viewport)和剪刀矩形不是渲染目标参数的一部分! 渲染目标 reshape 代码中要做的事情是分配帧缓冲区对象和他们的技术 Render Bufferstarget textures

  • 适当的绘图代码:大量的图形 API 操作应该放在这里。典型的操作顺序是:

    1. 选择渲染目标
    2. 设置视口(viewport)并清除
    3. 绑定(bind)保存绘图数据的缓冲区
    4. 设置渲染管道状态(深度测试、着色器、纹理等)
    5. 画东西
    6. 完成绘图

    请注意,在渲染单个图像的过程中,这些步骤中的每一个都可能发生多次,以上只是粗略的概述。此外,顺序可能会发生变化,例如,对于一组给定的绘图数据,可能会渲染多个视口(viewport),因此上述顺序并不是一成不变的。这取决于您的应用。

无论如何,您的程序代码到处都是绘图代码,这很可能是您问题的很大一部分。


1:旁注:哇,显示列表,好吧,这是过去的风潮。我的意思是,显示列表曾经是一种很酷的、大规模加速的东西,我们通过 X11-over-TCP 进行远程渲染。但这已经过时了——什么——大约 15 年左右。不要使用它。也不要使用 GL_POLYGON。您的数据显然是一个三角形列表(可能还有一些四边形),所以只需将它们按顺序放入一个数组中,将其加载到一个顶点数组中并调用 glDrawArrays那。 20 多年来你就应该这样做。 不要遵循已经过时将近四分之一个世纪的编程模型!

关于python - QGLWidget无法正常初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53094672/

相关文章:

opengl - 在 OpenGL 中检测鼠标位置/点击对象的最佳方法是什么?

c++ - 初学者 openGL 项目渲染三角形的问题

python - 如何更新作为类创建的 PyQt5 选项卡之间的值

python - 如何比较二维分布?

python - 使用 CDLL lib(或其他)在 Debian 64 位上使用 python 访问 32 位

python - 如何以这种方式打印字符串

c++ - opengl c++ 中的边界填充算法

python - QSqlQuery中isValid()的解释

python - 更改 QTableWidget 单个单元格的可编辑性

python - 我如何从 python 程序而不是代理中找到面向公众的 ip