2017-09-14 87 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

相关问题