まあ、色々スキルもあるけれど、これが動けば大抵のモノは作れちゃうんじゃないかな。
テスト用なので細かいところは、動けば良いよ的になってます。

from OpenGL.GL import *
from OpenGL.GL.shaders import *
import pygame
import numpy
import math
import sys

vs = """
in vec3 position;
in vec3 normal;
in vec3 color;
in vec2 uv;
uniform mat4 pMatrix;
uniform mat4 vMatrix;
uniform mat4 mMatrix;
out vec3 vColor;
out vec2 vUv;

void main(){
  vColor = color * max(dot(vec3(1.0), (vMatrix*mMatrix*vec4(normal, 0.0)).xyz), 0.2);
  vUv  = uv;
  gl_Position = pMatrix * vMatrix * mMatrix * vec4(position, 1.0);
}
"""

fs = """
in vec3 vColor;
in vec2 vUv;

void main(void) 
{
  gl_FragColor = vec4(vColor * vec3(vUv, 0.5), 1.0);
}

"""
def perspective(fovy, aspect, near, far):
  top = near * math.tan(fovy * math.pi / 360)
  right = top * aspect
  u = right * 2
  v = top * 2
  w = far - near
  return numpy.array([
    near * 2 / u, 0, 0, 0, 0,                  
    near * 2 / v, 0, 0, 0, 0,             
    -(far + near) / w, -1, 0, 0,
    -(far * near * 2) / w, 0], numpy.float32)

def normalize(p):
  return p / numpy.linalg.norm(p)

def lookAt(eye, center, up):
  z = normalize(numpy.array(eye) - numpy.array(center))
  x = normalize(numpy.cross(up, z))
  y = normalize(numpy.cross(z, x))
  return numpy.array([
    x[0], y[0], z[0], 0,
    x[1], y[1], z[1], 0,
    x[2], y[2], z[2], 0,
    -numpy.dot(x, eye), -numpy.dot(y, eye), -numpy.dot(z, eye), 1], numpy.float32)

def rotX(a):
  sin = math.sin(a)
  cos = math.cos(a)
  return numpy.array([
    1, 0, 0, 0,
    0, cos, sin, 0,
    0, -sin, cos, 0,
    0, 0, 0, 1], numpy.float32)

def rotY(a):
  sin = math.sin(a)
  cos = math.cos(a)
  return numpy.array([
    cos, 0, -sin, 0,
    0, 1, 0, 0,
    sin, 0, cos, 0,
    0, 0, 0, 1], numpy.float32)

def rotZ(a):
  sin = math.sin(a)
  cos = math.cos(a)
  return numpy.array([
    cos, sin, 0, 0,
    -sin, cos, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1], numpy.float32)

def transpose(a):
  return numpy.array([
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    a[0], a[1], a[2], 1], numpy.float32)


def mIdentity():
  return numpy.array([
    1, 0, 0, 0,
    0, 1, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1], numpy.float32)

def mMultply(a, b):
  return numpy.array(
    numpy.matrix(a.reshape((4,4))) * numpy.matrix(b.reshape((4,4))), numpy.float32)


def main():
  w, h = 350, 250
  pygame.init()
  pygame.display.set_mode((w, h), pygame.OPENGL|pygame.DOUBLEBUF)
  pygame.display.set_caption('pygame de GLSL')

  program = compileProgram(
    compileShader(vs, GL_VERTEX_SHADER),
    compileShader(fs, GL_FRAGMENT_SHADER))
  glUseProgram(program)
  
  position = [
    -1, -1, -1, -1, -1,  1,  1, -1,  1,  1, -1, -1,
    -1,  1, -1, -1,  1,  1,  1,  1,  1,  1,  1, -1,
    -1, -1, -1, -1,  1, -1,  1,  1, -1,  1, -1, -1,
    -1, -1,  1, -1,  1,  1,  1,  1,  1,  1, -1,  1,
    -1, -1, -1, -1, -1,  1, -1,  1,  1, -1,  1, -1,
     1, -1, -1,  1, -1,  1,  1,  1,  1,  1,  1, -1 ]          

  normal = [
     0, -1,  0,  0, -1,  0,  0, -1,  0,  0, -1,  0,
     0,  1,  0,  0,  1,  0,  0,  1,  0,  0,  1,  0,
     0,  0, -1,  0,  0, -1,  0,  0, -1,  0,  0, -1,
     0,  0,  1,  0,  0,  1,  0,  0,  1,  0,  0,  1,
    -1,  0,  0, -1,  0,  0, -1,  0,  0, -1,  0,  0,
     1,  0,  0,  1,  0,  0,  1,  0,  0,  1,  0,  0 ]

  uv = [
      0, 0, 1, 0, 1, 1, 0, 1,
      0, 0, 1, 0, 1, 1, 0, 1,
      0, 0, 1, 0, 1, 1, 0, 1,
      0, 0, 1, 0, 1, 1, 0, 1,
      0, 0, 1, 0, 1, 1, 0, 1,
      0, 0, 1, 0, 1, 1, 0, 1 ]

  color = numpy.ones(72)

  indeces = [
     0,  2,  1,  0,  3,  2,
     4,  5,  6,  4,  6,  7,
     8,  9, 10,  8, 10, 11,
    12, 15, 14, 12, 14, 13,
    16, 17, 18, 16, 18, 19,
    20, 23, 22, 20, 22, 21 ]
  
  data = [
    {'name': 'position', 'stride': 3, 'vertices': position},
    {'name': 'normal',   'stride': 3, 'vertices': normal},
    {'name': 'color',    'stride': 3, 'vertices': color},
    {'name': 'uv',       'stride': 2, 'vertices': uv}]
  
  for d in data:
    vertices = numpy.array(d['vertices'], numpy.float32)
    vbo = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glBufferData(GL_ARRAY_BUFFER, 4 * len(vertices), vertices, GL_STATIC_DRAW)
    attr = glGetAttribLocation(program, d['name'])
    glVertexAttribPointer(attr, d['stride'], GL_FLOAT, GL_FALSE, 0, None)
    glEnableVertexAttribArray(attr)
      
  indeces = numpy.array(indeces, numpy.ushort)
  ibo = glGenBuffers(1)
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo)
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * len(indeces), indeces, GL_STATIC_DRAW)
  size = len(indeces)

  uniform = {
    'pMatrix': glGetUniformLocation(program, 'pMatrix'),
    'vMatrix': glGetUniformLocation(program, 'vMatrix'),
    'mMatrix': glGetUniformLocation(program, 'mMatrix'),
    }
  glUniformMatrix4fv(uniform['pMatrix'], 1, GL_FALSE, perspective(45, w / h, 0.1, 100))
  glUniformMatrix4fv(uniform['vMatrix'], 1, GL_FALSE, lookAt([0, 0, 6], [0, 0, 0], [0, 1, 0]))

  glClearDepth(1)
  glClearColor(0, 0, 0, 1)
  glEnable(GL_CULL_FACE)
  glCullFace(GL_BACK)
  glEnable(GL_DEPTH_TEST)
  glDepthFunc(GL_LEQUAL)

  clock = pygame.time.Clock()   
  while True:
    clock.tick(60)   
    t = pygame.time.get_ticks() / 1000
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glUniformMatrix4fv(uniform['mMatrix'], 1, GL_FALSE, mMultply(rotX(t*0.2), rotY(t*0.5)))
    glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_SHORT, None)
    glUniformMatrix4fv(uniform['mMatrix'], 1, GL_FALSE, mMultply(transpose((1.0, 0.0, 0.0)), rotX(0.5)))
    glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_SHORT, None)
    pygame.display.flip()
    for event in pygame.event.get():
      if event.type == pygame.QUIT: sys.exit()
      if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE: sys.exit()     

if __name__ == '__main__':
  main()