2017-09-14 88 views
1

我有一個相當複雜的基於Python的OpenGL代碼,可以在Windows和Mac上正常運行,但在Linux上出現奇怪的帶狀區域失敗。從兩個角度的觀點: enter image description hereenter image description hereLinux OpenGL代碼失敗,適用於Mac和Windows

下面是在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() 
+0

請讀[如何創建吃了一個最小,完整和可驗證的例子](https://stackoverflow.com/help/mcve)。 – Rabbid76

+0

它看起來像深度緩衝區的問題,但你必須更具體。你使用幀緩衝區?你如何繪製場景(源代碼)? – Rabbid76

+0

創建了一個縮短的代碼來說明問題。在Linux上還未完全測試(在我進行旋轉調試之前顯示問題)。 FWIW,通過在Mac上打開WX_GL_DOUBLEBUFFER,我可以看到類似於Linux問題的東西。 – bht

回答

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] 

參見:

+1

這確實是個問題!由於我想在不同的硬件上支持wx 2.8和不同的緩衝區深度,因此我將wx.glcanvas.GLCanvas和wx.glcanvas.GLContext調用放在try/except塊內的一個循環中,然後嘗試32,24和16位。 – bht

相關問題