Python: OpenGL Error 1280 Invalid Enumerant with glEnd() - python

I am working on creating a flashlight app in Python using Numba for my kernel and OpenGL (code below) . It is very close to finished but when I run it I run into an error with glEnd error 1280. The terminal output for when the code is run is also below. I can't figure out what exactly is causing the issue and helping narrow it down would be very helpful.
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL.ARB.vertex_buffer_object import *
from OpenGL.GL.ARB.pixel_buffer_object import *
import numpy as np
import sys
import pycuda.gl as cuda_gl
import pycuda.driver as cuda_driver
import math
from numba import jit, cuda as nbcuda
W = 600
H = 600
loc = np.array([W/2, H/2], dtype = 'float32')
dragMode = False
TX = 32
TY = 32
pbo, tex, pycuda_pbo, distanceKernel = [None] * 4
class ExternalMemory(object):
"""
Provide an externally managed memory.
Interface requirement: __cuda_memory__, device_ctypes_pointer, _cuda_memize_
"""
__cuda_memory__ = True
def __init__(self, ptr, size):
self.device_ctypes_pointer = ctypes.c_void_p(ptr)
self._cuda_memsize_ = size
def render():
global pycuda_pbo, pbo
assert pbo is not None
pycuda_pbo.unregister()
glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, long(pbo))
pycuda_pbo = cuda_gl.BufferObject(long(pbo))
pbo_mapping = pycuda_pbo.map()
source_ptr = ExternalMemory(pbo_mapping.device_ptr(), W*H * 4)
d_out = nbcuda.devicearray.DeviceNDArray(shape = W*H * 4,
strides = (1,),
dtype = np.dtype('uint8'),
gpu_data = source_ptr)
blockSize = (TX, TY)
gridSize = ((W + TX - 1)/TX, (H + TY - 1)/TY)
distanceKernel[gridSize, blockSize](d_out, W, H, loc)
cuda_driver.Context.synchronize()
pbo_mapping.unmap()
glBindTexture(GL_TEXTURE_2D, tex)
def drawTexture():
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, H, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
glEnable(GL_TEXTURE_2D)
glBegin(GL_TEXTURE_2D)
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0); glVertex2f(0,0)
glTexCoord2f(0.0, 1.0); glVertex2f(0,H)
glTexCoord2f(1.0, 1.0); glVertex2f(W,H)
glTexCoord2f(1.0, 0.0); glVertex2f(W,0)
glEnd()
glDisable(GL_TEXTURE_2D)
def display():
render()
drawTexture()
glutSwapBuffers()
def create_PBO():
global pbo, pycuda_pbo
data = np.zeros((W*H,4), dtype = 'uint8')
pbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, pbo)
glBufferData(GL_ARRAY_BUFFER, data, GL_DYNAMIC_DRAW)
glBindBuffer(GL_ARRAY_BUFFER, 0)
pycuda_pbo = cuda_gl.BufferObject(long(pbo))
def create_texture():
global tex
tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
def exitfunc():
glBindBuffer(GL_ARRAY_BUFFER, long(pbo))
glDeleteBuffers(1, long(pbo));
glBindBuffer(GL_ARRAY_BUFFER, 0)
pbo = None
glDeleteTextures(tex);
tex = None
def keyboard(key, x, y):
if key == '\033': #\033 is escape key
exit()
elif key == 'a':
dragMode = not dragMode
elif key == 27:
exit()
glutPostRedisplay()
def mouseMove(x, y):
if dragMode == True:
loc[0] = x
loc[1] = y
glutPostRedisplay()
def mouseDrag(x, y):
if dragMode == False:
loc[0] = x
loc[1] = y
glutPostRedisplay()
def handleSpecialKeypress(key, x, y):
if key == GLUT_KEY_LEFT:
loc[0] -= DELTA
if key == GLUT_KEY_RIGHT:
loc[0] += DELTA
if key == GLUT_KEY_UP:
loc[1] -= DELTA
if key == GLUT_KEY_DOWN:
loc[1] += DELTA
glutPostRedisplay()
def printInstructions():
print "flashlight instructions"
print "a: toggle mouse tracking mode"
print "arrow keys: move ref location"
print "esc: close graphics window"
def main():
global cuda_gl, cuda_driver, distanceKernel
printInstructions();
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE)
glutCreateWindow("flashlight: distance image display app")
gluOrtho2D(0, W, H, 0)
glutDisplayFunc(display)
glutKeyboardFunc(keyboard)
glutSpecialFunc(handleSpecialKeypress)
glutPassiveMotionFunc(mouseMove)
glutMotionFunc(mouseDrag)
create_texture()
#Sets up GL interop
import pycuda.gl.autoinit
import pycuda.gl
cuda_gl = pycuda.gl
cuda_driver = pycuda.driver
# force compilation here
#nbcuda.jit(device = True)
def clip(n):
if n > 255:
n = 255
elif n < 0:
n = 0
return n
#nbcuda.jit("(uint8[::1], int32, int32, float32[::1])")
def distanceKernel(d_out, w, h, pos):
c = nbcuda.blockIdx.x*nbcuda.blockDim.x + nbcuda.threadIdx.x
r = nbcuda.blockIdx.y*nbcuda.blockDim.y + nbcuda.threadIdx.y
i = (r*w + c) * 4
if c >= w or r >= h:
return
d = math.sqrt((c - pos[0]) * (c - pos[0]) + (r - pos[1]) * (r - pos[1]))
intensity = clip(255 - d)
d_out[i] = intensity
d_out[i+1] = intensity
d_out[i+2] = 0
d_out[i+3] = 255
create_PBO()
glutMainLoop()
atexit(exitfunc)
main()
This is what the terminal spits out as OpenGL runs
flashlight instructions
a: toggle mouse tracking mode
arrow keys: move ref location
esc: close graphics window
cuInit
cuDeviceGetCount
cuDeviceGetCount
cuDeviceGet
cuGLCtxCreate
cuCtxGetDevice
cuGLRegisterBufferObject
cuGLUnregisterBufferObject
cuGLRegisterBufferObject
cuGLMapBufferObject
cuCtxSynchronize
cuGLUnmapBufferObject
Traceback (most recent call last):
File "_ctypes/callbacks.c", line 314, in 'calling callback function'
File "stackcode.py", line 80, in display
drawTexture()
File "stackcode.py", line 75, in drawTexture
glEnd()
File "latebind.pyx", line 44, in OpenGL_accelerate.latebind.Curry.__call__ (src/latebind.c:1201)
File "/home/uchytilc/anaconda2/lib/python2.7/site-packages/OpenGL/GL/exceptional.py", line 46, in glEnd
return baseFunction( )
File "/home/uchytilc/anaconda2/lib/python2.7/site-packages/OpenGL/platform/baseplatform.py", line 402, in __call__
return self( *args, **named )
File "errorchecker.pyx", line 53, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError (src/errorchecker.c:1218)
OpenGL.error.GLError: GLError(
err = 1280,
description = 'invalid enumerant',
baseOperation = glEnd,
cArguments = ()
)
cuCtxPopCurrent
cuCtxPushCurrent
cuGLUnregisterBufferObject
cuGLUnregisterBufferObject failed with code 1
PyCUDA WARNING: a clean-up operation failed (dead context maybe?)
cuGLUnregisterBufferObject failed: invalid argument
cuCtxPopCurrent
cuCtxPushCurrent
cuCtxDetach

The problem might come from this line:
glBegin(GL_TEXTURE_2D)
glBegin does not allow for this parameter. It only accepts primitive types (which TEXTURE_2D is not). Have a look at the documentation about supported values.

Related

Attribute Error while using PyQtgraph libraries in my python code

I'm running a code from github site and it has this error ( last lines) :
File "D:\Anaconda3\lib\site-packages\pyqtgraph\opengl\GLViewWidget.py", line 152, in viewMatrix
tr.translate(-center.x(), -center.y(), -center.z())
AttributeError: 'int' object has no attribute 'x'
I found that the error is related to pyqtgraph libraries and i didn't change their files
just install the last versions of PyOpenGl and PyQtGraph in spyder
can you please help me in this error?
We need more information,
The problem seems to be related to the fact that center is an int but you use it as an object with attributs
Can we see center's initialization ?
the GlViewWidget.py file :
from ..Qt import QtCore, QtGui, QtOpenGL, QT_LIB
from OpenGL.GL import *
import OpenGL.GL.framebufferobjects as glfbo
import numpy as np
from .. import Vector
from .. import functions as fn
##Vector = QtGui.QVector3D
ShareWidget = None
class GLViewWidget(QtOpenGL.QGLWidget):
"""
Basic widget for displaying 3D data
- Rotation/scale controls
- Axis/grid display
- Export options
High-DPI displays: Qt5 should automatically detect the correct resolution.
For Qt4, specify the ``devicePixelRatio`` argument when initializing the
widget (usually this value is 1-2).
"""
def __init__(self, parent=None, devicePixelRatio=None):
global ShareWidget
if ShareWidget is None:
## create a dummy widget to allow sharing objects (textures, shaders, etc) between views
ShareWidget = QtOpenGL.QGLWidget()
QtOpenGL.QGLWidget.__init__(self, parent, ShareWidget)
self.setFocusPolicy(QtCore.Qt.ClickFocus)
self.opts = {
'center': Vector(0,0,0), ## will always appear at the center of the widget
'distance': 10.0, ## distance of camera from center
'fov': 60, ## horizontal field of view in degrees
'elevation': 30, ## camera's angle of elevation in degrees
'azimuth': 45, ## camera's azimuthal angle in degrees
## (rotation around z-axis 0 points along x-axis)
'viewport': None, ## glViewport params; None == whole widget
'devicePixelRatio': devicePixelRatio,
}
self.setBackgroundColor('k')
self.items = []
self.noRepeatKeys = [QtCore.Qt.Key_Right, QtCore.Qt.Key_Left, QtCore.Qt.Key_Up, QtCore.Qt.Key_Down, QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown]
self.keysPressed = {}
self.keyTimer = QtCore.QTimer()
self.keyTimer.timeout.connect(self.evalKeyState)
self.makeCurrent()
def addItem(self, item):
self.items.append(item)
if hasattr(item, 'initializeGL'):
self.makeCurrent()
try:
item.initializeGL()
except:
self.checkOpenGLVersion('Error while adding item %s to GLViewWidget.' % str(item))
item._setView(self)
#print "set view", item, self, item.view()
self.update()
def removeItem(self, item):
self.items.remove(item)
item._setView(None)
self.update()
def initializeGL(self):
self.resizeGL(self.width(), self.height())
def setBackgroundColor(self, *args, **kwds):
"""
Set the background color of the widget. Accepts the same arguments as
pg.mkColor() and pg.glColor().
"""
self.opts['bgcolor'] = fn.glColor(*args, **kwds)
self.update()
def getViewport(self):
vp = self.opts['viewport']
dpr = self.devicePixelRatio()
if vp is None:
return (0, 0, int(self.width() * dpr), int(self.height() * dpr))
else:
return tuple([int(x * dpr) for x in vp])
def devicePixelRatio(self):
dpr = self.opts['devicePixelRatio']
if dpr is not None:
return dpr
if hasattr(QtOpenGL.QGLWidget, 'devicePixelRatio'):
return QtOpenGL.QGLWidget.devicePixelRatio(self)
else:
return 1.0
def resizeGL(self, w, h):
pass
#glViewport(*self.getViewport())
#self.update()
def setProjection(self, region=None):
m = self.projectionMatrix(region)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
a = np.array(m.copyDataTo()).reshape((4,4))
glMultMatrixf(a.transpose())
def projectionMatrix(self, region=None):
if region is None:
dpr = self.devicePixelRatio()
region = (0, 0, self.width() * dpr, self.height() * dpr)
x0, y0, w, h = self.getViewport()
dist = self.opts['distance']
fov = self.opts['fov']
nearClip = dist * 0.001
farClip = dist * 1000.
r = nearClip * np.tan(fov * 0.5 * np.pi / 180.)
t = r * h / w
## Note that X0 and width in these equations must be the values used in viewport
left = r * ((region[0]-x0) * (2.0/w) - 1)
right = r * ((region[0]+region[2]-x0) * (2.0/w) - 1)
bottom = t * ((region[1]-y0) * (2.0/h) - 1)
top = t * ((region[1]+region[3]-y0) * (2.0/h) - 1)
tr = QtGui.QMatrix4x4()
tr.frustum(left, right, bottom, top, nearClip, farClip)
return tr
def setModelview(self):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
m = self.viewMatrix()
a = np.array(m.copyDataTo()).reshape((4,4))
glMultMatrixf(a.transpose())
def viewMatrix(self):
tr = QtGui.QMatrix4x4()
tr.translate( 0.0, 0.0, -self.opts['distance'])
tr.rotate(self.opts['elevation']-90, 1, 0, 0)
tr.rotate(self.opts['azimuth']+90, 0, 0, -1)
center = self.opts['center']
tr.translate(-center.x(), -center.y(), -center.z())
return tr
def itemsAt(self, region=None):
"""
Return a list of the items displayed in the region (x, y, w, h)
relative to the widget.
"""
region = (region[0], self.height()-(region[1]+region[3]), region[2], region[3])
#buf = np.zeros(100000, dtype=np.uint)
buf = glSelectBuffer(100000)
try:
glRenderMode(GL_SELECT)
glInitNames()
glPushName(0)
self._itemNames = {}
self.paintGL(region=region, useItemNames=True)
finally:
hits = glRenderMode(GL_RENDER)
items = [(h.near, h.names[0]) for h in hits]
items.sort(key=lambda i: i[0])
return [self._itemNames[i[1]] for i in items]
def paintGL(self, region=None, viewport=None, useItemNames=False):
"""
viewport specifies the arguments to glViewport. If None, then we use self.opts['viewport']
region specifies the sub-region of self.opts['viewport'] that should be rendered.
Note that we may use viewport != self.opts['viewport'] when exporting.
"""
if viewport is None:
glViewport(*self.getViewport())
else:
glViewport(*viewport)
self.setProjection(region=region)
self.setModelview()
bgcolor = self.opts['bgcolor']
glClearColor(*bgcolor)
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT )
self.drawItemTree(useItemNames=useItemNames)
def drawItemTree(self, item=None, useItemNames=False):
if item is None:
items = [x for x in self.items if x.parentItem() is None]
else:
items = item.childItems()
items.append(item)
items.sort(key=lambda a: a.depthValue())
for i in items:
if not i.visible():
continue
if i is item:
try:
glPushAttrib(GL_ALL_ATTRIB_BITS)
if useItemNames:
glLoadName(i._id)
self._itemNames[i._id] = i
i.paint()
except:
from .. import debug
debug.printExc()
msg = "Error while drawing item %s." % str(item)
ver = glGetString(GL_VERSION)
if ver is not None:
ver = ver.split()[0]
if int(ver.split(b'.')[0]) < 2:
print(msg + " The original exception is printed above; however, pyqtgraph requires OpenGL version 2.0 or greater for many of its 3D features and your OpenGL version is %s. Installing updated display drivers may resolve this issue." % ver)
else:
print(msg)
finally:
glPopAttrib()
else:
glMatrixMode(GL_MODELVIEW)
glPushMatrix()
try:
tr = i.transform()
a = np.array(tr.copyDataTo()).reshape((4,4))
glMultMatrixf(a.transpose())
self.drawItemTree(i, useItemNames=useItemNames)
finally:
glMatrixMode(GL_MODELVIEW)
glPopMatrix()
def setCameraPosition(self, pos=None, distance=None, elevation=None, azimuth=None):
if pos is not None:
self.opts['center'] = pos
if distance is not None:
self.opts['distance'] = distance
if elevation is not None:
self.opts['elevation'] = elevation
if azimuth is not None:
self.opts['azimuth'] = azimuth
self.update()
def cameraPosition(self):
"""Return current position of camera based on center, dist, elevation, and azimuth"""
center = self.opts['center']
dist = self.opts['distance']
elev = self.opts['elevation'] * np.pi/180.
azim = self.opts['azimuth'] * np.pi/180.
pos = Vector(
center.x() + dist * np.cos(elev) * np.cos(azim),
center.y() + dist * np.cos(elev) * np.sin(azim),
center.z() + dist * np.sin(elev)
)
return pos
def orbit(self, azim, elev):
"""Orbits the camera around the center position. *azim* and *elev* are given in degrees."""
self.opts['azimuth'] += azim
self.opts['elevation'] = np.clip(self.opts['elevation'] + elev, -90, 90)
self.update()
def pan(self, dx, dy, dz, relative='global'):
"""
Moves the center (look-at) position while holding the camera in place.
============== =======================================================
**Arguments:**
*dx* Distance to pan in x direction
*dy* Distance to pan in y direction
*dx* Distance to pan in z direction
*relative* String that determines the direction of dx,dy,dz.
If "global", then the global coordinate system is used.
If "view", then the z axis is aligned with the view
direction, and x and y axes are inthe plane of the
view: +x points right, +y points up.
If "view-upright", then x is in the global xy plane and
points to the right side of the view, y is in the
global xy plane and orthogonal to x, and z points in
the global z direction.
============== =======================================================
Distances are scaled roughly such that a value of 1.0 moves
by one pixel on screen.
Prior to version 0.11, *relative* was expected to be either True (x-aligned) or
False (global). These values are deprecated but still recognized.
"""
# for backward compatibility:
relative = {True: "view-upright", False: "global"}.get(relative, relative)
if relative == 'global':
self.opts['center'] += QtGui.QVector3D(dx, dy, dz)
elif relative == 'view-upright':
cPos = self.cameraPosition()
cVec = self.opts['center'] - cPos
dist = cVec.length() ## distance from camera to center
xDist = dist * 2. * np.tan(0.5 * self.opts['fov'] * np.pi / 180.) ## approx. width of view at distance of center point
xScale = xDist / self.width()
zVec = QtGui.QVector3D(0,0,1)
xVec = QtGui.QVector3D.crossProduct(zVec, cVec).normalized()
yVec = QtGui.QVector3D.crossProduct(xVec, zVec).normalized()
self.opts['center'] = self.opts['center'] + xVec * xScale * dx + yVec * xScale * dy + zVec * xScale * dz
elif relative == 'view':
# pan in plane of camera
elev = np.radians(self.opts['elevation'])
azim = np.radians(self.opts['azimuth'])
fov = np.radians(self.opts['fov'])
dist = (self.opts['center'] - self.cameraPosition()).length()
fov_factor = np.tan(fov / 2) * 2
scale_factor = dist * fov_factor / self.width()
z = scale_factor * np.cos(elev) * dy
x = scale_factor * (np.sin(azim) * dx - np.sin(elev) * np.cos(azim) * dy)
y = scale_factor * (np.cos(azim) * dx + np.sin(elev) * np.sin(azim) * dy)
self.opts['center'] += QtGui.QVector3D(x, -y, z)
else:
raise ValueError("relative argument must be global, view, or view-upright")
self.update()
def pixelSize(self, pos):
"""
Return the approximate size of a screen pixel at the location pos
Pos may be a Vector or an (N,3) array of locations
"""
cam = self.cameraPosition()
if isinstance(pos, np.ndarray):
cam = np.array(cam).reshape((1,)*(pos.ndim-1)+(3,))
dist = ((pos-cam)**2).sum(axis=-1)**0.5
else:
dist = (pos-cam).length()
xDist = dist * 2. * np.tan(0.5 * self.opts['fov'] * np.pi / 180.)
return xDist / self.width()
def mousePressEvent(self, ev):
self.mousePos = ev.pos()
def mouseMoveEvent(self, ev):
diff = ev.pos() - self.mousePos
self.mousePos = ev.pos()
if ev.buttons() == QtCore.Qt.LeftButton:
if (ev.modifiers() & QtCore.Qt.ControlModifier):
self.pan(diff.x(), diff.y(), 0, relative='view')
else:
self.orbit(-diff.x(), diff.y())
elif ev.buttons() == QtCore.Qt.MidButton:
if (ev.modifiers() & QtCore.Qt.ControlModifier):
self.pan(diff.x(), 0, diff.y(), relative='view-upright')
else:
self.pan(diff.x(), diff.y(), 0, relative='view-upright')
def mouseReleaseEvent(self, ev):
pass
# Example item selection code:
#region = (ev.pos().x()-5, ev.pos().y()-5, 10, 10)
#print(self.itemsAt(region))
## debugging code: draw the picking region
#glViewport(*self.getViewport())
#glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT )
#region = (region[0], self.height()-(region[1]+region[3]), region[2], region[3])
#self.paintGL(region=region)
#self.swapBuffers()
def wheelEvent(self, ev):
delta = 0
if QT_LIB in ['PyQt4', 'PySide']:
delta = ev.delta()
else:
delta = ev.angleDelta().x()
if delta == 0:
delta = ev.angleDelta().y()
if (ev.modifiers() & QtCore.Qt.ControlModifier):
self.opts['fov'] *= 0.999**delta
else:
self.opts['distance'] *= 0.999**delta
self.update()
def keyPressEvent(self, ev):
if ev.key() in self.noRepeatKeys:
ev.accept()
if ev.isAutoRepeat():
return
self.keysPressed[ev.key()] = 1
self.evalKeyState()
def keyReleaseEvent(self, ev):
if ev.key() in self.noRepeatKeys:
ev.accept()
if ev.isAutoRepeat():
return
try:
del self.keysPressed[ev.key()]
except:
self.keysPressed = {}
self.evalKeyState()
def evalKeyState(self):
speed = 2.0
if len(self.keysPressed) > 0:
for key in self.keysPressed:
if key == QtCore.Qt.Key_Right:
self.orbit(azim=-speed, elev=0)
elif key == QtCore.Qt.Key_Left:
self.orbit(azim=speed, elev=0)
elif key == QtCore.Qt.Key_Up:
self.orbit(azim=0, elev=-speed)
elif key == QtCore.Qt.Key_Down:
self.orbit(azim=0, elev=speed)
elif key == QtCore.Qt.Key_PageUp:
pass
elif key == QtCore.Qt.Key_PageDown:
pass
self.keyTimer.start(16)
else:
self.keyTimer.stop()
def checkOpenGLVersion(self, msg):
## Only to be called from within exception handler.
ver = glGetString(GL_VERSION).split()[0]
if int(ver.split(b'.')[0]) < 2:
from .. import debug
debug.printExc()
raise Exception(msg + " The original exception is printed above; however, pyqtgraph requires OpenGL version 2.0 or greater for many of its 3D features and your OpenGL version is %s. Installing updated display drivers may resolve this issue." % ver)
else:
raise
def readQImage(self):
"""
Read the current buffer pixels out as a QImage.
"""
w = self.width()
h = self.height()
self.repaint()
pixels = np.empty((h, w, 4), dtype=np.ubyte)
pixels[:] = 128
pixels[...,0] = 50
pixels[...,3] = 255
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels)
# swap B,R channels for Qt
tmp = pixels[...,0].copy()
pixels[...,0] = pixels[...,2]
pixels[...,2] = tmp
pixels = pixels[::-1] # flip vertical
img = fn.makeQImage(pixels, transpose=False)
return img
def renderToArray(self, size, format=GL_BGRA, type=GL_UNSIGNED_BYTE, textureSize=1024, padding=256):
w,h = map(int, size)
self.makeCurrent()
tex = None
fb = None
try:
output = np.empty((w, h, 4), dtype=np.ubyte)
fb = glfbo.glGenFramebuffers(1)
glfbo.glBindFramebuffer(glfbo.GL_FRAMEBUFFER, fb )
glEnable(GL_TEXTURE_2D)
tex = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, tex)
texwidth = textureSize
data = np.zeros((texwidth,texwidth,4), dtype=np.ubyte)
## Test texture dimensions first
glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, None)
if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0:
raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2])
## create teture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texwidth, texwidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.transpose((1,0,2)))
self.opts['viewport'] = (0, 0, w, h) # viewport is the complete image; this ensures that paintGL(region=...)
# is interpreted correctly.
p2 = 2 * padding
for x in range(-padding, w-padding, texwidth-p2):
for y in range(-padding, h-padding, texwidth-p2):
x2 = min(x+texwidth, w+padding)
y2 = min(y+texwidth, h+padding)
w2 = x2-x
h2 = y2-y
## render to texture
glfbo.glFramebufferTexture2D(glfbo.GL_FRAMEBUFFER, glfbo.GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0)
self.paintGL(region=(x, h-y-h2, w2, h2), viewport=(0, 0, w2, h2)) # only render sub-region
glBindTexture(GL_TEXTURE_2D, tex) # fixes issue #366
## read texture back to array
data = glGetTexImage(GL_TEXTURE_2D, 0, format, type)
data = np.fromstring(data, dtype=np.ubyte).reshape(texwidth,texwidth,4).transpose(1,0,2)[:, ::-1]
output[x+padding:x2-padding, y+padding:y2-padding] = data[padding:w2-padding, -(h2-padding):-padding]
finally:
self.opts['viewport'] = None
glfbo.glBindFramebuffer(glfbo.GL_FRAMEBUFFER, 0)
glBindTexture(GL_TEXTURE_2D, 0)
if tex is not None:
glDeleteTextures([tex])
if fb is not None:
glfbo.glDeleteFramebuffers([fb])
return output
Somewhere in your code you are setting the center to be an int. setCameraPosition, maybe? It needs to be a Vector object, instead.

No shape display pyopengl

So i'm trying to make a function for displaying a circle, here's the function :
def drawCircle(x,y,size):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_STRIP)
glVertex2f(0,0)
glVertex2f(100,0)
glVertex2f(100,100)
glVertex2f(0,100)
But when i try it, nothing display. If you have the solution, please explain me in detail, I'm not a profesional in opengl or in pyopengl.
Here's the code :
import glfw
from OpenGL.GL import *
from OpenGL.GLUT import *
import numpy as np
import pyrr
from random import *
from math import *
buffer = bytearray(800 * 600 * 3)
display = (800,600)
if not glfw.init():
raise Exception("glfw can not be initialized!")
def CreateWindow(title="Baguette game",width=800,height=600):
display = (width,height)
window = glfw.create_window(width,height,title, None, None)
glfw.set_window_pos(window,400,200)
glfw.make_context_current(window)
return window
def DrawTriangle(pointA=[-0.5, -0.5, 0.0],pointB=[0.5, -0.5,0.0],
pointC=[-0.5, 0, 0.0],color=[1.0,1.0,1.0]):
vertices = [pointA[0], pointA[1], pointA[2],
pointB[0], pointB[1], pointB[2],
pointC[0], pointC[1], pointC[2]]
colors = [color[0], color[1], color[2],
color[0], color[1], color[2],
color[0], color[1], color[2] ]
v = np.array(vertices,dtype=np.float32)
c = np.array(colors, dtype=np.float32)
glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT,0,v)
glEnableClientState(GL_COLOR_ARRAY)
glColorPointer(3, GL_FLOAT,0,c)
glDrawArrays(GL_TRIANGLES,0,3)
def DrawRectangle(size=[0.5,0.5],position=[0,0],color=[1.0,1.0,1.0]):
DrawTriangle([position[0]-size[0]/2,position[1]+size[1]/2,0],
[position[0]+size[0]/2,position[1]+size[1]/2,0],
[position[0]+size[0]/2,position[1]-size[1]/2,0],
color)
DrawTriangle([position[0]-size[0]/2,position[1]-size[1]/2,0],
[position[0]+size[0]/2,position[1]-size[1]/2,0],
[position[0]-size[0]/2,position[1]+size[1]/2,0],
color)
def Pixel(x,y):
buffer_data = [randint(0,255), 0, 0] * (x * y)
buffer = (GLubyte * (x * y * 3))(*buffer_data)
glDrawPixels(x, y, GL_RGB, GL_UNSIGNED_BYTE, buffer)
def drawCircle(x,y,size):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_STRIP)
glVertex2f(0,0)
glVertex2f(100,0)
glVertex2f(100,100)
glVertex2f(0,100)
if __name__=="__main__":
window = CreateWindow()
initialPosition = (0,0,0)
z=1
while not glfw.window_should_close(window):
glfw.poll_events()
#glClear(GL_COLOR_BUFFER_BIT)
DrawRectangle([1,1],[-0.5,0],[1,0,0])
DrawRectangle([1,1],[0.5,0],[0,1,0])
glfw.swap_buffers(window)
glfw.terminate()
You don't use the x, y and size arguments at all. A glBegin/glEnd sequence must be delimited with glEnd. e.g.:
def drawCircle(cx, cy, radius):
glColor3f(1,1,1)
glBegin(GL_TRIANGLE_FAN)
glVertex2f(cx, cy)
for a in range(361):
x = cx + radius * cos(radians(a))
y = cy + radius * sin(radians(a))
glVertex2f(x, y)
glEnd()
For example draw a circle in the center of the viewport:
drawCircle(0, 0, 0.5)
I recommend reading a good OpenGL tutorial. e.g.: LearnOpenGL

hdrexposure program from SB OpenGL rendering blank screen

Relatively simple program drawing a blank screen. Ported from Superbible Opengl 7th ed.
The program is currently drawing a blank screen. Although the textoverlay is working correctly.
Update: Added the use of glGetError to add additional error checking. Though there is no error produced by it. Still a blank screen however.
Update and SUCCESS: The program is now rendering the hdr image perfect. Thanks to Rabbid76 excellent answer. It was also a ktxloader that needed a fix. Thank you.
Expected output is:
support files: hdrexposure_support.zip
ported from: hdrexposure.cpp
source code:
#!/usr/bin/python3
import sys
import time
import ctypes
fullscreen = True
sys.path.append("./shared")
from sbmloader import SBMObject # location of sbm file format loader
from ktxloader import KTXObject # location of ktx file format loader
from textoverlay import OVERLAY_
from shader import shader_load, link_from_shaders
from sbmath import m3dDegToRad, m3dRadToDeg, m3dTranslateMatrix44, m3dRotationMatrix44, \
m3dMultiply, m3dOrtho, m3dPerspective, rotation_matrix, translate, m3dScaleMatrix44, \
scale, m3dLookAt, normalize
try:
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, glBindVertexArray
except:
print ('''
ERROR: PyOpenGL not installed properly.
''')
sys.exit()
import numpy as np
from math import cos, sin
import glm
identityMatrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
myobject = SBMObject()
ktxobject = KTXObject()
overlay = OVERLAY_()
texture = GLuint(0)
program = GLuint(0)
vao = GLuint(0)
exposure=1.0
vs_source = '''
#version 420 core
void main(void)
{
const vec4 vertices[] = vec4[](vec4(-1.0, -1.0, 0.5, 1.0),
vec4( 1.0, -1.0, 0.5, 1.0),
vec4(-1.0, 1.0, 0.5, 1.0),
vec4( 1.0, 1.0, 0.5, 1.0));
gl_Position = vertices[gl_VertexID];
}
'''
fs_source = '''
#version 430 core
uniform sampler2D s;
uniform float exposure;
out vec4 color;
void main(void)
{
vec4 c = texture(s, gl_FragCoord.xy / vec2(512.0, 512.0));
c.xyz = vec3(1.0) - exp(-c.xyz * exposure);
color = c;
}
'''
def checkGLError():
status = glGetError()
if status != GL_NO_ERROR:
raise RuntimeError('gl error %s' % (status,))
class Scene:
def __init__(self, width, height):
global overlay
global texture
global program
global vao
self.width = width
self.height = height
overlay.init(80, 50)
#// Generate a name for the texture
glGenTextures(1, texture)
#// Load texture from file
texture = ktxobject.ktx_load("treelights_2k.ktx")
#// Now bind it to the context using the GL_TEXTURE_2D binding point
glBindTexture(GL_TEXTURE_2D, texture)
program = glCreateProgram()
fs = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fs, fs_source)
glCompileShader(fs)
if not glGetShaderiv(fs, GL_COMPILE_STATUS):
print( 'compile error:' )
print( glGetShaderInfoLog(fs) )
vs = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vs, vs_source)
glCompileShader(vs)
if not glGetShaderiv(vs, GL_COMPILE_STATUS):
print( 'compile error:' )
print( glGetShaderInfoLog(vs) )
glAttachShader(program, vs)
glAttachShader(program, fs)
glLinkProgram(program)
if not glGetProgramiv(program, GL_LINK_STATUS):
print( 'link error:' )
print( glGetProgramInfoLog(program) )
glGenVertexArrays(1, vao)
glBindVertexArray(vao)
def display(self):
global texture
global program
currentTime = time.time()
green = [ 0.0, 0.25, 0.0, 1.0 ]
glClearBufferfv(GL_COLOR, 0, green)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D, texture)
glUseProgram(program)
glViewport(0, 0, self.width, self.height)
glUniform1f(0, exposure)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
overlay.clear()
buffer = ("Exposure = %2.2f (Numpad +/- to change)" % exposure)
overlay.drawText(buffer, 0, 0)
overlay.draw()
checkGLError()
glutSwapBuffers()
def reshape(self, width, height):
self.width = width
self.height = height
def keyboard(self, key, x, y ):
global fullscreen
global exposure
print ('key:' , key)
if key == b'\x1b': # ESC
sys.exit()
elif key == b'f' or key == b'F': #fullscreen toggle
if (fullscreen == True):
glutReshapeWindow(512, 512)
glutPositionWindow(int((1360/2)-(512/2)), int((768/2)-(512/2)))
fullscreen = False
else:
glutFullScreen()
fullscreen = True
elif key == b'+':
exposure *= 1.1
elif key == b'-':
exposure /= 1.1
def init(self):
pass
def timer(self, blah):
glutPostRedisplay()
glutTimerFunc( int(1/60), self.timer, 0)
time.sleep(1/60.0)
if __name__ == '__main__':
glutInit()
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(512, 512)
w1 = glutCreateWindow('OpenGL SuperBible - HDR Exposure')
glutInitWindowPosition(int((1360/2)-(512/2)), int((768/2)-(512/2)))
fullscreen = False
#glutFullScreen()
scene = Scene(512,512)
glutReshapeFunc(scene.reshape)
glutDisplayFunc(scene.display)
glutKeyboardFunc(scene.keyboard)
glutIdleFunc(scene.display)
#glutTimerFunc( int(1/60), scene.timer, 0)
scene.init()
glutMainLoop()
Current output:
I was getting before updating the fragment shader:
Any help is appreciated. Thank You.
The result of exp(0.0) is 1.0, so the result of 1.0-exp(0.0) is 0.0.
You've to ensure that the value of the uniform exposure is not 0.0, to get a result greater than 0.0 for the expression:
c.xyz = vec3(1.0) - exp(-c.xyz * exposure);
The texture data is of type float. Create numpy.array with the element type numpy.float32, from the byte array, before initializing the texture image:
for i in range(0, h.miplevels):
if h.gltype == GL_FLOAT:
float_data = np.frombuffer(data[ptr:], dtype=np.float32)
glTexSubImage2D(GL_TEXTURE_2D, i, 0, 0, width, height, h.glformat, h.gltype, float_data)
else: # h.type == GL_UNSIGNED_BYTE
glTexSubImage2D(GL_TEXTURE_2D, i, 0, 0, width, height, h.glformat, h.gltype, data[ptr:])
ptr += height * calculate_stride(h, width, 1)
Note, you've to implement different cases for different types.

What is the lookat matrix multiplication function in python for a dragon superbible opengl example?

I mostly ported over the dragon example from SB OpenGL. The output gif of the program is below the code.
My question what is what's the lookat function in python?
Supporting files: dragon.zip simply put pydragon.py into the folder 'dragon' and run
Source code of pydragon.py
#!/usr/bin/python3
import sys
import time
sys.path.append("./shared")
from sbmloader import SBMObject # location of sbm file format loader
from ktxloader import KTXObject # location of ktx file format loader
from sbmath import m3dDegToRad, m3dRadToDeg, m3dTranslateMatrix44, m3dRotationMatrix44, m3dMultiply, m3dOrtho, m3dPerspective, rotation_matrix, translate, m3dScaleMatrix44
fullscreen = True
import numpy.matlib
import numpy as np
import math
try:
from OpenGL.GLUT import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, glBindVertexArray
except:
print ('''
ERROR: PyOpenGL not installed properly.
''')
sys.exit()
identityMatrix = [1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]
clear_program = GLuint(0)
append_program = GLuint(0)
resolve_program = GLuint(0)
class textures:
color = GLuint(0)
normals = GLuint(0)
class uniforms_block:
mv_matrix = (GLfloat * 16)(*identityMatrix)
view_matrix = (GLfloat * 16)(*identityMatrix)
proj_matrix = (GLfloat * 16)(*identityMatrix)
uniforms_buffer = GLuint(0)
class uniforms:
mvp = GLuint(0)
fragment_buffer = GLuint(0)
head_pointer_image = GLuint(0)
atomic_counter_buffer = GLuint(0)
dummy_vao = GLuint(0)
uniform = uniforms()
myobject = SBMObject()
def length(v):
return math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])
def normalize(v):
l = length(v)
#if (v[0] == 0 and v[1] == 0 and v[2] ==0):
# return [0.0, 1/3, 0.0]
return [v[0]/l, v[1]/l, v[2]/l]
def dot(v0, v1):
return v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2]
def cross(v0, v1):
return [
v0[1]*v1[2]-v1[1]*v0[2],
v0[2]*v1[0]-v1[2]*v0[0],
v0[0]*v1[1]-v1[0]*v0[1]]
def m3dLookAt(eye, target, up):
mz = normalize( (eye[0]-target[0], eye[1]-target[1], eye[2]-target[2]) ) # inverse line of sight
mx = normalize( cross( up, mz ) )
my = normalize( cross( mz, mx ) )
tx = dot( mx, eye )
ty = dot( my, eye )
tz = -dot( mz, eye )
return np.array([mx[0], my[0], mz[0], 0, mx[1], my[1], mz[1], 0, mx[2], my[2], mz[2], 0, tx, ty, tz, 1])
def scale(s):
return [s,0,0,0, 0,s,0,0, 0,0,s,0, 0,0,0,1]
def link_from_shaders(shaders, shader_count, delete_shaders, check_errors=False):
program = GLuint(0)
program = glCreateProgram()
for i in range(0, shader_count):
glAttachShader(program, shaders[i]);
glLinkProgram(program);
if (delete_shaders):
for i in range(0, shader_count):
glDeleteShader(shaders[i]);
return program
def shader_load(filename, shader_type):
result = GLuint(0)
with open ( filename, "rb") as data:
result = glCreateShader(shader_type)
glShaderSource(result, data.read() )
glCompileShader(result)
return result
def load_shaders():
global clear_program
global append_program
global resolve_program
global uniform
shaders = [GLuint(0), GLuint(0)]
shaders[0] = shader_load("fragmentlist_shaders/clear.vs.glsl", GL_VERTEX_SHADER);
shaders[1] = shader_load("fragmentlist_shaders/clear.fs.glsl", GL_FRAGMENT_SHADER);
if (clear_program):
glDeleteProgram(clear_program);
clear_program = link_from_shaders(shaders, 2, True);
shaders[0] = shader_load("fragmentlist_shaders/append.vs.glsl", GL_VERTEX_SHADER);
shaders[1] = shader_load("fragmentlist_shaders/append.fs.glsl", GL_FRAGMENT_SHADER);
if (append_program):
glDeleteProgram(append_program);
append_program = link_from_shaders(shaders, 2, True);
uniform.mvp = glGetUniformLocation(append_program, "mvp");
shaders[0] = shader_load("fragmentlist_shaders/resolve.vs.glsl", GL_VERTEX_SHADER);
shaders[1] = shader_load("fragmentlist_shaders/resolve.fs.glsl", GL_FRAGMENT_SHADER);
if (resolve_program):
glDeleteProgram(resolve_program)
resolve_program = link_from_shaders(shaders, 2, True);
class Scene:
def __init__(self, width, height):
global uniforms_buffer
global fragment_buffer
global atomic_counter_buffer
global head_pointer_image
global dummy_vao
global myobject
self.width = width
self.height = height
load_shaders()
glGenBuffers(1, uniforms_buffer)
glBindBuffer(GL_UNIFORM_BUFFER, uniforms_buffer)
glBufferData(GL_UNIFORM_BUFFER, sizeof(GLfloat * 16 *3), None, GL_DYNAMIC_DRAW)
myobject.load("dragon.sbm")
glGenBuffers(1, fragment_buffer)
glBindBuffer(GL_SHADER_STORAGE_BUFFER, fragment_buffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 1024 * 1024 * 16, None, GL_DYNAMIC_COPY)
glGenBuffers(1, atomic_counter_buffer);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomic_counter_buffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, None, GL_DYNAMIC_COPY);
head_pointer_image = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, head_pointer_image);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1024, 1024);
glGenVertexArrays(1, dummy_vao);
glBindVertexArray(dummy_vao);
def display(self):
green = [ 0.0, 0.1, 0.0, 0.0 ]
currentTime = time.time()
f = currentTime
zeros = [ 0.0, 0.0, 0.0, 0.0 ]
gray = [ 0.1, 0.1, 0.1, 0.0 ]
ones = [ 1.0 ]
glViewport(0, 0, self.width , self.height);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
glUseProgram(clear_program);
glBindVertexArray(dummy_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glUseProgram(append_program)
model_matrix = (GLfloat * 16)(*identityMatrix)
model_matrix = scale(6.0)
view_matrix = (GLfloat * 16)(*identityMatrix)
view_matrix = m3dLookAt([math.cos(f * 0.35) * 120.0, math.cos(f * 0.4) * 30.0, math.sin(f * 0.35) * 120.0],
[0.0, -20.0, 0.0],
[0.0, 1, 0.0])
mv_matrix = (GLfloat * 16)(*identityMatrix)
mv_matrix = m3dMultiply(view_matrix , model_matrix)
proj_matrix = (GLfloat * 16)(*identityMatrix)
proj_matrix = m3dPerspective(m3dDegToRad(50.0), float(self.width) / float(self.height), 0.1, 1000.0)
glUniformMatrix4fv(uniform.mvp, 1, GL_FALSE, m3dMultiply(proj_matrix , mv_matrix))
zero = 0;
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomic_counter_buffer)
# next line not working ????
#glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, sys.getsizeof(zero), zero);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, fragment_buffer)
glBindImageTexture(0, head_pointer_image, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI)
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT)
myobject.render()
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT)
glUseProgram(resolve_program)
glBindVertexArray(dummy_vao)
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
glutSwapBuffers()
def reshape(self, width, height):
self.width = width
self.height = height
def keyboard(self, key, x, y ):
global fullscreen
print ('key:' , key)
if key == b'\x1b': # ESC
sys.exit()
elif key == b'f' or key == b'F': #fullscreen toggle
if (fullscreen == True):
glutReshapeWindow(512, 512)
glutPositionWindow(int((1360/2)-(512/2)), int((768/2)-(512/2)))
fullscreen = False
else:
glutFullScreen()
fullscreen = True
print('done')
def init(self):
pass
def timer(self, blah):
glutPostRedisplay()
glutTimerFunc( int(1/60), self.timer, 0)
time.sleep(1/60.0)
if __name__ == '__main__':
start = time.time()
glutInit()
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
glutInitWindowSize(512, 512)
w1 = glutCreateWindow('OpenGL SuperBible - Fragment List')
glutInitWindowPosition(int((1360/2)-(512/2)), int((768/2)-(512/2)))
fullscreen = False
many_cubes = False
#glutFullScreen()
scene = Scene(512,512)
glutReshapeFunc(scene.reshape)
glutDisplayFunc(scene.display)
glutKeyboardFunc(scene.keyboard)
glutIdleFunc(scene.display)
#glutTimerFunc( int(1/60), scene.timer, 0)
scene.init()
glutMainLoop()
The output is supposed to appear like the following:
Ported from fragmentlist.cpp found there from the Superbible OpenGL 7th ed.
Current Question:
Any ideas why the texture rendered on the dragon is not translucent as the expected output has it?
The view space is the local system which is defined by the point of view onto the scene.
The position of the view, the line of sight and the upwards direction of the view, define a coordinate system relative to the world coordinate system. The objects of a scene have to be drawn in relation to the view coordinate system, to be "seen" from the viewing position. The inverse matrix of the view coordinate system is named the view matrix. This matrix transforms from world coordinates to view coordinates.
The code below defines a matrix that exactly encapsulates the steps necessary to calculate a look at the scene:
Converting model coordinates into view system coordinates.
Rotation, to look in the direction of the view.
Movement to the eye position.
Euclidean length of a vector:
def length(v):
return math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])
Unit vector:
def normalize(v):
l = length(v)
return [v[0]/l, v[1]/l, v[2]/l]
Dot product:
def dot(v0, v1):
return v0[0]*v1[0]+v0[1]*v1[1]+v0[2]*v1[2]
Cross product:
def cross(v0, v1):
return [
v0[1]*v1[2]-v1[1]*v0[2],
v0[2]*v1[0]-v1[2]*v0[0],
v0[0]*v1[1]-v1[0]*v0[1]]
The following code does the same as gluLookAt or glm::lookAt does:
The parameter eye is the point of view, target is the point which is looked at and up is the upwards direction.
def m3dLookAt(eye, target, up):
mz = normalize( (eye[0]-target[0], eye[1]-target[1], eye[2]-target[2]) ) # inverse line of sight
mx = normalize( cross( up, mz ) )
my = normalize( cross( mz, mx ) )
tx = dot( mx, eye )
ty = dot( my, eye )
tz = -dot( mz, eye )
return np.array([mx[0], my[0], mz[0], 0, mx[1], my[1], mz[1], 0, mx[2], my[2], mz[2], 0, tx, ty, tz, 1])
Use it like this:
view_matrix = m3dLookAt([0, 0, 20], [0, 0, 0], [0, 1, 0])

OpenGL Shadow Mapping using GLSL

I am trying to get shadow mapping working using GLSL. Unfortunately my depth render results are unusable even I have a pretty decent depth buffer precision. It is rendering like wireframe, following image may be a better description.
I am also including a test case(single file including shader), only dependency is pyopengl.
# shadow mapping test
# utkualtinkaya at gmail
# shader is from http://www.fabiensanglard.net/shadowmapping/index.php
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGL.GL.shaders import *
from OpenGL.GL.framebufferobjects import *
import math
class Camera:
def __init__(self):
self.rotx, self.roty = math.pi/4, math.pi/4
self.distance = 100
self.moving = False
self.ex, self.ey = 0, 0
self.size = (800, 600)
def load_matrices(self):
glViewport(0, 0, *self.size)
y = math.cos(self.roty) * self.distance
x = math.sin(self.roty) * math.cos(self.rotx) * self.distance
z = math.sin(self.roty) * math.sin(self.rotx) * self.distance
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective(45.0, self.size[0]/float(self.size[1]), 1, 1000)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(x,y,z, 0,0,0, 0,1,0)
def on_mouse_button (self, b, s, x, y):
self.moving = not s
self.ex, self.ey = x, y
if b in [3, 4]:
dz = (1 if b == 3 else -1)
self.distance += self.distance/15.0 * dz;
def on_mouse_move(self, x, y, z = 0):
if self.moving:
self.rotx += (x-self.ex) / 300.0
self.roty += -(y-self.ey) / 300.0
self.ex, self.ey = x, y
def set_size(self, w, h):
self.size = w, h
class Shader():
def __init__(self):
self.is_built = False
self.uniforms = {}
def build(self):
self.program = compileProgram(
compileShader('''
uniform mat4 camMatrix;
uniform mat4 shadowMatrix;
varying vec4 depthProjection;
uniform bool useShadow;
void main() {
gl_Position = camMatrix * gl_ModelViewMatrix * gl_Vertex;
depthProjection = shadowMatrix * gl_ModelViewMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
}
''',GL_VERTEX_SHADER),
compileShader('''
varying vec4 depthProjection;
uniform sampler2D shadowMap;
uniform bool useShadow;
void main () {
float shadow = 1.0;
if (useShadow) {
vec4 shadowCoord = depthProjection / depthProjection.w ;
// shadowCoord.z -= 0.0003;
float distanceFromLight = texture2D(shadowMap, shadowCoord.st).z;
if (depthProjection .w > 0.0)
shadow = distanceFromLight < shadowCoord.z ? 0.5 : 1.0 ;
}
gl_FragColor = shadow * gl_Color;
}
''',GL_FRAGMENT_SHADER),)
self.is_built = True
self.uniforms['camMatrix'] = glGetUniformLocation(self.program, 'camMatrix')
self.uniforms['shadowMatrix'] = glGetUniformLocation(self.program, 'shadowMatrix')
self.uniforms['shadowMap'] = glGetUniformLocation(self.program, 'shadowMap')
self.uniforms['useShadow'] = glGetUniformLocation(self.program, 'useShadow')
print self.uniforms
def use(self):
if not self.is_built:
self.build()
glUseProgram(self.program)
class Test:
def __init__(self):
glutInit(sys.argv)
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)
glutInitWindowSize(800, 600)
glutInitWindowPosition(1120/2, 100)
self.window = glutCreateWindow("Shadow Test")
self.cam = Camera()
self.light = Camera()
self.cam.set_size(800, 600)
self.light.set_size(2048, 2048)
self.light.distance = 100
self.shader = Shader()
self.initialized = False
def setup(self):
self.initialized = True
glClearColor(0,0,0,1.0);
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST)
self.fbo = glGenFramebuffers(1);
self.shadowTexture = glGenTextures(1)
glBindFramebuffer(GL_FRAMEBUFFER, self.fbo)
w, h = self.light.size
glActiveTexture(GL_TEXTURE5)
glBindTexture(GL_TEXTURE_2D, self.shadowTexture)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, None)
glDrawBuffer(GL_NONE)
glReadBuffer(GL_NONE)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, self.fbo, 0)
FBOstatus = glCheckFramebufferStatus(GL_FRAMEBUFFER)
if FBOstatus != GL_FRAMEBUFFER_COMPLETE:
print ("GL_FRAMEBUFFER_COMPLETE_EXT failed, CANNOT use FBO\n");
glBindFramebuffer(GL_FRAMEBUFFER, 0)
#glActiveTexture(GL_TEXTURE0)
def draw(self):
glPushMatrix()
glTranslate(0, 10 ,0)
glColor4f(0, 1, 1, 1)
glutSolidCube(5)
glPopMatrix()
glPushMatrix()
glColor4f(0.5, 0.5, .5, 1)
glScale(100, 1, 100)
glutSolidCube(1)
glPopMatrix()
def apply_camera(self, cam):
cam.load_matrices()
model_view = glGetDoublev(GL_MODELVIEW_MATRIX);
projection = glGetDoublev(GL_PROJECTION_MATRIX);
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glMultMatrixd(projection)
glMultMatrixd(model_view)
glUniformMatrix4fv(self.shader.uniforms['camMatrix'], 1, False, glGetFloatv(GL_MODELVIEW_MATRIX))
glLoadIdentity()
def shadow_pass(self):
glUniform1i(self.shader.uniforms['useShadow'], 0)
glBindFramebuffer(GL_FRAMEBUFFER, self.fbo)
glClear(GL_DEPTH_BUFFER_BIT)
glCullFace(GL_FRONT)
self.apply_camera(self.light)
self.draw()
glBindFramebuffer(GL_FRAMEBUFFER, 0)
def final_pass(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.light.load_matrices()
model_view = glGetDoublev(GL_MODELVIEW_MATRIX);
projection = glGetDoublev(GL_PROJECTION_MATRIX);
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
bias = [ 0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0]
glLoadMatrixd(bias)
glMultMatrixd(projection)
glMultMatrixd(model_view)
glUniformMatrix4fv(self.shader.uniforms['shadowMatrix'], 1, False, glGetFloatv(GL_MODELVIEW_MATRIX))
glActiveTexture(GL_TEXTURE5)
glBindTexture(GL_TEXTURE_2D, self.shadowTexture)
glUniform1i(self.shader.uniforms['shadowMap'], 5)
glUniform1i(self.shader.uniforms['useShadow'], 1);
self.apply_camera(self.cam)
glLoadIdentity()
glCullFace(GL_BACK)
self.draw()
def render(self):
if not self.initialized: self.setup()
self.shader.use()
self.shadow_pass()
self.final_pass()
glutSwapBuffers()
def mouse_move(self, *args):
self.cam.on_mouse_move(*args)
self.light.on_mouse_move(*args)
def mouse_button(self, b, *args):
if b==0:
self.light.on_mouse_button(b, *args)
else:
self.cam.on_mouse_button(b, *args)
def main(self):
glutDisplayFunc(self.render)
glutIdleFunc(self.render)
glutMouseFunc(self.mouse_button)
glutMotionFunc(self.mouse_move)
glutReshapeFunc(self.cam.set_size)
#self.setup()
glutMainLoop()
if __name__ == '__main__':
test = Test()
test.main()
solved it, it is the binding issue, in shadow pass fragment shader I simply checked a boolean value to disable reading the texture, but that was not enough. I should have unbind the texture before shadow pass, that is mentioned in documentation as:
Quote from OpenGL Refence:
Special precautions need to be taken to avoid attaching a texture image to the currently bound framebuffer while the texture object is currently bound and potentially sampled by the current vertex or fragment shader.
NVIDIA ignores this, ATI behaves pretty much "undefined" as the documentation says.
// shadowCoord.z -= 0.0003;
Your commented out shadow bias is the solution to your z-fighting problem. Change it to some value e.g. += 0.0005 and you should be good to go.

Categories