Linux OpenGL代码失败,适用于Mac&视窗

时间:2017-09-14 18:42:10

标签: python python-2.7 wxpython pyopengl

我有一个相当复杂的基于Python的OpenGL代码,可以在Windows和Mac上正常运行,但在Linux上却出现了奇怪的带状区域。两个角度的观点: enter image description here enter image description here

以下是Mac上相同的代码图:enter image description here

问题不仅在于球体,而且这是最简单的展示方式。这个问题对OpenGL比我更有经验的人有什么建议吗?

感谢任何提示或建议。

以下是一些显示此问题的示例代码

'''Draws a sphere and axis triplet with openGL; rotates with mouse drag.
This works fine on Windows and Mac, but sphere displays strangely on Linux
'''
import sys
import math
import numpy as np
import numpy.linalg as nl
import wx
import wx.glcanvas
import OpenGL.GL as GL
import OpenGL.GLU as GLU
drawingData = {
    'oldxy' : [0, 0],
    'Quaternion' : np.array([ 0.11783419,  0.87355958,  0.09141639,  0.4633053 ]),
    'linecolors': [(np.array([[0, 0, 0], [1, 0, 0]]), [255,   0,   0]),
                   (np.array([[0, 0, 0], [0, 1, 0]]), [  0, 255,   0]),
                   (np.array([[0, 0, 0], [0, 0, 1]]), [  0,   0, 255])],
}

def Q2Mat(Q):
    ''' make rotation matrix from quaternion
    '''
    QN = Q/np.sqrt(np.sum(np.array(Q)**2))
    aa = QN[0]**2
    ab = QN[0]*QN[1]
    ac = QN[0]*QN[2]
    ad = QN[0]*QN[3]
    bb = QN[1]**2
    bc = QN[1]*QN[2]
    bd = QN[1]*QN[3]
    cc = QN[2]**2
    cd = QN[2]*QN[3]
    dd = QN[3]**2
    M = [[aa+bb-cc-dd, 2.*(bc-ad),  2.*(ac+bd)],
        [2*(ad+bc),   aa-bb+cc-dd,  2.*(cd-ab)],
        [2*(bd-ac),    2.*(ab+cd), aa-bb-cc+dd]]
    return np.array(M)

def prodQVQ(Q,V):
    """compute the quaternion vector rotation qvq-1 = v'
    """
    T2 = Q[0]*Q[1]
    T3 = Q[0]*Q[2]
    T4 = Q[0]*Q[3]
    T5 = -Q[1]*Q[1]
    T6 = Q[1]*Q[2]
    T7 = Q[1]*Q[3]
    T8 = -Q[2]*Q[2]
    T9 = Q[2]*Q[3]
    T10 = -Q[3]*Q[3]
    M = np.array([[T8+T10,T6-T4,T3+T7],[T4+T6,T5+T10,T9-T2],[T7-T3,T2+T9,T5+T8]])
    VP = 2.*np.inner(V,M)
    return VP+V

def invQ(Q):
    '''get inverse of quaternion q=r+ai+bj+ck; q* = r-ai-bj-ck
    '''
    return Q*np.array([1,-1,-1,-1])

def AVdeg2Q(A,V):
    ''' convert angle (degrees) & vector to quaternion
        q=r+ai+bj+ck
    '''
    sind = lambda x: math.sin(x*math.pi/180.)
    cosd = lambda x: math.cos(x*math.pi/180.)
    Q = np.zeros(4)
    d = nl.norm(np.array(V))
    if not A:       #== 0.!
        A = 360.
    if d:
        V = V/d
        p = A/2.
        Q[0] = cosd(p)
        Q[1:4] = V*sind(p)
    else:
        Q[3] = 1.
    return Q

def prodQQ(QA,QB):
    ''' Grassman quaternion product, QA,QB quaternions; q=r+ai+bj+ck
    '''
    D = np.zeros(4)
    D[0] = QA[0]*QB[0]-QA[1]*QB[1]-QA[2]*QB[2]-QA[3]*QB[3]
    D[1] = QA[0]*QB[1]+QA[1]*QB[0]+QA[2]*QB[3]-QA[3]*QB[2]
    D[2] = QA[0]*QB[2]-QA[1]*QB[3]+QA[2]*QB[0]+QA[3]*QB[1]
    D[3] = QA[0]*QB[3]+QA[1]*QB[2]-QA[2]*QB[1]+QA[3]*QB[0]
    return D

def RenderUnitVectors(x,y,z):
    'Show the axes'
    GL.glEnable(GL.GL_COLOR_MATERIAL)
    GL.glLineWidth(2)
    GL.glEnable(GL.GL_BLEND)
    GL.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA)
    GL.glEnable(GL.GL_LINE_SMOOTH)
    GL.glPushMatrix()
    GL.glTranslate(x,y,z)
    GL.glScalef(1,1,1)
    GL.glBegin(GL.GL_LINES)
    for line,color in drawingData['linecolors']:
            GL.glColor3ubv(color)
            GL.glVertex3fv(-line[1]/2.)
            GL.glVertex3fv(line[1]/2.)
    GL.glEnd()
    GL.glPopMatrix()
    GL.glColor4ubv([0,0,0,0])
    GL.glDisable(GL.GL_LINE_SMOOTH)
    GL.glDisable(GL.GL_BLEND)
    GL.glDisable(GL.GL_COLOR_MATERIAL)

def RenderSphere(x,y,z,radius,color):
    'show a sphere'
    GL.glMaterialfv(GL.GL_FRONT_AND_BACK,GL.GL_DIFFUSE,color)
    GL.glPushMatrix()
    GL.glTranslate(x,y,z)        
    GL.glMultMatrixf(np.eye(4).T)
    GLU.gluSphere(GLU.gluNewQuadric(),radius,20,10)
    GL.glPopMatrix()

class myGLCanvas(wx.Panel):
    def __init__(self, parent, id=-1,dpi=None,**kwargs):
        wx.Panel.__init__(self,parent,id=id,**kwargs)
        if 'win' in sys.platform:           # for Windows (& darwin==Mac) -- already double buffered
            attribs = None
        else:                               # Linux
            attribs = [wx.glcanvas.WX_GL_DOUBLEBUFFER,]
        self.canvas = wx.glcanvas.GLCanvas(self,-1,attribList=attribs,**kwargs)
        self.context = wx.glcanvas.GLContext(self.canvas)
        self.canvas.SetCurrent(self.context)
        sizer=wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas,1,wx.EXPAND)
        self.SetSizer(sizer)
        self.canvas.Bind(wx.EVT_MOTION, self.OnMouseMove)
        self.Draw()
        self.Draw()
        return

    def OnMouseMove(self,event):
        if not event.Dragging():
            drawingData['oldxy'] = list(event.GetPosition())
            return
        # Perform a rotation in x-y space
        oldxy = drawingData['oldxy']
        if not len(oldxy): oldxy = list(event.GetPosition())
        dxy = event.GetPosition()-oldxy
        drawingData['oldxy'] = list(event.GetPosition())
        V = np.array([dxy[1],dxy[0],0.])
        A = 0.25*np.sqrt(dxy[0]**2+dxy[1]**2)
        if not A: return
        # next transform vector back to xtal coordinates via inverse quaternion & make new quaternion
        Q = drawingData['Quaternion']
        V = prodQVQ(invQ(Q),np.inner(np.eye(3),V))
        Q = prodQQ(Q,AVdeg2Q(A,V))
        drawingData['Quaternion'] = Q
        self.Draw()

    def Draw(self):
        GL.glClearColor(0.,0.,0.,0.)
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
        GL.glInitNames()
        GL.glPushName(0)

        GL.glMatrixMode(GL.GL_PROJECTION)
        GL.glLoadIdentity()
        GL.glViewport(0,0,*self.canvas.GetSize())
        GLU.gluPerspective(20.,self.canvas.GetSize()[0]*1./self.canvas.GetSize()[1],7.5,12.5)
        GLU.gluLookAt(0,0,10,0,0,0,0,1,0)

        # Set Lighting            
        GL.glEnable(GL.GL_DEPTH_TEST)
        GL.glEnable(GL.GL_LIGHTING)
        GL.glEnable(GL.GL_LIGHT0)
        GL.glLightModeli(GL.GL_LIGHT_MODEL_TWO_SIDE,0)
        GL.glLightfv(GL.GL_LIGHT0,GL.GL_AMBIENT,[1,1,1,1])
        GL.glLightfv(GL.GL_LIGHT0,GL.GL_DIFFUSE,[1,1,1,1])

        GL.glMatrixMode(GL.GL_MODELVIEW)
        GL.glLoadIdentity()
        matRot = Q2Mat(drawingData['Quaternion'])
        matRot = np.concatenate((np.concatenate((matRot,[[0],[0],[0]]),axis=1),[[0,0,0,1],]),axis=0)
        GL.glMultMatrixf(matRot.T)
        GL.glMultMatrixf(np.eye(4).T)
        Tx,Ty,Tz = (0.20045985394544949, 0.44135342324377724, 0.40844172594191536)
        GL.glTranslate(-Tx,-Ty,-Tz)
        RenderUnitVectors(Tx,Ty,Tz)
        RenderSphere(0, 0, 0, 0.804, [1.,  1.,  1.])
        self.canvas.SetCurrent(self.context)
        self.canvas.SwapBuffers()

class GUI(wx.App):
    def OnInit(self):
        frame = wx.Frame(None,-1,'ball rendering',wx.DefaultPosition,wx.Size(400,400))
        frame.Show()
        wx.CallAfter(myGLCanvas,frame,size=wx.Size(400,400)) # wait for frame to be displayed
        self.MainLoop()
        return True

if __name__ == '__main__':
    GUI()

1 个答案:

答案 0 :(得分:1)

您必须通过设置WX_GL_DEPTH_SIZE,根据硬件条件指定深度缓冲区的位数。深度缓冲区的大小应为16,24或32。

attribs = [
     wx.glcanvas.WX_GL_RGBA,
     wx.glcanvas.WX_GL_DOUBLEBUFFER,
     wx.glcanvas.WX_GL_DEPTH_SIZE, 16]

另见: