0

Help me understand why my light is at a fixed position and won't follow the eye/camera. The openGL FAQ seems to say you just set the light's position before doing any transforms for the objects in your world, and that you can set it only once... But the light still stays at a fixed position.

import pyglet

from pyglet.gl import *
from pyglet.window import key
from pyglet.graphics import draw
from vector_math import *

win = pyglet.window.Window()
keys = key.KeyStateHandler()
win.push_handlers(keys)

rtri = 0.0
eye_vec = [0, 0, 2]
center_vec = [0, 0, 0]
up_vec = [0, 1, 0]
center_dist = 3.0

glClearColor(0.0, 0.0, 0.0, 0.0)    # This Will Clear The Background Color To Black
glClearDepth(1.0)                   # Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS)                # The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST)             # Enables Depth Testing
glEnable(GL_LINE_STIPPLE)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glShadeModel(GL_SMOOTH)             # Enables Smooth Color Shading

glViewport(0,0,win.width,win.height)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()                    # Reset The Projection Matrix
# Calculate The Aspect Ratio Of The Window
gluPerspective(45.0, float(win.width) / float(win.height), 0.01, 100.0)

glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glPushMatrix()

glTranslatef(0.0, 0.0, 0.5)
glLightfv(GL_LIGHT0, GL_POSITION, (GLfloat * 4)(0.0, 0.0, 0.0, 1))
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat * 3)(40.0, 40.0, 40.0))
glLightfv(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, (GLfloat * 1) (.35))

glEnable(GL_LIGHT0)

glPopMatrix()

def move_eye_in(going_in):
    global center_dist
    global eye_vec
    center_dist += (-0.3 if going_in else 0.3)
    eye_vec = vec_scalar_mul(vec_normalize(eye_vec), center_dist)

def rotate_eye(is_left):
    global eye_vec

    print 'center_vec', center_vec
    print 'eye_vec', eye_vec

    center_minus_eye = vec_sub(center_vec, eye_vec)
    print 'center_minus_eye', center_minus_eye

    print 'up_vec', up_vec
    look_vec = vec_scalar_mul(vec_normalize(vec_cross(up_vec, center_minus_eye)), 0.5)
    print 'look_vec', look_vec

    eye_plus_look_vec = vec_add(eye_vec, look_vec) if is_left else vec_sub(eye_vec, look_vec)
    print 'eye_plus_look_vec', eye_plus_look_vec

    eye_vec = vec_scalar_mul(vec_normalize(eye_plus_look_vec), center_dist)

def move_eye(x, y, z):
    eye_vec[0] += x
    eye_vec[1] += y
    eye_vec[2] += z

def draw_pyramid(dim):
    glBegin(GL_TRIANGLES)

    glColor3f(1.0, 1.0, 0.0);   # yellow
    glVertex3f(0.0, dim, 0.0);  # Top Of Triangle (Right)
    glVertex3f(-dim, -dim, dim); # Left Of Triangle (Right)
    glVertex3f(dim, -dim, dim);

    glColor3f(1.0, 0.0, 0.0);   # red
    glVertex3f(0.0, dim, 0.0);  # Top Of Triangle (Right)
    glVertex3f(dim, -dim, dim); # Left Of Triangle (Right)
    glVertex3f(dim, -dim, -dim);

    glColor3f(0.0, 1.0, 0.0);   # green
    glVertex3f(0.0, dim, 0.0);      # Top Of Triangle (Back)
    glVertex3f(dim, -dim, -dim);    # Left Of Triangle (Back)
    glVertex3f(-dim, -dim, -dim)

    glColor3f(0.0, 0.0, 1.0);   # blue
    glVertex3f(0.0, dim, 0.0);      # Top Of Triangle (Left)
    glVertex3f(-dim, -dim, -dim);   # Left Of Triangle (Left)
    glVertex3f(-dim, -dim, dim);

    glEnd()

def makeUnitLineGrid(dim):
    line_coords = []
    for a in range(dim + 1):
        for b in range(dim + 1):
            line_coords.extend([
                # vert lines
                # a, 0,   b,
                # a, dim, b,
                # horiz lines
                0,   a, b,
                dim, a, b,
                # depth lines
                a, b, 0,
                a, b, dim])
    return line_coords

line_coords = makeUnitLineGrid(20)

@win.event
def on_draw():

    handle_down_keys()

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(90.0, float(win.width) / float(win.height), 0.001, 100.0)

    # glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    global rtri
    rtri += 1

    gluLookAt(
            eye_vec[0], eye_vec[1], eye_vec[2],
            center_vec[0], center_vec[1], center_vec[2],
            up_vec[0], up_vec[1], up_vec[2])

    glPushMatrix()

    # glTranslatef(0, 0, -0.5)
    # glRotatef(rtri, 0.0, 0.0, 1.0)
    # glRotatef(-90, 1.0, 0.0, 0.0)
    glScalef(1/5.0, 1/5.0, 1/5.0)
    draw_pyramid(3.0)

    glPopMatrix()

    glPushMatrix()

    glTranslatef(3, 0, 0)
    glRotatef(90, 0.0, 1.0, 0.0)
    glScalef(1/5.0, 1/5.0, 1/5.0)
    draw_pyramid(3.0)

    glPopMatrix()

    glPushMatrix()

    glLineStipple(1, 0xFFF)
    glTranslatef(-2.5, -2.5, -2.5)
    glScalef(1.5, 1.5, 1.5)
    glColor4f(1.0, 1.0, 0.0, 0.1);   # yellow

    glEnable(GL_LIGHTING)
    draw(len(line_coords) / 3, GL_LINES,
        ('v3f', line_coords),
        # ('c3B', colors),
    )
    glDisable(GL_LIGHTING)

    glPopMatrix()


def handle_down_keys():

    if keys[key.PAGEUP]:
        move_eye_in(True)
    elif keys[key.PAGEDOWN]:
        move_eye_in(False)
    elif keys[key.LEFT]:
        rotate_eye(True)
    elif keys[key.RIGHT]:
        rotate_eye(False)
    elif keys[key.UP]:
        move_eye(0, 0.5, 0)
    elif keys[key.DOWN]:
        move_eye(0, -0.5, 0)


pyglet.app.run()

vector_math.py

import math

def vec_add(a, b):
    return [a[0] + b[0], a[1] + b[1], a[2] + b[2]]

def vec_sub(a, b):
    return [a[0] - b[0], a[1] - b[1], a[2] - b[2]]

def vec_cross(a, b):
    return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]

def vec_normalize(a):
    mag = math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])
    return [a[0] / mag, a[1] / mag, a[2] / mag]

def vec_scalar_mul(a, n):
    return [a[0] * n, a[1] * n, a[2] * n]

1 Answers1

1

There seem to potentially be two problems with your code:

  1. Generally, you want to put your viewing transformation on the model-view matrix stack, as compared to the projection matrix stack. Line 126, where you set gluLookAt really should go after line 135, where you reset the model-view matrix by calling glLoadIdentity. The reason for this is that lighting normals are transformed by the part of the model-view matrix, and not including your viewing transform will likely yield undesirable results.

  2. Second, you're specifying the light's position (by calling glLight( GL_LIGHT0, GL_POSITION, ...);) before any other transformation (assuming that the python code at the top of the files executes first).

When you specify a light's position in this manner, it gets locked in eye coordinates (a light's position is transformed by the matrix at the top of the model-view matrix when you call glLight( ..., GL_POSITION, ... );) If you want the light to move with the eye point, specify it after your call to gluLookAt, which will transform the light's position to move along with the eye.

radical7
  • 8,957
  • 3
  • 24
  • 33
  • Putting gluLookAt after line 135 almost completely wrecks it. I can see one blue line, but can't manage to see anything else by moving around. Why is #2 bad? I thought the FAQ said to do that so it would get locked in to the eye coords. I originally had my glLightfv set position call below glMatrixMode(GL_MODELVIEW) / line 136, but that didn't change anything. – user1612860 Mar 25 '13 at 04:42
  • This is what I read, and the FAQ it links to: http://stackoverflow.com/questions/5571534/opengl-light-source-that-follows-the-camera – user1612860 Mar 25 '13 at 04:52
  • @user1612860 Point #2 addresses the light "not moving". As your code is now, the light's position is fixed in eye coordinates, and so the results you see should be like headlights in a car; objects in the scene may move around, but the light always comes from the same direction relative to the viewer. If you want the "light to move", which I interpreted to be "move relative to the viewer" then you would want to position the light after the viewing transformation was specified. – radical7 Mar 25 '13 at 05:08
  • I see the light fixed in space when I move around now. I want the light to be like a miner's helmet, as mention in the above link's link, so that when I move around the lines nearest the camera are always lit up. The problem is that regardless of where I put the glLight lines, the light source always stays fixed in space and does not move with the camera. – user1612860 Mar 25 '13 at 05:12
  • For the miner helmet mode, then specify the light's position before the viewing transform (i.e., `gluLookAt`) is the right thing to do, so your approach was correct before, I suppose, and your question was ambiguous. I'd still recommend putting the viewing transform on the correct matrix stack. – radical7 Mar 25 '13 at 05:19
  • Have you actually run it? In this version it almost seems to work, except only the z or x lines seem to light up when you are at the edge of the cube: http://pastie.org/7107056 and not both. You need to hit page down to back up and then left or right to swing to the edge of the cube. Is this just normal openGL behavior? – user1612860 Mar 25 '13 at 05:29
  • Ok, I think that's just surface normals. Thanks. – user1612860 Mar 25 '13 at 07:08