[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() |