PyOpenGL: gluLookAt behaviour?

734 views Asked by At

I am trying to get different perspectives in 3D on a OpenGL window.

If you run the code (with anything to do with gluLookAt commented out) and left click the red line point at the place you clicked, right click and the green line aligns to where you clicked. All happens in the xy plane with z=0.0, also it wont let you pick any -ve y values (that's deliberate).

I am trying to pan around the scene using 'x', 'y' & 'z' keys. The first thing I tried was changing the values for where the 'eye' is situated. It has been nothing but a complete disaster!!

No matter how many times I read what gluLookAt is supposed to do, I can never make it do it!

In the code that follows I am trying to set the view at 10 units in the z direction away from the origin, look towards the origin along the z axis.

I just get a black screen (if I leave out anything to do with gluLookAt it looks like https://i.stack.imgur.com/ATsJO.png )

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import numpy as np
import sys

global lp, lq, rp, rq, z, eyeX, eyeY, eyeZ
lp = 0.0
lq = 2.5
rp = 0.0
rq = 2.5
z = 0.0

# gluLookAt 'eye' coordinates
eyeX = 0.0 
eyeY = 0.0
eyeZ = 10.0

def init():
    global eyeX, eyeY, eyeZ
    glClearColor(0.0, 0.0, 0.0, 1.0)
    glOrtho(-10.0, 10.0, -10.0, 10.0, -10.0, 10.0)
    glClear(GL_COLOR_BUFFER_BIT)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(eyeX, eyeY, eyeZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)

def plotdial():
    global lp, lq, rp, rq, eyeX, eyeY, eyeZ
    #lOrigin = np.array((0.0, 0.0, 0.0))
    rOrigin = np.array((5.0, 0.0, 0.0))
    radius = 2.5

    glClear(GL_COLOR_BUFFER_BIT)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    gluLookAt(eyeX, eyeY, eyeZ, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)  

    # Left arm unit vector calculation
    lVec =  np.array((lp, lq, z))
    lMag = np.linalg.norm(lVec)
    lVec = (lVec/lMag)*radius
    glColor3f(1.0, 0.0, 0.0)
    glLineWidth(3.0)
    glBegin(GL_LINES)
    glVertex3f(0.0, 0.0, z)
    glVertex3f(lVec[0], lVec[1], z)
    glEnd()
    glLineWidth(1.0)
    glColor3f(0.0, 0.0, 1.0)
    glutWireSphere(2.5, 25, 25)

    # Right 
    glPushMatrix()
    glTranslatef(rOrigin[0], rOrigin[1], z)
    glColor3f(0.0, 1.0, 0.0)
    glLineWidth(3.0)
    glBegin(GL_LINES)
    glVertex3f(0.0, 0.0, z)
    rVec =  np.array((rp, rq, z))
    rMag = np.linalg.norm(rVec)
    rVec = (rVec/rMag)*radius 
    glVertex3f(rVec[0], rVec[1], z)
    glEnd()
    glLineWidth(1.0)
    glColor3f(0.0, 0.0, 1.0)
    glutWireSphere(2.5, 25, 25)
    glPopMatrix()

    glFlush()

def keyboard(key, x, y):
    global glutshape, solid, eyeX, eyeY, eyeZ
    step = 0.01
    if key == chr(27) or key == "q":
        sys.exit()
    if key == "x":
        eyeX -= step
    if key == "X":
        eyeX += step
    if key == "y":
        eyeY -= step
    if key == "Y":
        eyeY += step
    if key == "z":
        eyeZ -= step
    if key == "Z":
        eyeZ -= step
    glutPostRedisplay()

def mouse(button, state, x, y):
    global lp, lq, rp, rq
    o_lp = lp    
    o_lq = lq
    o_rp = rp
    o_rq = rq
    if button == GLUT_LEFT_BUTTON and state == GLUT_DOWN:
        lp = -10.0 + x/500.0 * 20
        lq = 10 - y/500.0 * 20   
        if lq < 0.0:
            lp = o_lp
            lq = o_lq
    if button == GLUT_RIGHT_BUTTON and state == GLUT_DOWN:
        rp = -10.0 + x/500.0 * 20 - 5 # -5 is 2*radius
        rq = 10 - y/500.0 * 20 
        if rq < 0.0:
            rp = o_rp
            rq = o_rq
    glutPostRedisplay()

def main():
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB)
    glutInitWindowSize(500,500)
    glutInitWindowPosition(50,50)
    glutCreateWindow('Dial Trial')
    glutDisplayFunc(plotdial)
    glutKeyboardFunc(keyboard)
    glutMouseFunc(mouse)
    init()
    glutMainLoop()

main() 

So what's the story here? Is it that glLookAt doesn't use the axes set in glOrtho?

1

There are 1 answers

0
Hugh Fisher On

You are missing glMatrixMode(GL_PROJECTION) before the glOrtho. So after the init call you have an identity (no-op) projection matrix and a modelview matrix that happens to include the orthographic projection before the lookat. I would assume that the first frame you draw looks OK.

After that you set up the MODELVIEW matrix correctly, but the projection is wrong.

The usual pattern for OpenGL rendering is to break up the display code into two functions or methods. One sets up the projection and looks something like:

glMatrixMode(GL_PROJECTION)
glOrtho / gluPerspective / whatever
glMatrixMode(GL_MODELVIEW)

The second sets up the viewpoint and looks like:

glLoadIdentity()
gluLookAt