Reputation: 83
What is the right way to use setAttributeBuffer? What should the offset be measured in? Bytes? or the number of elements? None seem to work when using multiple vertex attributes. What exactly to provide for the indices argument in glDrawElements
? Why do I get 0 returned from QOpenGLShaderProgram.attributeLocation
? How to get an attribute location from shader? I'm linking to an example code that should draw a grid. Without the usage of the colour
attribute, it works. But as soon as I enable the colour attribute, I get nothing on the screen. Can anyone please point out what is wrong or at least provide an example usage? The calls to setAttributeBuffer can be found in GraphicsObject.allocateVertices()
# PyQT/OpenGL example
import ctypes
import os
import time
from functools import partial
from math import copysign
import numpy
from PyQt5 import QtGui, QtWidgets, QtCore
VPORTMIN = -8.0
VPORTMAX = 8.0
DAMPENER = 0.1
SHADERPATH = './'
def parseShader(file: str, program: QtGui.QOpenGLShaderProgram):
def readStrings(inFile: file):
source = ''
lines = []
lastpos = inFile.tell()
for data in iter(inFile.readline, ''):
if "#shader" in data:
break
elif data == eof:
break
lines.append(data)
lastpos = inFile.tell()
inFile.seek(lastpos)
return source.join(lines)
file = open(file, 'r')
file.readlines()
eof = file.tell() # get location of EOF character.
file.seek(0, 0) # go back to file beginning.
vs = ''
fs = ''
while True:
line = file.readline()
if file.tell() == eof:
# Reached EOF.
break
elif not line:
continue
elif line == "#shader vertex\n":
vs = readStrings(file)
elif line == "#shader fragment\n":
fs = readStrings(file)
program.addShaderFromSourceCode(QtGui.QOpenGLShader.Vertex, vs)
program.addShaderFromSourceCode(QtGui.QOpenGLShader.Fragment, fs)
if not program.link():
log = program.log()
print(log)
return False
else:
return True
class Window(QtWidgets.QMainWindow):
def __init__(self, app):
super().__init__()
self.app = app
self.app.mainwindow = self
self.glviewPort = GLViewport(parent=self)
self.glviewPort.setMinimumSize(600, 600)
self.glviewPort.setMouseTracking(True)
self.glviewPort.grabKeyboard()
self.setCentralWidget(self.glviewPort)
def closeEvent(self, event: QtGui.QCloseEvent):
self.glviewPort.flush()
return super().closeEvent(event)
class GraphicsObject:
def __init__(self, name=None):
self.name = name
self.vao = QtGui.QOpenGLVertexArrayObject()
self.vbo = QtGui.QOpenGLBuffer(QtGui.QOpenGLBuffer.VertexBuffer)
self.ibo = QtGui.QOpenGLBuffer(QtGui.QOpenGLBuffer.IndexBuffer)
self.vertices = []
self.indices = []
self.dtype = None
self.modelMatrix = QtGui.QMatrix4x4()
self.modelMatrix.setToIdentity()
self.viewMatrix = QtGui.QMatrix4x4()
self.viewMatrix.setToIdentity()
self.projMatrix = QtGui.QMatrix4x4()
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
self.shaderProgram = None
self.vertexPosIdx = 0
self.vertexColorIdx = 0
self.u_MVPidx = 0
self.primType = None
self.count = 0
self.color = QtGui.QVector4D(1.0, 1.0, 1.0, 0.0)
self.rendererId = None
self.blendStatus = False
self.lineSmoothStat = False
self.linewidth = 1.0
self.usagePattern = QtGui.QOpenGLBuffer.StaticDraw
self.dirty = False
self.allowzoom = True
def createObjects(self):
self.shaderProgram = QtGui.QOpenGLShaderProgram()
self.shaderProgram.create()
self.vao.create()
self.vbo.create()
self.ibo.create()
def buildShader(self):
if not parseShader(os.path.join(SHADERPATH, 'graphshader.glsl'), self.shaderProgram):
print("Failed to compile shader!")
sys.exit(1)
else:
self.shaderProgram.bind()
self._cacheUniforms()
def _cacheUniforms(self):
self.vertexPosIdx = self.shaderProgram.attributeLocation("position")
self.vertexColorIdx = self.shaderProgram.attributeLocation("color")
self.u_MVPidx = self.shaderProgram.uniformLocation("u_mvp")
print(self.u_MVPidx)
def bindAll(self):
self.shaderProgram.bind()
self.vao.bind()
self.vbo.bind()
self.ibo.bind()
def setDatatype(self, dtype):
"""
Sets datatype.
Args:
dtype: dtype.
Returns: None
"""
self.dtype = dtype
def setUsagePattern(self, pattern):
self.usagePattern = pattern
def allocateVertices(self, vertices: list):
self.vbo.setUsagePattern(self.usagePattern)
self.ibo.setUsagePattern(self.usagePattern)
self.vertices = numpy.array(vertices, dtype=numpy.float32)
if self.vbo.bufferId():
self.vbo.allocate(self.vertices.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)).contents,
sys.getsizeof(self.vertices))
self.shaderProgram.enableAttributeArray(self.vertexPosIdx)
self.shaderProgram.setAttributeBuffer(self.vertexPosIdx, # Location of attribute in vertex shader.
self.dtype, # data type of vertices.
0, # Start location in vertices buffer.
3, # No. of components per vertex in vertices buffer.
7 * 4) # stride, number of bytes b/w consecutive vertices.
self.shaderProgram.enableAttributeArray(self.vertexColorIdx)
self.shaderProgram.setAttributeBuffer(self.vertexColorIdx, # Location of attribute in vertex shader.
self.dtype, # data type of vertices.
3 * 4, # Start location to color attributes in vertices buffer.
4, # No. of components per vertex in vertices buffer.
7 * 4) # stride, number of bytes b/w consecutive vertices.
self.dirty = True
def allocateIndices(self, indices):
self.ibo.bind()
self.indices = numpy.array(indices, dtype=numpy.uint32)
if self.ibo.bufferId():
self.ibo.allocate(self.indices.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)).contents,
sys.getsizeof(self.indices))
def unbindAll(self):
self.shaderProgram.release()
self.vao.release()
self.vbo.release()
def destroyBuffers(self):
self.vao.destroy()
self.vbo.destroy()
self.ibo.destroy()
def destroy(self):
self.unbindAll()
self.destroyShader()
self.destroyBuffers()
def destroyShader(self):
self.shaderProgram.removeAllShaders()
def setAllowZoom(self, state):
"""
Allow/block camera zoom.
Args:
state: bool
Returns: None
"""
self.allowzoom = state
def setPrimitives(self, primType):
self.primType = primType
def setCount(self, count):
self.count = count
def setColor(self, r, g, b, a):
"""
Sets color
Args:
r: red 0-1
g: green 0-1
b: blue 0-1
a: alpha 0-1
Returns:
"""
self.color = QtGui.QVector4D(r, g, b, a)
def setBlend(self, status):
"""
Enables blend bit.
Args:
status: bool
Returns: None
"""
self.blendStatus = status
def setLineSmooth(self, status):
"""
Enables line smooth.
Args:
status: bool
Returns: None
"""
self.lineSmoothStat = status
def setLineWidth(self, w: float):
"""
Sets a line width.
Args:
w: float; clamped to 0.1-1
Returns: None
"""
self.linewidth = w
if copysign(1, w - 1.0) > 0:
# provided width > 1
self.linewidth = w
elif copysign(1, w - 0.0) < 0:
# provided width < 0
self.linewidth = 0.1
def setTranslation(self, x, y, z):
"""
Translates model by x, y, z.
Args:
x: translate along x. in units of dx
y: translate along y. in units of dy
z: translate along z. in units of dz
Returns: None
"""
self.modelMatrix.translate(QtGui.QVector3D(x, y, z))
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
def setScale(self, sx=1.0, sy=1.0, sz=1.0):
"""
Scales model by sx, sy, sz. Default is 1.0, i.e, no scale.
Args:
sx: scale along x
sy: scale along y
sz: scale along z
Returns: None
"""
self.modelMatrix.scale(QtGui.QVector3D(sx, sy, sz))
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
def setRotation(self, angle, x=0.0, y=0.0, z=1.0):
"""
Rotates model by angle degrees around axis (x, y, z). Default axis points out of screen. z+ve.
angle > 0, CW rotation
angle < 0, CCW rotation
Args:
angle: degrees
x: axis direction
y: axis direction
z: axis direction
Returns: None
"""
self.modelMatrix.rotate(angle, QtGui.QVector3D(x, y, z))
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
def setViewMat(self, mat: QtGui.QMatrix4x4):
if not self.allowzoom:
data = mat.data()
data[0] = 1.0
data[5] = 1.0
data[10] = 1.0
self.viewMatrix = QtGui.QMatrix4x4(data).transposed()
else:
self.viewMatrix = mat
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
def setProjMat(self, mat: QtGui.QMatrix4x4):
self.projMatrix = mat
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
def drawCall(self, gl):
if self.blendStatus:
gl.glEnable(gl.GL_BLEND)
gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_DST_ALPHA)
if self.lineSmoothStat:
gl.glEnable(gl.GL_LINE_SMOOTH)
if 1.0 - self.linewidth > 1.0e-5:
gl.glLineWidth(self.linewidth)
self.shaderProgram.bind()
self.vao.bind()
self.ibo.bind()
self.shaderProgram.setUniformValue(self.u_MVPidx, self.mvpMatrix)
gl.glDrawElements(self.primType, len(self.indices), gl.GL_UNSIGNED_INT, None)
self.shaderProgram.release()
self.vao.release()
self.ibo.release()
if self.blendStatus:
gl.glDisable(gl.GL_BLEND)
if self.lineSmoothStat:
gl.glDisable(gl.GL_LINE_SMOOTH)
if 1.0 - self.linewidth > 1.0e-5:
gl.glLineWidth(1.0)
def updateContents(self, offset, data: list, count):
self.bindAll()
data = numpy.array(data, dtype=numpy.float32)
self.vbo.write(offset, data.ctypes.data_as(ctypes.POINTER(ctypes.c_void_p)).contents, count)
self.unbindAll()
self.dirty = True
def resetTransform(self):
self.modelMatrix.setToIdentity()
self.mvpMatrix = self.projMatrix * self.viewMatrix * self.modelMatrix
class Camera:
"""
An abstract camera class that processes input and calculates the vectors and matrices for use in OpenGL.
"""
UP = QtCore.Qt.Key_Up
DOWN = QtCore.Qt.Key_Down
LEFT = QtCore.Qt.Key_Left
RIGHT = QtCore.Qt.Key_Right
movementSpeed = 2.5
xmin = VPORTMIN
xmax = VPORTMAX
ymin = VPORTMIN
ymax = VPORTMAX
lastPos = QtGui.QVector3D()
lowerleft = QtCore.QPointF()
upperright = QtCore.QPointF()
def __init__(self, position: QtGui.QVector3D, front: QtGui.QVector3D, up: QtGui.QVector3D):
"""
Constructor. Initialize a camera at origin, looking at center with up as specified.
Args:
position: position of camera in world space, i.e, the space with all other objects.
front: the camera looks in the front direction.
up: the camera when upright has it's up axis pointed in specified 'up' direction.
"""
self.position = position
self.front = front
self.up = up
self.position = position
self.direction = front
self.up = up
self.right = QtGui.QVector3D.crossProduct(self.direction, self.up)
self.front = self.position + self.direction
self.view = QtGui.QMatrix4x4()
self.zoomIncrement = 0.0
self.view.lookAt(self.position, self.front, self.up)
self.projection = QtGui.QMatrix4x4()
self.projection.ortho(VPORTMIN, VPORTMAX, VPORTMIN, VPORTMAX, 0.0, 100.0)
def getViewMatrix(self):
"""
Return a view matrix
Returns: QtGui.QMatrix4x4
"""
return self.view
def getProjMatrix(self):
"""
Return a projection matrix
Returns: QtGui.QMatrix4x4
"""
return self.projection
def processMousePan(self, posNdc: QtGui.QVector3D, eventType: QtGui.QMouseEvent.Type):
"""
Pan the viewport in direction of mouse move.
Args
pos (QtGui.QVector3D): in viewport co-ordinates.
eventType (QtGui.QMouseEvent.Type): type of mouse event.
Returns: None
"""
posProj = self.projection.inverted()[0] * posNdc
posMV = self.view.inverted()[0] * posProj
if eventType == QtGui.QMouseEvent.MouseButtonPress:
self.lastPos = posMV
elif eventType == QtGui.QMouseEvent.MouseMove:
offset = posMV - self.lastPos
offset.setZ(0.0)
self.view.translate(offset)
self.position = self.position - offset
self.front = self.position + self.direction
self.view.setToIdentity()
self.view.lookAt(self.position, self.front, self.up)
elif eventType == QtGui.QMouseEvent.MouseButtonRelease:
pass
def processKbd(self, direction, deltatime):
"""
Process up,down,left,right key inputs.
Returns: None
"""
velocity = self.movementSpeed * deltatime
if direction == self.UP:
# Move everything down
dx = QtGui.QVector3D(0.0, 0.0, 0.0)
dy = QtGui.QVector3D(0.0, velocity, 0.0)
elif direction == self.DOWN:
# Move everything up
dx = QtGui.QVector3D(0.0, 0.0, 0.0)
dy = QtGui.QVector3D(0.0, -velocity, 0.0)
elif direction == self.RIGHT:
# Move everything left
dx = QtGui.QVector3D(velocity, 0.0, 0.0)
dy = QtGui.QVector3D(0.0, 0.0, 0.0)
elif direction == self.LEFT:
# Move everything right
dx = QtGui.QVector3D(-velocity, 0.0, 0.0)
dy = QtGui.QVector3D(0.0, 0.0, 0.0)
else:
return
self.position = self.position + dx + dy
self.front = self.position + self.direction
self.view.setToIdentity()
self.view.lookAt(self.position, self.front, self.up)
def fitView(self, xmin, xmax, ymin, ymax):
self.projection.setToIdentity()
self.projection.ortho(xmin, xmax, ymin, ymax, -0.1, 100.0)
def processResize(self, w: float, h: float, keepAspectRatio=True):
if keepAspectRatio:
aspectRatio = w / h
xSpan = 1.0
ySpan = 1.0
if aspectRatio >= 1:
# width >= height
xSpan *= aspectRatio
else:
# height > width
ySpan = xSpan / aspectRatio
self.xmin = VPORTMIN * xSpan
self.xmax = VPORTMAX * xSpan
self.ymin = VPORTMIN * ySpan
self.ymax = VPORTMAX * ySpan
self.fitView(self.xmin, self.xmax, self.ymin, self.ymax)
def processWheel(self, factor, w, h, deltatime):
aspectRatio = float(w) / float(h)
xSpan = 1.0
ySpan = 1.0
if aspectRatio >= 1:
# width >= height
xSpan *= aspectRatio
else:
# height > width
ySpan = xSpan / aspectRatio
zDampener = min(self.xmax - self.xmin, self.ymax - self.ymin)
# Damp zoom so that it's slow when far away. Also consider frame latency.
# exponential function from [https://www.geogebra.org/m/eBHzJyKt]
zDampener = 0.8 * deltatime * 1.00 ** zDampener
if copysign(1, (factor - 1.0)) < 0:
# zoom out
self.xmin -= zDampener * xSpan
self.xmax += zDampener * xSpan
self.ymin -= zDampener * ySpan
self.ymax += zDampener * ySpan
else:
# zoom in
self.xmin += zDampener * xSpan
self.xmax -= zDampener * xSpan
self.ymin += zDampener * ySpan
self.ymax -= zDampener * ySpan
if (self.xmin > -1.0) or (self.ymin > -1.0):
# zoom out
self.xmin -= zDampener * xSpan
self.xmax += zDampener * xSpan
self.ymin -= zDampener * ySpan
self.ymax += zDampener * ySpan
self.fitView(self.xmin, self.xmax, self.ymin, self.ymax)
else:
self.fitView(self.xmin, self.xmax, self.ymin, self.ymax)
class Renderer:
"""
Manages state of graphics objects. This is responsible for drawing on viewport.
"""
def __init__(self, w, h):
self.w = w
self.h = h
self.objects = set()
def register(self, obj: GraphicsObject):
self.objects.add(obj)
obj.rendererId = self.__hash__()
def deRegister(self, obj: GraphicsObject):
self.objects.discard(obj)
obj.rendererId = None
def draw(self, gl, camera):
"""
Call draw calls of all registered objects.
Returns: None
"""
gl.glEnable(gl.GL_DEPTH_TEST)
gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
for obj in self.objects:
if obj.rendererId is None:
continue
else:
obj.setViewMat(camera.getViewMatrix())
obj.setProjMat(camera.getProjMatrix())
obj.drawCall(gl)
class GLViewport(QtWidgets.QOpenGLWidget):
def __init__(self, parent=None):
"""
Re-implements QOpenGLWidget.
Args:
parent: Optional.
"""
super().__init__(parent)
self.camera = Camera(QtGui.QVector3D(0.0, 0.0, 100.0), QtGui.QVector3D(0.0, 0.0, -1.0),
QtGui.QVector3D(0.0, 1.0, 0.0))
self.renderer = Renderer(self.width(), self.height())
self.axGrid = GraphicsObject("axGrid")
self.m_gl = None
self.m_time = 0
self.m_deltatime = 0
self.m_frameCount = 0
self.numScheduledScalings = 0
def initializeGL(self):
defaultFmt = QtGui.QSurfaceFormat.defaultFormat()
verProf = QtGui.QOpenGLVersionProfile(defaultFmt)
self.m_gl = self.context().versionFunctions(verProf)
self.m_gl.initializeOpenGLFunctions()
self.m_gl.glClearColor(0.224, 0.224, 0.224, 1.0)
# Co-ordinate lines.
vertices = []
indices = []
delta = 1.0
xmin = -5.0
xmax = 5.0
dx = delta
ymin = -5.0
ymax = 5.0
dy = delta
nHlines = int((xmax - xmin) / dx) + 1
nVlines = int((ymax - ymin) / dy) + 1
r = 0.4
g = 0.4
b = 0.4
a = 0.302
# Horizontal lines
for i in range(0, nHlines):
y = ymin + i * dy
p1 = [xmin, y, 1.0]
p2 = [xmax, y, 1.0]
vertices.append(p1[0])
vertices.append(p1[1])
vertices.append(p1[2])
vertices.append(r)
vertices.append(g)
vertices.append(b)
vertices.append(a)
vertices.append(p2[0])
vertices.append(p2[1])
vertices.append(p2[2])
vertices.append(r)
vertices.append(g)
vertices.append(b)
vertices.append(a)
# Vertical lines
for i in range(0, nVlines):
x = xmin + i * dx
p1 = [x, ymin, 1.0]
p2 = [x, ymax, 1.0]
vertices.append(p1[0])
vertices.append(p1[1])
vertices.append(p1[2])
vertices.append(r)
vertices.append(g)
vertices.append(b)
vertices.append(a)
vertices.append(p2[0])
vertices.append(p2[1])
vertices.append(p2[2])
vertices.append(r)
vertices.append(g)
vertices.append(b)
vertices.append(a)
for i in range(2 * nHlines + 2 * nVlines):
indices.append(i)
self.axGrid.createObjects()
self.axGrid.buildShader()
self.axGrid.bindAll()
self.axGrid.setCount(len(vertices) / 3)
self.axGrid.setDatatype(self.m_gl.GL_FLOAT)
self.axGrid.setUsagePattern(QtGui.QOpenGLBuffer.StaticDraw)
self.axGrid.allocateVertices(vertices)
self.axGrid.allocateIndices(indices)
self.axGrid.unbindAll()
self.axGrid.setPrimitives(self.m_gl.GL_LINES)
self.axGrid.setBlend(True)
# Register graphics objects.
self.renderer.register(self.axGrid)
self.getGLinfo()
def getGLinfo(self):
profile = "None"
if self.context().format().profile() == QtGui.QSurfaceFormat.CoreProfile:
profile = "Core"
elif self.context().format().profile() == QtGui.QSurfaceFormat.CompatibilityProfile:
profile = "Compat"
print("""
OpenGL : {0}
OpenGLES : {1}
Version : {2}
Major Version : {3}
Minor Version : {4}
Profile : {5}
versionFunctions : {6}
""".format(not self.context().isOpenGLES(), self.context().isOpenGLES(),
self.m_gl.glGetString(self.m_gl.GL_VERSION),
self.m_gl.glGetIntegerv(self.m_gl.GL_MAJOR_VERSION),
self.m_gl.glGetIntegerv(self.m_gl.GL_MINOR_VERSION),
profile, self.m_gl))
def resizeGL(self, w: int, h: int):
self.m_gl.glViewport(0, 0, w, h)
# Re-adjust ortho
self.camera.processResize(float(w), float(h), keepAspectRatio=True)
self.update()
def paintGL(self):
if self.m_frameCount == 0:
self.m_time = time.time()
self.m_gl.glViewport(0, 0, self.width(), self.height())
self.renderer.draw(self.m_gl, self.camera)
self.m_deltatime = time.time() - self.m_time
try:
self.fps = 1. / (self.m_deltatime)
# print(self.fps)
except ZeroDivisionError:
pass
self.m_frameCount += 1
self.m_time = time.time()
def mousePressEvent(self, event: QtGui.QMouseEvent):
"""
Allow pan with MMB, selection with LMB, context menu with RMB
Args:
event: the event.
Returns: None
"""
button = event.button()
modifier = event.modifiers()
posViewport = event.pos()
posNdc = QtGui.QVector3D()
posNdc.setX((2. / self.width()) * (posViewport.x() - (self.width() / 2.)))
posNdc.setY((2. / self.height()) * (-posViewport.y() + (self.height() / 2.))) # note the flip in sign.
posNdc.setZ(0.0)
if button == QtCore.Qt.MiddleButton:
self.camera.processMousePan(posNdc, event.type())
self.update()
return super().mousePressEvent(event)
def mouseMoveEvent(self, event: QtGui.QMouseEvent):
"""
Allow pan with MMB, selection with LMB, context menu with RMB
Args:
event: the event.
Returns: None
"""
buttons = event.buttons()
modifier = event.modifiers()
posViewport = event.pos()
posNdc = QtGui.QVector3D()
posNdc.setX((2. / self.width()) * (posViewport.x() - (self.width() / 2.)))
posNdc.setY((2. / self.height()) * (-posViewport.y() + (self.height() / 2.))) # note the flip in sign.
posNdc.setZ(0.0)
if buttons == QtCore.Qt.MiddleButton:
self.camera.processMousePan(posNdc, event.type())
self.update()
return super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event: QtGui.QMouseEvent):
"""
Allow pan with MMB, selection with LMB, context menu with RMB
Args:
event: the event.
Returns: None
"""
button = event.button()
modifier = event.modifiers()
posViewport = event.pos()
posNdc = QtGui.QVector3D()
posNdc.setX((2. / self.width()) * (posViewport.x() - (self.width() / 2.)))
posNdc.setY((2. / self.height()) * (-posViewport.y() + (self.height() / 2.))) # note the flip in sign.
posNdc.setZ(0.0)
if button == QtCore.Qt.MiddleButton:
self.camera.processMousePan(posNdc, event.type())
self.update()
return super().mouseReleaseEvent(event)
def wheelEvent(self, event: QtGui.QWheelEvent):
"""
Re-implement QGraphicsView's wheelEvent handler for smooooooth zoom.
[https://wiki.qt.io/Smooth_Zoom_In_QGraphicsView]
Args:
event (QtGui.QWheelEvent): the event
Returns:
"""
numDegrees = event.angleDelta().y() / 8
numSteps = numDegrees / 15
self.numScheduledScalings += numSteps
if self.numScheduledScalings * numSteps < 0:
# Reset previously scheduled scalings if user changed wheel direction.
self.numScheduledScalings = numSteps
anim = QtCore.QTimeLine(350, self)
anim.setUpdateInterval(8)
anim.valueChanged.connect(partial(self.scalingTime))
anim.finished.connect(partial(self.animFinished))
anim.start()
@QtCore.pyqtSlot()
def scalingTime(self):
factor = 1.0 + self.numScheduledScalings / 300.
self.camera.processWheel(factor, float(self.width()), float(self.height()), self.m_deltatime)
self.update()
@QtCore.pyqtSlot()
def animFinished(self):
if self.numScheduledScalings > 0:
self.numScheduledScalings -= 1
else:
self.numScheduledScalings += 1
def keyPressEvent(self, event: QtGui.QKeyEvent):
key = event.key()
self.camera.processKbd(key, self.m_deltatime)
self.update()
def flush(self):
self.axGrid.destroy()
if __name__ == '__main__':
import sys
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_UseDesktopOpenGL)
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)
fmt = QtGui.QSurfaceFormat.defaultFormat()
fmt.setVersion(2, 0) # Request 2.0, that's the minimum we can get if PyQt5 was installed with desktop OpenGL
fmt.setSamples(4)
fmt.setSwapInterval(1)
QtGui.QSurfaceFormat.setDefaultFormat(fmt)
app = QtWidgets.QApplication(sys.argv)
window = Window(app)
window.resize(1000, 1000)
window.show()
sys.exit(app.exec_())
#graphshader.glsl
#shader vertex
#version 130
in vec3 position;
uniform mat4 u_mvp;
in vec4 color;
out vec4 vertexColor;
void main() {
gl_Position = vec4(position.xyz, 1.0f);
vertexColor = color;
}
#shader fragment
#version 130
in vec4 vertexColor;
void main(){
gl_FragColor = vertexColor;
}
Upvotes: 0
Views: 937
Reputation: 83
Alright, it appears to be resolved. Apparently, setAttributeBuffer
usage is correct, there is nothing wrong with that! The error was in the shader. I did not multiply the model-view-projection matrix!
gl_Position = u_mvp * vec4(position.xyz, 1.0f);
fixed it.
Upvotes: 1