Как правильно использовать setAttributeBuffer ? В чем должно измеряться смещение? Б? или количество элементов? Ни один из них не работает при использовании нескольких атрибутов вершин. Что именно обеспечить аргументу индексов в glDrawElements
? Почему я получаю 0 от QOpenGLShaderProgram.attributeLocation
? Как получить атрибут местоположения из шейдера? Я ссылаюсь на пример кода, который должен нарисовать сетку. Без использования атрибута colour
это работает. Но как только я включаю атрибут цвета, я ничего не получаю на экране. Может кто-нибудь указать, что не так или хотя бы привести пример использования? Вызовы setAttributeBuffer можно найти в 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;
}