pczebra
pczebra

Reputation: 21

QGLWidget can't be initialized normally

here is my QGLWidget class for drawing 3d meshes by openGL

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()

then i have two QGLWidgets in pyqt, to instant the class

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()

and show

image of runing result

the second QGLWidget and the later QGLWidget always has trouble with gl size, they can not show normally anyway! How can i fix the problem.

Upvotes: 2

Views: 175

Answers (1)

datenwolf
datenwolf

Reputation: 162164

Most of such scaling problems come down to not following best practices. For some reasons, practically all early tutorials on OpenGL, written when OpenGL itself was fairly new, placed setting the viewport size and setting the projection matrix in the reshape handler. Similarly a lot of stuff was done in the initialization code, which actually belongs into the display code.

These tutorials got away with that, because these tutorials were entirely self contained and didn't have to interact with a larger program. You're using the Qt framework, which internally also makes use of OpenGL do draw stuff. So you have to be prepared to live with that.

Here are the basic rules for living with OpenGL:

  • Initialization code: will do only things that will not have any observable effect on the generated image. Anything that influences the data flow of the rendering process, i.e. render pipeline state should not be set in initialization code. Things to do in initialization code would be loading assets, i.e. models, textures and – in your case – setting up display lists¹.

  • render target reshape code: Like initialization code this should not do anything that influences the actual rendering data flow. You use it to initialize resources, which parameters depend on the size and location of the render target. The viewport and the scissor rectangle are not part of the render target parameters! Things to do in render target reshape code is allocating Framebuffer Objects and their attechment Render Buffers or target textures.

  • drawing code proper: The bulk of graphics API operations should be placed here. The typical order of operations is:

    1. select render target
    2. set viewport & clear
    3. bind the buffers holding the drawing data
    4. set render pipeline state (depth testing, shaders, textures etc.)
    5. draw stuff
    6. finish drawing

    Note that each of these steps may happen several times throughout rendering a single image, the above is just the rough outline. Also the order may change, for example for a given set of drawing data multiple viewports may be rendered to, so the above ordering is not set in stone. It depends on your application.

Anyway, your program code as things that are considered drawing code all over the place, and that's likely a huge part of your problem.


1: On a side note: Whoa, display lists, well that's a blast from the past. I mean, display lists used to be kind of cool, massively accelerated things, wenn doing remote rendering though X11-over-TCP. But that's been out of fashion for now – what – something like 15 years or so. Don't use it. Also don't use GL_POLYGON. Your data obviously is a list of triangles (and maybe some quads), so just put them into an array, in order, load that into a vertex array and call glDrawArrays on that. That's how you're supposed to do it for over 20 years. Don't follow a programming model, that's been outdated for almost the quarter of a century!

Upvotes: 1

Related Questions