[PyOpenGL-Users] Perspective and LookAt matrices: Python implementation renders nothing
Brought to you by:
mcfletch
|
From: Florian N. <flo...@en...> - 2015-11-28 11:30:09
|
Hi!
I am still experiencing PyOpenGL and today I implemented Perspective and LookAt matrices based on gluLookAt and gluPerspective (frustum):
def perspectiveMatrix2(fovDeg, aspectRatio, near, far):
ymax = near*np.tan(fovDeg*np.pi/360)
xmax = ymax*aspectRatio
return perspectiveMatrix(-xmax, xmax, -ymax, ymax, near, far)
def perspectiveMatrix(left, right, bottom, top, near, far):
mat = np.array([[2*near/(right-left), 0, (right+left)/(right-left), 0],
[0, 2*near/(top-bottom), (top+bottom)/(top-bottom), 0],
[0, 0, (near+far)/(near-far), 2*near*far/(near-far)],
[0, 0, -1, 0]])
return mat
def lookAt(eye, center, up):
E = eye
C = center
U = up
L = C-E
L = L/np.linalg.norm(L)
S = np.cross(L,U)
S = S/np.linalg.norm(S)
Uprim = np.cross(S,L)
mat = np.zeros(shape=(4,4))
mat[:,0] = np.hstack([S, 0])
mat[:,1] = np.hstack([Uprim, 0])
mat[:,2] = np.hstack([-L, 0])
mat[:,3] = np.hstack([-E, 1])
return mat
However it renders strange things or sometimes nothing depending on the input parameters.
I also provide my running code (where getXRotation, getYRotation and getZRotation behave as expected) so I suppose the issue com from my perspective and lookAt matrices.
I have two last questions about matrices in GLSL:
- I have found that mat*vec4(position, 1) and vec4(position,1)*mat do not trigger any errors while the latter, in my opinion, should fail, why?
- As OpenGL and bumpy are not identically ordered (column/row major), should I always have to transpose my matrix before using OpenGL functions?
Thanks in advance for your help!
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Copyright (c) 2014, Nicolas P. Rougier. All rights reserved.
# Distributed under the terms of the new BSD License.
# -----------------------------------------------------------------------------
import sys
import ctypes
import numpy as np
import OpenGL.GL as gl
import OpenGL.GLU as glu
import OpenGL.GLUT as glut
vertex_code = """
uniform float scale;
uniform mat4 matCam;
attribute vec4 color;
attribute vec3 position;
varying vec4 v_color;
void main()
{
gl_Position = matCam*vec4(scale*position, 1.0);
v_color = color;
} """
fragment_code = """
varying vec4 v_color;
void main()
{
gl_FragColor = v_color;
} """
def display():
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glDepthFunc(gl.GL_LESS)
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
#gl.glDrawArrays(gl.GL_TRIANGLE_STRIP, 0, 9)
gl.glDrawElements(gl.GL_TRIANGLES, len(index), gl.GL_UNSIGNED_INT, None)
glut.glutSwapBuffers()
def reshape(width,height):
gl.glViewport(0, 0, width, height)
def keyboard( key, x, y ):
if key == '\033':
sys.exit( )
def perspectiveMatrix(left, right, bottom, top, near, far):
mat = np.array([[2*near/(right-left), 0, (right+left)/(right-left), 0],
[0, 2*near/(top-bottom), (top+bottom)/(top-bottom), 0],
[0, 0, (near+far)/(near-far), 2*near*far/(near-far)],
[0, 0, -1, 0]])
return mat
def perspectiveMatrix2(fovDeg, aspectRatio, near, far):
ymax = near*np.tan(fovDeg*np.pi/360)
xmax = ymax*aspectRatio
return perspectiveMatrix(-xmax, xmax, -ymax, ymax, near, far)
def lookAt(eye, center, up):
E = eye
C = center
U = up
L = C-E
L = L/np.linalg.norm(L)
S = np.cross(L,U)
S = S/np.linalg.norm(S)
Uprim = np.cross(S,L)
mat = np.zeros(shape=(4,4))
mat[:,0] = np.hstack([S, 0])
mat[:,1] = np.hstack([Uprim, 0])
mat[:,2] = np.hstack([-L, 0])
mat[:,3] = np.hstack([-E, 1])
return mat
def getXRotation(theta):
matX = np.array([[1, 0, 0, 0],
[0, np.cos(theta), -np.sin(theta), 0],
[0, np.sin(theta), np.cos(theta), 0],
[0, 0, 0, 1],
])
return matX
def getYRotation(theta):
matY = np.array([[np.cos(theta), 0, np.sin(theta), 0],
[0, 1, 0, 0],
[-np.sin(theta), 0, np.cos(theta), 0],
[0, 0, 0, 1],
])
return matY
def getZRotation(theta):
matZ = np.array([[np.cos(theta), -np.sin(theta), 0, 0],
[np.sin(theta), np.cos(theta), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
])
return matZ
def timer(fps):
global clock
clock += 0.001 * 1000.0/fps
theta = clock
eye = np.array([0,0,1])
center = np.array([0,0,0])
up = np.array([0,1,0])
#mat = lookAt(eye, center, up)
#mat = getXRotation(clock)
mat = perspectiveMatrix2(1, 4/3, 100, -5)
loc = gl.glGetUniformLocation(program, "matCam")
gl.glUniformMatrix4fv(loc, 1, False, mat.T)
glut.glutTimerFunc(1000/fps, timer, fps)
glut.glutPostRedisplay()
# GLUT init
# --------------------------------------
glut.glutInit()
glut.glutInitDisplayMode(glut.GLUT_DOUBLE | glut.GLUT_RGBA)
glut.glutCreateWindow('Hello world!')
glut.glutReshapeWindow(512,512)
glut.glutReshapeFunc(reshape)
glut.glutDisplayFunc(display)
glut.glutKeyboardFunc(keyboard)
glut.glutTimerFunc(1000/60, timer, 60)
# Build data
# --------------------------------------
data = np.zeros(8, [("position", np.float32, 3),
("color", np.float32, 4)])
data['color'] = [ (1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1),
(1,0,0,1), (0,1,0,1), (0,0,1,1), (1,1,0,1)]
data['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)
]
index = np.array( [0,1,2,
0,2,3,
0,3,4,
0,4,5,
0,5,6,
0,6,1,
1,6,7,
1,7,2,
7,4,3,
7,3,2,
4,7,6,
4,6,5], dtype=np.uint32)
# Build & activate program
# --------------------------------------
# Request a program and shader slots from GPU
program = gl.glCreateProgram()
vertex = gl.glCreateShader(gl.GL_VERTEX_SHADER)
fragment = gl.glCreateShader(gl.GL_FRAGMENT_SHADER)
# Set shaders source
gl.glShaderSource(vertex, vertex_code)
gl.glShaderSource(fragment, fragment_code)
# Compile shaders
gl.glCompileShader(vertex)
gl.glCompileShader(fragment)
# Attach shader objects to the program
gl.glAttachShader(program, vertex)
gl.glAttachShader(program, fragment)
# Build program
gl.glLinkProgram(program)
# Get rid of shaders (no more needed)
gl.glDetachShader(program, vertex)
gl.glDetachShader(program, fragment)
# Make program the default program
gl.glUseProgram(program)
# Build buffer
# --------------------------------------
# Request a buffer slot from GPU
buffer = gl.glGenBuffers(1)
# Make this buffer the default one
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
# Upload data
gl.glBufferData(gl.GL_ARRAY_BUFFER, data.nbytes, data, gl.GL_DYNAMIC_DRAW)
buffer_index = gl.glGenBuffers(1)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index)
gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, index.nbytes, index, gl.GL_STATIC_DRAW)
# Bind attributes
# --------------------------------------
stride = data.strides[0]
offset = ctypes.c_void_p(0)
loc = gl.glGetAttribLocation(program, "position")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
gl.glVertexAttribPointer(loc, 3, gl.GL_FLOAT, False, stride, offset)
offset = ctypes.c_void_p(data.dtype["position"].itemsize)
loc = gl.glGetAttribLocation(program, "color")
gl.glEnableVertexAttribArray(loc)
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, buffer)
gl.glVertexAttribPointer(loc, 4, gl.GL_FLOAT, False, stride, offset)
gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, buffer_index)
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glDepthFunc(gl.GL_LESS)
# Bind uniforms
# --------------------------------------
loc = gl.glGetUniformLocation(program, "scale")
gl.glUniform1f(loc, 0.5)
clock = 0
loc = gl.glGetUniformLocation(program, "matCam")
gl.glUniformMatrix4fv(loc, 1, False, np.eye(4))
# Enter mainloop
# --------------------------------------
glut.glutMainLoop()
|