我有一個相當複雜的基於Python的OpenGL代碼,可以在Windows和Mac上正常運行,但在Linux上出現奇怪的帶狀區域失敗。從兩個角度的觀點: Linux OpenGL代碼失敗,適用於Mac和Windows
的問題不僅與球,但是這是展現最容易的事情。這個問題是否對任何擁有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()
請讀[如何創建吃了一個最小,完整和可驗證的例子](https://stackoverflow.com/help/mcve)。 – Rabbid76
它看起來像深度緩衝區的問題,但你必須更具體。你使用幀緩衝區?你如何繪製場景(源代碼)? – Rabbid76
創建了一個縮短的代碼來說明問題。在Linux上還未完全測試(在我進行旋轉調試之前顯示問題)。 FWIW,通過在Mac上打開WX_GL_DOUBLEBUFFER,我可以看到類似於Linux問題的東西。 – bht