Search code examples
pythonpyopenglgluglulookat

How to use gluLookAt in PyOpenGL?


I'm trying to learn PyOpenGL, but I'm not sure how to use gluLookAt to move the camera. I've got an image displaying, but I think I might be missing something that allows me to use gluLookAt? Incoming wall o'text, I'm not sure where the problem might be. I've cut out the shaders and the texture code, because I don't think it's relevant, but if it is, I can post it.

import sys
import ctypes
import numpy

from OpenGL import GL, GLU
from OpenGL.GL import shaders
from OpenGL.arrays import vbo

import pygame
from numpy import array

class OpenGLSprite():
    def __init__(self,_sprite='',_vertexShader = None, _fragmentShader = None):
        if not isinstance(_sprite, pygame.Surface):
            self.sprite = pygame.image.load(_sprite)
        else: self.sprite = _sprite

        vertexData = numpy.array([
             # X    Y   Z   U,   V
            -1.0, -1.0, 0, 0.0, 0.0,
            -1.0,  1.0, 0, 0.0, 1.0,
             1.0,  1.0, 0, 1.0, 1.0,

             1.0,  1.0, 0, 1.0, 1.0,
             1.0, -1.0, 0, 1.0, 0.0,
            -1.0, -1.0, 0, 0.0, 0.0,

            ], dtype=numpy.float32)

        self.loadTexture()
        self.buildShaders(_vertexShader, _fragmentShader)

        self.VAO = GL.glGenVertexArrays(1)
        GL.glBindVertexArray(self.VAO)

        self.VBO = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.VBO)
        GL.glBufferData(GL.GL_ARRAY_BUFFER, vertexData.nbytes, vertexData,
            GL.GL_STATIC_DRAW)

        positionAttrib = GL.glGetAttribLocation(self.shaderProgram, 'position')
        coordsAttrib = GL.glGetAttribLocation(self.shaderProgram, 'texCoords')

        GL.glEnableVertexAttribArray(0)
        GL.glEnableVertexAttribArray(1)
        GL.glVertexAttribPointer(positionAttrib, 3, GL.GL_FLOAT, GL.GL_FALSE, 20,
            None)
        # the last parameter is a pointer
        GL.glVertexAttribPointer(coordsAttrib, 2, GL.GL_FLOAT, GL.GL_TRUE, 20,
            ctypes.c_void_p(12))

        # load texture and assign texture unit for shaders
        self.texUnitUniform = GL.glGetUniformLocation(self.shaderProgram, 'texUnit')

        # Finished
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, 0)
        GL.glBindVertexArray(0)

    def render(self):
        GL.glClearColor(0, 0, 0, 1)
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

        # active shader program
        GL.glUseProgram(self.shaderProgram)

        try:
            # Activate texture
            GL.glActiveTexture(GL.GL_TEXTURE0)
            GL.glBindTexture(GL.GL_TEXTURE_2D, self.texture)
            GL.glUniform1i(self.texUnitUniform, 0)

            # Activate array
            GL.glBindVertexArray(self.VAO)

            # draw triangle
            GL.glDrawArrays(GL.GL_TRIANGLES, 0, 6)
        finally:
            GL.glBindVertexArray(0)
            GL.glUseProgram(0)


def main():
    pygame.init()
    screen = pygame.display.set_mode((640,480),pygame.OPENGL|pygame.DOUBLEBUF)
    GL.glClearColor(0.5, 0.5, 0.5, 1.0)

    camX = 0.0
    camZ = 3.0

    sprite = OpenGLSprite('logo-bluebg-square.png')

    status = 0

    while status == 0:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                status = 1
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    status = 1
                if event.key == pygame.K_LEFT:
                    camX -= 0.1
                if event.key == pygame.K_LEFT:
                    camX += 0.1

        GLU.gluLookAt(camX,0.0,camZ,
                      0.0,0.0,0.0,
                      0.0,1.0,0.0)

        sprite.render()

        pygame.display.flip()

    return 0

if __name__ == '__main__': 
    main()

The gluLookAt in the main game loop doesn't seem to do anything, no matter what parameters I modify. Changing camX with the keys isn't affecting anything, it just keeps looking at the surface straight on. From what I understand, the first three inputs to gluLookAt should be the location of the "Camera", correct? So if it's looking to the origin and the X position of the camera is moving, it should be rotating and moving the surface, right? Is there something special I have to do when setting up the object to allow it to work with gluLookAt? Do I have to do something after calling it to apply the transform to something? Does it need to be in the drawing code of the object, or the gameLoop?


Solution

  • The GLU library is for use with the fixed-function pipeline. It doesn't work with modern OpenGL, when you're using vertex shaders (at least, not unless you're doing compatibility-profile stuff, but it looks like you're not doing that). Instead, you will create the equivalent matrix, and use it as part of one of your uniforms.

    The GLM source code for the equivalent function is available on GitHub in glm/glm/gtc/matrix_transform.inl, in the function lookAtRH. Use this function to create your matrix, multiply it by any other components of your view matrix, and set it as a uniform in your vertex shader.