PyOpenGL:使用gluLookup和gluPerspective很难

时间:2014-11-28 00:43:05

标签: python opengl bioinformatics pyopengl

我正在尝试编写一个程序,该程序接受蛋白质中一组原子的x,y,z坐标,这些原子都被标准化为[0,1]范围。然而,在这样做时,我在绘制点时非常困难,因此它们看起来是“三维的”。也就是说,我可以使用glVertex3fv为每个点提供所有三个坐标而没有太多麻烦来绘制点,但我尝试使用gluPerspective和gluLookAt来适当地构图相机已经令人沮丧,我一直无法找到任何资源在线解释原因。

我已经为gluPerspective指定了使用50.0视角的参数,以及1:1的宽高比。我已经将minZ和maxZ参数指定为-1和1,它应该包含我的数据点的宽度,因为它们是从[0,1]标准化的,如上所述。评论gluPerspective显示了在“2d”空间中绘制的点 - 尽管如果我的理解是正确的,它们是三维绘制的。取消注释gluPerspective会使窗口变为空白。

gluLookAt似乎绝对没有做任何事,无论我传递什么参数。

我正在使用PyOpenGL,它只是OpenGL for Python的包装器。这允许我使用OpenGL和一些特定于python的库 - 在本例中是ProDy(用于解析/获取/操作蛋白质数据文件的库)。

我正在使用Python 2.7和OpenGL 3.1 build 9.17.10.3517。

我的程序从PDB中获取蛋白质文件,解析它,获取蛋白质中每个原子的坐标,对它们进行标准化,并将坐标绘制到屏幕上。

这是我的代码:

import OpenGL 
from prody import *
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

#create initial window parameters
width = 500
height = 500
#fetch PDB data
id = "1cwa"
filename = fetchPDB(id)
atoms = parsePDB(filename)
coords = atoms.getCoords()

#max/mins

class Stats(object):
    maxX = coords[0][0]
    maxY = coords[0][1]
    maxZ = coords[0][2]
    minX = maxX-1
    minY = maxY-1
    minZ = maxZ-1
    meanX = 0
    meanY = 0
    meanZ = 0

def Scale():
#find max and min for each range
    for a in coords:
        #print(a[2])
        if(a[0] < Stats.minX):
            Stats.minX = a[0]
        elif(a[0] > Stats.maxX):
            Stats.maxX = a[0]
        if(a[1] < Stats.minY):
            Stats.minY = a[1]
        elif(a[1] > Stats.maxY):
            Stats.maxY = a[1]
        if(a[2] < Stats.minZ):
            Stats.minZ = a[2]
        elif(a[2] > Stats.maxZ):
            Stats.maxZ = a[2]
    #multiply projection matrix
    quoX = Stats.maxX - Stats.minX
    quoY = Stats.maxY - Stats.minY
    quoZ = Stats.maxZ - Stats.minZ
    quoN = max(quoZ,max(quoX,quoY))
    Stats.meanX = (Stats.maxX + Stats.minX)/2
    Stats.meanY = (Stats.maxY + Stats.minY)/2
    Stats.meanZ = (Stats.maxZ + Stats.minZ)/2
    for a in coords:
        a[0] = (a[0]-Stats.minX)/(quoN)
        print(a[0])
        a[1] = (a[1]-Stats.minY)/(quoN)
        print(a[1])
        a[2] = (a[2]-Stats.minZ)/(quoN)
        print(a[2])


def drawAtom(atom):
    x = atom[0]
    y = atom[1]
    z = atom[2]
    glBegin(GL_POINTS)
    #glVertex2f(x,y)
    glVertex3fv(atom)
    glEnd()  

def draw():
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    glEnable(GL_DEPTH_TEST)
    glPointSize(7)
    for atom in coords:
        drawAtom(atom)
        glutSwapBuffers()

def init():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
    glutInitWindowPosition(0, 0)
    glutInitWindowSize(width,height)
    glutCreateWindow(b"CycloVis")
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glEnable(GL_DEPTH_TEST)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    Scale()
    #gluPerspective(50.0,1.0,-1,1)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(1,1,5,Stats.minZ,Stats.meanZ,Stats.maxZ,9999999,1,1)
    glColor3d(1.0, 0.0, 1.0)
    glutDisplayFunc(draw)

if __name__ == '__main__':

#initialize
    init()

    if "-vers" in sys.argv:
        print ("GL_VERSION    = ", glGetString(GL_VERSION))

    glutMainLoop()

1 个答案:

答案 0 :(得分:0)

gluLookAt不会重新调整您的观看量。它将平移和旋转您的所有点,但要扩展所需的一切投影矩阵。当您将对gluPerspective的通话注释掉时,观看音量会在所有方向上从[ -1 1 ]延伸(因为投影矩阵是一个单位矩阵)。我想你已经发现当你将gluPerspective gluLookAt注释掉你的一组规范化数据点时([ 0 < / strong>, 1 ])填充大约1/4的视口(右上角)?

现在,至于gluLookAt搞砸了,这也很容易解释。您在问题中显示的代码使用上述[ -1 1 ]查看量(标准化设备坐标)。 gluLookAt将旋转并转换您的点,但它们仍然必须位于您的“视点”(前三个坐标传递到gluLookAt)的+/- 1个单位内才能看到。当您使用 1 1 5 作为您的观点时,绝对不是这种情况。您的规范化数据点均不在z = [ 4 6 ]范围内。

这可能会为您的数据集产生更好的结果:

gluLookAt(0.5,0.5,0.0, 0.5,0.5,1.0, 0.0,1.0,0.0)

将相机置于[ 0 1 ] X,Y范围中间,并将最近的点定位在近剪裁平面上。它向下看正Z轴并且Y轴朝上。