Exemple #1
0
class MeshVertexBuffer(object):
  def __init__(self, vertices=0):
    self.update(vertices)
    self.uniforms = dict()
    self.buffer = None

  def update(self, vertices):
    self.vertices = vertices
    self.attributes = dict()
    self.offsets = dict()
    self.size = 0
    self.changed = True

  def add(self, name, data, count=3, datatype=GL.GL_FLOAT):
    self.attributes[name] = MeshVertexAttribute(name, data, count, datatype)
    self.changed = True

  def remove(self, name):
    if name in self.attributes:
      del self.attributes[name]
      self.changed = True

  def create(self, gl):
    if not self.buffer:
      self.buffer = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
    if not self.buffer.isCreated() and not self.buffer.create():
      raise Exception("buffer creation failed!")
    self.buffer.bind()
    self.offsets = dict()
    self.size = 0
    for item in self.attributes.values():
      self.offsets[item.name] = self.size
      self.size += self.vertices * item.count * item.datasize
    self.buffer.allocate(self.size)
    for item in self.attributes.values():
      self.buffer.write(self.offsets[item.name], item.data.data, self.vertices * item.count * item.datasize)
    self.buffer.release()
    self.changed = False

  def destroy(self, gl):
    if not self.buffer:
      return
    self.buffer.destroy()
    self.buffer = None
    self.changed = True

  def enable(self, gl, shader):
    if self.changed:
      self.create(gl)
    shader.setUniforms(self.uniforms)
    self.buffer.bind()
    for item in self.attributes.values():
      if item.enabled:
        shader.setAttributeArray(item.name, item.datatype, self.offsets[item.name], item.count)
    self.buffer.release()

  def disable(self, gl, shader):
    for item in self.attributes.values():
      if item.enabled:
        shader.unsetAttributeArray(item.name)
Exemple #2
0
class MeshIndexBuffer(object):
  def __init__(self, elements=0, data=np.zeros((0), dtype=np.uint32), primitives=GL.GL_POINTS, datatype=GL.GL_UNSIGNED_INT):
    self.update(elements, data, primitives, datatype)
    self.uniforms = dict()
    self.buffer = None

  def update(self, elements, data, primitives=GL.GL_POINTS, datatype=GL.GL_UNSIGNED_INT):
    self.elements = elements
    self.data = data
    self.primitives = primitives
    self.datatype = datatype
    if datatype == GL.GL_UNSIGNED_BYTE:
      self.datasize = 1
    elif datatype == GL.GL_UNSIGNED_SHORT:
      self.datasize = 2
    elif datatype == GL.GL_UNSIGNED_INT:
      self.datasize = 4
    else:
      raise Exception("unsupported index type")
    self.size = 0
    self.changed = True

  def create(self, gl):
    if not self.buffer:
      self.buffer = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
    if not self.buffer.isCreated() and not self.buffer.create():
      raise Exception("buffer creation failed!")
    self.buffer.bind()
    self.size = self.elements * self.datasize
    self.buffer.allocate(self.size)
    self.buffer.write(0, self.data.data, self.elements * self.datasize)
    self.buffer.release()
    self.changed = False

  def destroy(self, gl):
    if not self.buffer:
      return
    self.buffer.destroy()
    self.buffer = None
    self.changed = True

  def enable(self, gl, shader):
    if self.changed:
      self.create(gl)
    shader.setUniforms(self.uniforms)
    self.buffer.bind()

  def disable(self, gl, shader):
    self.buffer.release()
Exemple #3
0
class GLWidget(QOpenGLWidget, QOpenGLFunctions):
    xRotationChanged = Signal(int)
    yRotationChanged = Signal(int)
    zRotationChanged = Signal(int)

    def __init__(self, parent=None):
        QOpenGLWidget.__init__(self, parent)
        QOpenGLFunctions.__init__(self)

        self.core = "--coreprofile" in QCoreApplication.arguments()
        self.xRot = 0
        self.yRot = 0
        self.zRot = 0
        self.lastPos = 0
        self.logo = Logo()
        self.vao = QOpenGLVertexArrayObject()
        self.logoVbo = QOpenGLBuffer()
        self.program = QOpenGLShaderProgram()
        self.projMatrixLoc = 0
        self.mvMatrixLoc = 0
        self.normalMatrixLoc = 0
        self.lightPosLoc = 0
        self.proj = QMatrix4x4()
        self.camera = QMatrix4x4()
        self.world = QMatrix4x4()
        self.transparent = "--transparent" in QCoreApplication.arguments()
        if self.transparent:
            fmt = self.format()
            fmt.setAlphaBufferSize(8)
            self.setFormat(fmt)

    def xRotation(self):
        return self.xRot

    def yRotation(self):
        return self.yRot

    def zRotation(self):
        return self.zRot

    def minimumSizeHint(self):
        return QSize(50, 50)

    def sizeHint(self):
        return QSize(400, 400)

    def normalizeAngle(self, angle):
        while angle < 0:
            angle += 360 * 16
        while angle > 360 * 16:
            angle -= 360 * 16
        return angle

    def setXRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.xRot:
            self.xRot = angle
            self.emit(SIGNAL("xRotationChanged(int)"), angle)
            self.update()

    def setYRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.yRot:
            self.yRot = angle
            self.emit(SIGNAL("yRotationChanged(int)"), angle)
            self.update()

    def setZRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.zRot:
            self.zRot = angle
            self.emit(SIGNAL("zRotationChanged(int)"), angle)
            self.update()

    def cleanup(self):
        self.makeCurrent()
        self.logoVbo.destroy()
        del self.program
        self.program = None
        self.doneCurrent()

    def vertexShaderSourceCore(self):
        return """#version 150
                in vec4 vertex;
                in vec3 normal;
                out vec3 vert;
                out vec3 vertNormal;
                uniform mat4 projMatrix;
                uniform mat4 mvMatrix;
                uniform mat3 normalMatrix;
                void main() {
                   vert = vertex.xyz;
                   vertNormal = normalMatrix * normal;
                   gl_Position = projMatrix * mvMatrix * vertex;
                }"""

    def fragmentShaderSourceCore(self):
        return """#version 150
                in highp vec3 vert;
                in highp vec3 vertNormal;
                out highp vec4 fragColor;
                uniform highp vec3 lightPos;
                void main() {
                   highp vec3 L = normalize(lightPos - vert);
                   highp float NL = max(dot(normalize(vertNormal), L), 0.0);
                   highp vec3 color = vec3(0.39, 1.0, 0.0);
                   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);
                   fragColor = vec4(col, 1.0);
                }"""

    def vertexShaderSource(self):
        return """attribute vec4 vertex;
                attribute vec3 normal;
                varying vec3 vert;
                varying vec3 vertNormal;
                uniform mat4 projMatrix;
                uniform mat4 mvMatrix;
                uniform mat3 normalMatrix;
                void main() {
                   vert = vertex.xyz;
                   vertNormal = normalMatrix * normal;
                   gl_Position = projMatrix * mvMatrix * vertex;
                }"""

    def fragmentShaderSource(self):
        return """varying highp vec3 vert;
                varying highp vec3 vertNormal;
                uniform highp vec3 lightPos;
                void main() {
                   highp vec3 L = normalize(lightPos - vert);
                   highp float NL = max(dot(normalize(vertNormal), L), 0.0);
                   highp vec3 color = vec3(0.39, 1.0, 0.0);
                   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);
                   gl_FragColor = vec4(col, 1.0);
                }"""

    def initializeGL(self):
        self.context().aboutToBeDestroyed.connect(self.cleanup)
        self.initializeOpenGLFunctions()
        self.glClearColor(0, 0, 0, 1)

        self.program = QOpenGLShaderProgram()

        if self.core:
            self.vertexShader = self.vertexShaderSourceCore()
            self.fragmentShader = self.fragmentShaderSourceCore()
        else:
            self.vertexShader = self.vertexShaderSource()
            self.fragmentShader = self.fragmentShaderSource()

        self.program.addShaderFromSourceCode(QOpenGLShader.Vertex,
                                             self.vertexShader)
        self.program.addShaderFromSourceCode(QOpenGLShader.Fragment,
                                             self.fragmentShader)
        self.program.bindAttributeLocation("vertex", 0)
        self.program.bindAttributeLocation("normal", 1)
        self.program.link()

        self.program.bind()
        self.projMatrixLoc = self.program.uniformLocation("projMatrix")
        self.mvMatrixLoc = self.program.uniformLocation("mvMatrix")
        self.normalMatrixLoc = self.program.uniformLocation("normalMatrix")
        self.lightPosLoc = self.program.uniformLocation("lightPos")

        self.vao.create()
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)

        self.logoVbo.create()
        self.logoVbo.bind()
        float_size = ctypes.sizeof(ctypes.c_float)
        self.logoVbo.allocate(self.logo.constData(),
                              self.logo.count() * float_size)

        self.setupVertexAttribs()

        self.camera.setToIdentity()
        self.camera.translate(0, 0, -1)

        self.program.setUniformValue(self.lightPosLoc, QVector3D(0, 0, 70))
        self.program.release()
        vaoBinder = None

    def setupVertexAttribs(self):
        self.logoVbo.bind()
        f = QOpenGLContext.currentContext().functions()
        f.glEnableVertexAttribArray(0)
        f.glEnableVertexAttribArray(1)
        float_size = ctypes.sizeof(ctypes.c_float)

        null = VoidPtr(0)
        pointer = VoidPtr(3 * float_size)
        f.glVertexAttribPointer(0, 3, int(GL.GL_FLOAT), int(GL.GL_FALSE),
                                6 * float_size, null)
        f.glVertexAttribPointer(1, 3, int(GL.GL_FLOAT), int(GL.GL_FALSE),
                                6 * float_size, pointer)
        self.logoVbo.release()

    def paintGL(self):
        self.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
        self.glEnable(GL.GL_DEPTH_TEST)
        self.glEnable(GL.GL_CULL_FACE)

        self.world.setToIdentity()
        self.world.rotate(180 - (self.xRot / 16), 1, 0, 0)
        self.world.rotate(self.yRot / 16, 0, 1, 0)
        self.world.rotate(self.zRot / 16, 0, 0, 1)

        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        self.program.bind()
        self.program.setUniformValue(self.projMatrixLoc, self.proj)
        self.program.setUniformValue(self.mvMatrixLoc,
                                     self.camera * self.world)
        normalMatrix = self.world.normalMatrix()
        self.program.setUniformValue(self.normalMatrixLoc, normalMatrix)

        self.glDrawArrays(GL.GL_TRIANGLES, 0, self.logo.vertexCount())
        self.program.release()
        vaoBinder = None

    def resizeGL(self, width, height):
        self.proj.setToIdentity()
        self.proj.perspective(45, width / height, 0.01, 100)

    def mousePressEvent(self, event):
        self.lastPos = QPoint(event.pos())

    def mouseMoveEvent(self, event):
        dx = event.x() - self.lastPos.x()
        dy = event.y() - self.lastPos.y()

        if event.buttons() & Qt.LeftButton:
            self.setXRotation(self.xRot + 8 * dy)
            self.setYRotation(self.yRot + 8 * dx)
        elif event.buttons() & Qt.RightButton:
            self.setXRotation(self.xRot + 8 * dy)
            self.setZRotation(self.zRot + 8 * dx)

        self.lastPos = QPoint(event.pos())
Exemple #4
0
class GLWidget(QOpenGLWidget, QOpenGLFunctions):
    xRotationChanged = Signal(int)
    yRotationChanged = Signal(int)
    zRotationChanged = Signal(int)

    def __init__(self, parent=None):
        QOpenGLWidget.__init__(self, parent)
        QOpenGLFunctions.__init__(self)

        self.core = "--coreprofile" in QCoreApplication.arguments()
        self.xRot = 0
        self.yRot = 0
        self.zRot = 0
        self.lastPos = 0
        self.logo = Logo()
        self.vao = QOpenGLVertexArrayObject()
        self.logoVbo = QOpenGLBuffer()
        self.program = QOpenGLShaderProgram()
        self.projMatrixLoc = 0
        self.mvMatrixLoc = 0
        self.normalMatrixLoc = 0
        self.lightPosLoc = 0
        self.proj = QMatrix4x4()
        self.camera = QMatrix4x4()
        self.world = QMatrix4x4()
        self.transparent = "--transparent" in QCoreApplication.arguments()
        if self.transparent:
            fmt = self.format()
            fmt.setAlphaBufferSize(8)
            self.setFormat(fmt)

    def xRotation(self):
        return self.xRot

    def yRotation(self):
        return self.yRot

    def zRotation(self):
        return self.zRot

    def minimumSizeHint(self):
        return QSize(50, 50)

    def sizeHint(self):
        return QSize(400, 400)

    def normalizeAngle(self, angle):
        while angle < 0:
            angle += 360 * 16
        while angle > 360 * 16:
            angle -= 360 * 16
        return angle

    def setXRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.xRot:
            self.xRot = angle
            self.emit(SIGNAL("xRotationChanged(int)"), angle)
            self.update()

    def setYRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.yRot:
            self.yRot = angle
            self.emit(SIGNAL("yRotationChanged(int)"), angle)
            self.update()

    def setZRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.zRot:
            self.zRot = angle
            self.emit(SIGNAL("zRotationChanged(int)"), angle)
            self.update()

    def cleanup(self):
        self.makeCurrent()
        self.logoVbo.destroy()
        del self.program
        self.program = None
        self.doneCurrent()

    def vertexShaderSourceCore(self):
        return """#version 150
                in vec4 vertex;
                in vec3 normal;
                out vec3 vert;
                out vec3 vertNormal;
                uniform mat4 projMatrix;
                uniform mat4 mvMatrix;
                uniform mat3 normalMatrix;
                void main() {
                   vert = vertex.xyz;
                   vertNormal = normalMatrix * normal;
                   gl_Position = projMatrix * mvMatrix * vertex;
                }"""

    def fragmentShaderSourceCore(self):
        return """#version 150
                in highp vec3 vert;
                in highp vec3 vertNormal;
                out highp vec4 fragColor;
                uniform highp vec3 lightPos;
                void main() {
                   highp vec3 L = normalize(lightPos - vert);
                   highp float NL = max(dot(normalize(vertNormal), L), 0.0);
                   highp vec3 color = vec3(0.39, 1.0, 0.0);
                   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);
                   fragColor = vec4(col, 1.0);
                }"""


    def vertexShaderSource(self):
        return """attribute vec4 vertex;
                attribute vec3 normal;
                varying vec3 vert;
                varying vec3 vertNormal;
                uniform mat4 projMatrix;
                uniform mat4 mvMatrix;
                uniform mat3 normalMatrix;
                void main() {
                   vert = vertex.xyz;
                   vertNormal = normalMatrix * normal;
                   gl_Position = projMatrix * mvMatrix * vertex;
                }"""

    def fragmentShaderSource(self):
        return """varying highp vec3 vert;
                varying highp vec3 vertNormal;
                uniform highp vec3 lightPos;
                void main() {
                   highp vec3 L = normalize(lightPos - vert);
                   highp float NL = max(dot(normalize(vertNormal), L), 0.0);
                   highp vec3 color = vec3(0.39, 1.0, 0.0);
                   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);
                   gl_FragColor = vec4(col, 1.0);
                }"""

    def initializeGL(self):
        self.context().aboutToBeDestroyed.connect(self.cleanup)
        self.initializeOpenGLFunctions()
        self.glClearColor(0, 0, 0, 1)

        self.program = QOpenGLShaderProgram()

        if self.core:
            self.vertexShader = self.vertexShaderSourceCore()
            self.fragmentShader = self.fragmentShaderSourceCore()
        else:
            self.vertexShader = self.vertexShaderSource()
            self.fragmentShader = self.fragmentShaderSource()

        self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, self.vertexShader)
        self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, self.fragmentShader)
        self.program.bindAttributeLocation("vertex", 0)
        self.program.bindAttributeLocation("normal", 1)
        self.program.link()

        self.program.bind()
        self.projMatrixLoc = self.program.uniformLocation("projMatrix")
        self.mvMatrixLoc = self.program.uniformLocation("mvMatrix")
        self.normalMatrixLoc = self.program.uniformLocation("normalMatrix")
        self.lightPosLoc = self.program.uniformLocation("lightPos")

        self.vao.create()
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)

        self.logoVbo.create()
        self.logoVbo.bind()
        float_size = ctypes.sizeof(ctypes.c_float)
        self.logoVbo.allocate(self.logo.constData(), self.logo.count() * float_size)

        self.setupVertexAttribs()

        self.camera.setToIdentity()
        self.camera.translate(0, 0, -1)

        self.program.setUniformValue(self.lightPosLoc, QVector3D(0, 0, 70))
        self.program.release()
        vaoBinder = None

    def setupVertexAttribs(self):
        self.logoVbo.bind()
        f = QOpenGLContext.currentContext().functions()
        f.glEnableVertexAttribArray(0)
        f.glEnableVertexAttribArray(1)
        float_size = ctypes.sizeof(ctypes.c_float)

        null = VoidPtr(0)
        pointer = VoidPtr(3 * float_size)
        f.glVertexAttribPointer(0, 3, int(GL.GL_FLOAT), int(GL.GL_FALSE), 6 * float_size, null)
        f.glVertexAttribPointer(1, 3, int(GL.GL_FLOAT), int(GL.GL_FALSE), 6 * float_size, pointer)
        self.logoVbo.release()

    def paintGL(self):
        self.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
        self.glEnable(GL.GL_DEPTH_TEST)
        self.glEnable(GL.GL_CULL_FACE)

        self.world.setToIdentity()
        self.world.rotate(180 - (self.xRot / 16), 1, 0, 0)
        self.world.rotate(self.yRot / 16, 0, 1, 0)
        self.world.rotate(self.zRot / 16, 0, 0, 1)

        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        self.program.bind()
        self.program.setUniformValue(self.projMatrixLoc, self.proj)
        self.program.setUniformValue(self.mvMatrixLoc, self.camera * self.world)
        normalMatrix = self.world.normalMatrix()
        self.program.setUniformValue(self.normalMatrixLoc, normalMatrix)

        self.glDrawArrays(GL.GL_TRIANGLES, 0, self.logo.vertexCount())
        self.program.release()
        vaoBinder = None

    def resizeGL(self, width, height):
        self.proj.setToIdentity()
        self.proj.perspective(45, width / height, 0.01, 100)

    def mousePressEvent(self, event):
        self.lastPos = QPoint(event.pos())

    def mouseMoveEvent(self, event):
        dx = event.x() - self.lastPos.x()
        dy = event.y() - self.lastPos.y()

        if event.buttons() & Qt.LeftButton:
            self.setXRotation(self.xRot + 8 * dy)
            self.setYRotation(self.yRot + 8 * dx)
        elif event.buttons() & Qt.RightButton:
            self.setXRotation(self.xRot + 8 * dy)
            self.setZRotation(self.zRot + 8 * dx)

        self.lastPos = QPoint(event.pos())
Exemple #5
0
class OpenGLWidget(QOpenGLWidget, QOpenGLExtraFunctions):

    def __init__(self, fmt: QSurfaceFormat, parent=None, *args, **kwargs):
        QOpenGLWidget.__init__(self, parent, *args, **kwargs)
        QOpenGLExtraFunctions.__init__(self, *args, **kwargs)
        self.width, self.height = 1280, 720

        self.program = QOpenGLShaderProgram()
        self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        self.ebo = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
        self.vao = QOpenGLVertexArrayObject()

        self.model_loc = None
        self.projection_loc = None
        self.camera_loc = None
        self.attrib_loc = None

        self.shape = Cube()
        self.models = []
        self.model = None
        self.projection = None

        self.camera = Camera()
        self.last_pos = QPoint(self.width / 2.0, self.height / 2.0)

        self.setFormat(fmt)
        self.context = QOpenGLContext(self)
        if not self.context.create():
            raise RuntimeError("Unable to create GL context")

        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(1000.0/FPS)

    ### QtGL ###

    def initializeGL(self) -> None:
        self.context.aboutToBeDestroyed.connect(self.cleanup)

        self.initializeOpenGLFunctions()
        self.build_shaders()
        self.create_vbo()
        self.glClearColor(0.2, 0.0, 0.2, 0.5)

    def paintGL(self) -> None:
        self.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
        self.glEnable(gl.GL_DEPTH_TEST)
        self.camera.move()
        self.render()

    def resizeGL(self, width: int, height: int) -> None:
        self.width, self.height = width, height
        self.glViewport(0, 0, width, height)
        self.projection = pyrr.matrix44.create_perspective_projection_matrix(45, width/height, 0.1, 150)

    def render(self) -> None:
        self.program.bind()
        vao_binder = QOpenGLVertexArrayObject.Binder(self.vao)

        # TODO: switch to Qt functions (doesn't work)
        gl.glUniformMatrix4fv(self.projection_loc, 1, gl.GL_FALSE, self.projection)
        view = self.camera.get_view_matrix()
        gl.glUniformMatrix4fv(self.camera_loc, 1, gl.GL_FALSE, view)

        for model in self.models:
            # TODO: move to entity class ?
            rotation = pyrr.matrix44.create_from_axis_rotation(
                pyrr.vector3.create_from_matrix44_translation(model),
                time.time(),
            )
            scale = pyrr.matrix44.create_from_scale(
                pyrr.vector3.create_from_matrix44_translation(model) * 0.1,
            )
            rotation = pyrr.matrix44.multiply(scale, rotation)
            model = pyrr.matrix44.multiply(rotation, model)

            orbit = pyrr.Matrix44.from_y_rotation(-0.1*time.time())
            model = pyrr.matrix44.multiply(model, orbit)
            gl.glUniformMatrix4fv(self.model_loc, 1, gl.GL_FALSE, model)
            self.glDrawElements(gl.GL_TRIANGLES, len(self.shape.indices), gl.GL_UNSIGNED_INT, VoidPtr(0))

        self.program.release()
        vao_binder = None

    ### Helpers ###

    def build_shaders(self) -> None:
        if not self.program.addShaderFromSourceFile(QOpenGLShader.Vertex, "shaders/vertex_shader.glsl"):
            raise FileNotFoundError("Unable to load vertex shader")
        if not self.program.addShaderFromSourceFile(QOpenGLShader.Fragment, "shaders/fragment_shader.glsl"):
            raise FileNotFoundError("Unable to load fragment shader")
        if not self.program.link():
            raise RuntimeError("Unable to link shader program")

    def create_vbo(self) -> None:
        self.program.bind()  # suspicious behaviour ?

        self.vao.create()
        vao_binder = QOpenGLVertexArrayObject.Binder(self.vao)

        self.vbo.create()
        self.vbo.bind()
        self.vbo.allocate(self.shape.vertices, self.shape.vertices.nbytes)

        self.attrib_loc = self.program.attributeLocation("a_position")
        self.model_loc = self.program.uniformLocation("model")
        self.projection_loc = self.program.uniformLocation("projection")
        self.camera_loc = self.program.uniformLocation("camera")

        for i in range(150):
            x, y, z = random.normalvariate(0, 15), random.normalvariate(0, 15), random.normalvariate(0, 15)
            self.models.append(pyrr.matrix44.create_from_translation(pyrr.Vector3([x, y, z])))

        self.ebo.create()
        self.ebo.bind()
        self.ebo.allocate(self.shape.indices, self.shape.indices.nbytes)

        float_size = ctypes.sizeof(ctypes.c_float)  # (4)
        null = VoidPtr(0)
        pointer = VoidPtr(3 * float_size)
        self.glEnableVertexAttribArray(0)
        self.glVertexAttribPointer(
            0, 3, gl.GL_FLOAT, gl.GL_FALSE, 6 * float_size, null
        )
        self.glEnableVertexAttribArray(1)
        self.glVertexAttribPointer(
            1, 3, gl.GL_FLOAT, gl.GL_FALSE, 6 * float_size, pointer
        )
        self.vao.release()
        self.vbo.release()
        self.ebo.release()

        self.program.release()
        vao_binder = None

    ### Events ###

    def keyPressEvent(self, event):
        """W: 0x57, A: 0x41, S: 0x53, D: 0x44, space: 0x20, shift: 0x01000020"""  # TODO: make keymap
        if event.key() == int(0x57):
            self.camera.keyboard_press("FORWARD")
        elif event.key() == int(0x53):
            self.camera.keyboard_press("BACKWARD")
        if event.key() == int(0x41):
            self.camera.keyboard_press("LEFT")
        elif event.key() == int(0x44):
            self.camera.keyboard_press("RIGHT")
        if event.key() == int(0x20):
            self.camera.keyboard_press("UP")
        elif event.key() == int(0x01000020):
            self.camera.keyboard_press("DOWN")

    def keyReleaseEvent(self, event):
        if event.key() == int(0x57):
            self.camera.keyboard_release("FORWARD")
        elif event.key() == int(0x53):
            self.camera.keyboard_release("BACKWARD")
        if event.key() == int(0x41):
            self.camera.keyboard_release("LEFT")
        elif event.key() == int(0x44):
            self.camera.keyboard_release("RIGHT")
        if event.key() == int(0x20):
            self.camera.keyboard_release("UP")
        elif event.key() == int(0x01000020):
            self.camera.keyboard_release("DOWN")

    def mousePressEvent(self, event):
        self.last_pos = QPoint(event.pos())
        event.accept()

    def mouseMoveEvent(self, event):
        dx = event.x() - self.last_pos.x()
        dy = event.y() - self.last_pos.y()

        if event.buttons():
            self.camera.mouse_movement(float(dx), float(dy))

        event.accept()
        self.last_pos = QPoint(event.pos())

    def wheelEvent(self, event):
        if event.type() in (Qt.ScrollBegin, Qt.ScrollEnd):  # FIXME: doesn't seem to work, true divide err
            return

        degrees = event.delta() / 8
        steps = degrees / 15

        event.accept()
        self.camera.scroll_movement(steps)

    ### Slots ###

    @Slot()
    def cleanup(self):
        if not self.makeCurrent():
            raise Exception("Could not make context current")
        self.vbo.destroy()
        self.program.bind()
        self.program.removeAllShaders()
        self.program.release()
        del self.program
        self.program = None
        self.doneCurrent()
Exemple #6
0
class EventsGL(QOpenGLWidget):
    "Cube gl widget"

    def __init__(self, parent=None):
        QOpenGLWidget.__init__(self, parent)

        # camera
        self.camera = QtCamera()
        self.camera.position = QVector3D(0.0, 0.0, 3.0)
        self.camera.front = QVector3D(0.0, 0.0, -1.0)
        self.camera.up = QVector3D(0.0, 1.0, 0.0)
        self.camera.movementSensitivity = 0.05

        # shaders etc
        tutoTutoDir = os.path.dirname(__file__)
        tutoPardir = os.path.join(tutoTutoDir, os.pardir)
        tutoPardir = os.path.realpath(tutoPardir)
        mediaDir = os.path.join(tutoPardir, "media")
        shaderDir = os.path.join(mediaDir, "shaders")

        availableShaders = ["cube"]
        self.shaders = {
            name: {
                "fragment": os.path.join(shaderDir, name + ".frag"),
                "vertex": os.path.join(shaderDir, name + ".vert")
            }
            for name in availableShaders
        }
        self.core = "--coreprofile" in QCoreApplication.arguments()
        imdir = os.path.join(mediaDir, "images")
        imFName = "im"
        imageFile1 = os.path.join(imdir, imFName + "0.png")
        self.image1 = QImage(imageFile1).mirrored()
        imageFile2 = os.path.join(imdir, imFName + "1.png")
        self.image2 = QImage(imageFile2).mirrored()

        # opengl data related
        self.context = QOpenGLContext()
        self.vao = QOpenGLVertexArrayObject()
        self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        self.program = QOpenGLShaderProgram()
        self.texture1 = None
        self.texture2 = None
        self.texUnit1 = 0
        self.texUnit2 = 1

        # vertex data
        self.cubeVertices = np.array(
            [
                # pos vec3 || texcoord vec2
                -0.5,
                -0.5,
                -0.5,
                0.0,
                0.0,
                0.5,
                -0.5,
                -0.5,
                1.0,
                0.0,
                0.5,
                0.5,
                -0.5,
                1.0,
                1.0,
                0.5,
                0.5,
                -0.5,
                1.0,
                1.0,
                -0.5,
                0.5,
                -0.5,
                0.0,
                1.0,
                -0.5,
                -0.5,
                -0.5,
                0.0,
                0.0,
                -0.5,
                -0.5,
                0.5,
                0.0,
                0.0,
                0.5,
                -0.5,
                0.5,
                1.0,
                0.0,
                0.5,
                0.5,
                0.5,
                1.0,
                1.0,
                0.5,
                0.5,
                0.5,
                1.0,
                1.0,
                -0.5,
                0.5,
                0.5,
                0.0,
                1.0,
                -0.5,
                -0.5,
                0.5,
                0.0,
                0.0,
                -0.5,
                0.5,
                0.5,
                1.0,
                0.0,
                -0.5,
                0.5,
                -0.5,
                1.0,
                1.0,
                -0.5,
                -0.5,
                -0.5,
                0.0,
                1.0,
                -0.5,
                -0.5,
                -0.5,
                0.0,
                1.0,
                -0.5,
                -0.5,
                0.5,
                0.0,
                0.0,
                -0.5,
                0.5,
                0.5,
                1.0,
                0.0,
                0.5,
                0.5,
                0.5,
                1.0,
                0.0,
                0.5,
                0.5,
                -0.5,
                1.0,
                1.0,
                0.5,
                -0.5,
                -0.5,
                0.0,
                1.0,
                0.5,
                -0.5,
                -0.5,
                0.0,
                1.0,
                0.5,
                -0.5,
                0.5,
                0.0,
                0.0,
                0.5,
                0.5,
                0.5,
                1.0,
                0.0,
                -0.5,
                -0.5,
                -0.5,
                0.0,
                1.0,
                0.5,
                -0.5,
                -0.5,
                1.0,
                1.0,
                0.5,
                -0.5,
                0.5,
                1.0,
                0.0,
                0.5,
                -0.5,
                0.5,
                1.0,
                0.0,
                -0.5,
                -0.5,
                0.5,
                0.0,
                0.0,
                -0.5,
                -0.5,
                -0.5,
                0.0,
                1.0,
                -0.5,
                0.5,
                -0.5,
                0.0,
                1.0,
                0.5,
                0.5,
                -0.5,
                1.0,
                1.0,
                0.5,
                0.5,
                0.5,
                1.0,
                0.0,
                0.5,
                0.5,
                0.5,
                1.0,
                0.0,
                -0.5,
                0.5,
                0.5,
                0.0,
                0.0,
                -0.5,
                0.5,
                -0.5,
                0.0,
                1.0
            ],
            dtype=ctypes.c_float)
        # cube worldSpace coordinates
        self.cubeCoords = [
            QVector3D(0.2, 1.1, -1.0),
            QVector3D(2.0, 5.0, -15.0),
            QVector3D(-1.5, -2.2, -2.5),
            QVector3D(-3.8, -2.0, -12.3),
            QVector3D(2.4, -0.4, -3.5),
            QVector3D(-1.7, 3.0, -7.5),
            QVector3D(1.3, -2.0, -2.5),
            QVector3D(1.5, 2.0, -2.5),
            QVector3D(1.5, 0.2, -1.5),
            QVector3D(-1.3, 1.0, -1.5)
        ]
        self.rotateVector = QVector3D(0.7, 0.2, 0.5)

    def loadShader(self, shaderName: str, shaderType: str):
        "Load shader"
        shader = self.shaders[shaderName]
        shaderSourcePath = shader[shaderType]
        if shaderType == "vertex":
            shader = QOpenGLShader(QOpenGLShader.Vertex)
        else:
            shader = QOpenGLShader(QOpenGLShader.Fragment)
        #
        isCompiled = shader.compileSourceFile(shaderSourcePath)

        if isCompiled is False:
            print(shader.log())
            raise ValueError(
                "{0} shader {2} known as {1} is not compiled".format(
                    shaderType, shaderName, shaderSourcePath))
        return shader

    def useShaders(self, shaderProgram: QOpenGLShaderProgram,
                   shaders: {"shaderName": ["shaderType"]}, attrLocs: dict):
        ""
        print("program shaders: ", shaderProgram.shaders())
        for shaderName, shaderTypes in shaders.items():
            #
            if len(shaderTypes) == 2:
                self.useShaderSingleName(shaderProgram=shaderProgram,
                                         shaderName=shaderName,
                                         attrLocs=attrLocs)
            elif len(shaderTypes) == 1:
                shaderType = shaderTypes[0]
                if shaderType == "vertex":
                    shader = self.loadVertexShader(shaderName)
                else:
                    shader = self.loadFragmentShader(shaderName)

                shaderProgram.addShader(shader)
                # adding shader
                self.bindLinkProgram(shaderProgram, attrLocs)

    def loadVertexShader(self, shaderName: str):
        "load vertex shader"
        return self.loadShader(shaderName, "vertex")

    def loadFragmentShader(self, shaderName: str):
        "load fragment shader"
        return self.loadShader(shaderName, "fragment")

    def getGlInfo(self):
        "Get opengl info"
        info = """
            Vendor: {0}
            Renderer: {1}
            OpenGL Version: {2}
            Shader Version: {3}
            """.format(pygl.glGetString(pygl.GL_VENDOR),
                       pygl.glGetString(pygl.GL_RENDERER),
                       pygl.glGetString(pygl.GL_VERSION),
                       pygl.glGetString(pygl.GL_SHADING_LANGUAGE_VERSION))
        return info

    def moveCamera(self, direction: str):
        "Move camera to certain direction and update gl widget"
        self.camera.move(direction, deltaTime=0.05)
        self.update()

    def turnAround(self, x: float, y: float):
        ""
        self.camera.lookAround(xoffset=x, yoffset=y, pitchBound=True)
        self.update()

    def rotateCubes(self, xval: float, yval: float, zval: float):
        ""
        self.rotateVector.setZ(zval)
        self.rotateVector.setY(yval)
        self.rotateVector.setX(xval)
        self.update()

    def cleanUpGl(self):
        "Clean up everything"
        self.context.makeCurrent()
        self.vbo.destroy()
        self.texture1.destroy()
        self.texture2.destroy()
        self.vao.destroy()
        del self.program
        self.program = None
        self.doneCurrent()

    def resizeGL(self, width: int, height: int):
        "Resize the viewport"
        funcs = self.context.functions()
        funcs.glViewport(0, 0, width, height)

    def initializeGL(self):
        print('gl initial')
        print(self.getGlInfo())

        # create context and make it current
        self.context.create()
        self.context.aboutToBeDestroyed.connect(self.cleanUpGl)

        # initialize functions
        funcs = self.context.functions()
        funcs.initializeOpenGLFunctions()
        funcs.glClearColor(0.0, 0.4, 0.4, 0)
        funcs.glEnable(pygl.GL_DEPTH_TEST)
        funcs.glEnable(pygl.GL_TEXTURE_2D)

        # create uniform values for shaders
        # deal with shaders

        # cube shader
        self.program = QOpenGLShaderProgram(self.context)
        vshader = self.loadVertexShader("cube")
        fshader = self.loadFragmentShader("cube")
        self.program.addShader(vshader)  # adding vertex shader
        self.program.addShader(fshader)  # adding fragment shader
        self.program.bindAttributeLocation("aPos", 0)
        self.program.bindAttributeLocation("aTexCoord", 1)

        isLinked = self.program.link()
        print("cube shader program is linked: ", isLinked)
        # bind the program
        self.program.bind()

        self.program.setUniformValue('myTexture1', self.texUnit1)
        self.program.setUniformValue('myTexture2', self.texUnit2)
        #
        # deal with vaos and vbo
        # vbo
        isVbo = self.vbo.create()
        isVboBound = self.vbo.bind()

        floatSize = ctypes.sizeof(ctypes.c_float)

        # allocate space on vbo buffer
        self.vbo.allocate(self.cubeVertices.tobytes(),
                          floatSize * self.cubeVertices.size)
        self.vao.create()
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        funcs.glEnableVertexAttribArray(0)  # viewport
        funcs.glVertexAttribPointer(0, 3, int(pygl.GL_FLOAT),
                                    int(pygl.GL_FALSE), 5 * floatSize,
                                    VoidPtr(0))
        funcs.glEnableVertexAttribArray(1)
        funcs.glVertexAttribPointer(1, 2, int(pygl.GL_FLOAT),
                                    int(pygl.GL_FALSE), 5 * floatSize,
                                    VoidPtr(3 * floatSize))
        # deal with textures
        # first texture
        self.texture1 = QOpenGLTexture(QOpenGLTexture.Target2D)
        self.texture1.create()
        self.texture1.bind(self.texUnit1)
        self.texture1.setData(self.image1)
        self.texture1.setMinMagFilters(QOpenGLTexture.Nearest,
                                       QOpenGLTexture.Nearest)
        self.texture1.setWrapMode(QOpenGLTexture.DirectionS,
                                  QOpenGLTexture.Repeat)
        self.texture1.setWrapMode(QOpenGLTexture.DirectionT,
                                  QOpenGLTexture.Repeat)

        # second texture
        self.texture2 = QOpenGLTexture(QOpenGLTexture.Target2D)
        self.texture2.create()
        self.texture2.bind(self.texUnit2)
        self.texture2.setData(self.image2)
        self.texture2.setMinMagFilters(QOpenGLTexture.Linear,
                                       QOpenGLTexture.Linear)
        self.texture2.setWrapMode(QOpenGLTexture.DirectionS,
                                  QOpenGLTexture.Repeat)
        self.texture2.setWrapMode(QOpenGLTexture.DirectionT,
                                  QOpenGLTexture.Repeat)

        self.vbo.release()
        vaoBinder = None
        print("gl initialized")

    def paintGL(self):
        "drawing loop"
        funcs = self.context.functions()

        # clean up what was drawn
        funcs.glClear(pygl.GL_COLOR_BUFFER_BIT | pygl.GL_DEPTH_BUFFER_BIT)
        self.vao.bind()
        self.vbo.bind()

        # actual drawing
        self.program.bind()
        # set projection matrix
        projectionMatrix = QMatrix4x4()
        projectionMatrix.perspective(self.camera.zoom,
                                     self.width() / self.height(), 0.2, 100.0)

        self.program.setUniformValue('projection', projectionMatrix)

        # set view/camera matrix
        viewMatrix = self.camera.getViewMatrix()
        self.program.setUniformValue('view', viewMatrix)

        # bind textures
        for i, pos in enumerate(self.cubeCoords):
            #
            cubeModel = QMatrix4x4()
            cubeModel.translate(pos)
            angle = 30 * i
            cubeModel.rotate(angle, self.rotateVector)
            self.program.setUniformValue("model", cubeModel)
            self.texture1.bind(self.texUnit1)
            self.texture2.bind(self.texUnit2)
            funcs.glDrawArrays(pygl.GL_TRIANGLES, 0, 36)
        self.vbo.release()
        self.program.release()
        self.texture1.release()
        self.texture2.release()
class GLWidget(QOpenGLWidget, QOpenGLFunctions):
    xRotationChanged = Signal(int)
    yRotationChanged = Signal(int)
    zRotationChanged = Signal(int)
    zoomChanged = Signal(int)
    fileSaved = Signal()

    def __init__(self, parent=None):
        QOpenGLWidget.__init__(self, parent)
        QOpenGLFunctions.__init__(self)

        self.core = "--coreprofile" in QCoreApplication.arguments()
        self.xRot = 0
        self.yRot = 0
        self.zRot = 4327
        self.zoom = 0
        self.lastPos = 0
        self.lithophane = Lithophane()
        self.vao = QOpenGLVertexArrayObject()
        self.lithophaneVbo = QOpenGLBuffer()
        self.program = QOpenGLShaderProgram()
        self.projMatrixLoc = 0
        self.mvMatrixLoc = 0
        self.normalMatrixLoc = 0
        self.lightPosLoc = 0
        self.proj = QMatrix4x4()
        self.camera = QMatrix4x4()
        self.world = QMatrix4x4()
        self.transparent = "--transparent" in QCoreApplication.arguments()
        if self.transparent:
            fmt = self.format()
            fmt.setAlphaBufferSize(8)
            self.setFormat(fmt)

    def updateImage(self, img_scr):
        self.fileDir = img_scr
        self.lithophane.generateVertex(img_scr)
        self.initializeGL()

    def generateSTL(self,file_name):
        file=open(file_name, "w")
        file.write("solid lithophane\n")  
        i=0
        v_data=[]
        while(i <= self.lithophane.m_count):
           n1=self.lithophane.m_data[i]
           i+=1
           n2=self.lithophane.m_data[i]
           i+=1
           n3=self.lithophane.m_data[i]
           i+=1
           v1=self.lithophane.m_data[i]
           i+=1
           v2=self.lithophane.m_data[i]
           i+=1
           v3=self.lithophane.m_data[i]
           i+=1
           v_data.append([n1,n2,n3])
        triangle_count = 0
        for i in range(0,len(v_data)-1,4):
            q1 = v_data[i]
            q2 = v_data[i+1]
            q3 = v_data[i+2]
            q4 = v_data[i+3]
            file.write("facet normal 0.0 0.0 0.0\n")
            file.write("    outer loop\n")
            file.write("            vertex {} {} {}\n".format(np.float32(q1[0]),np.float32(q1[1]),np.float32(q1[2])))
            file.write("            vertex {} {} {}\n".format(np.float32(q2[0]),np.float32(q2[1]),np.float32(q2[2])))
            file.write("            vertex {} {} {}\n".format(np.float32(q4[0]),np.float32(q4[1]),np.float32(q4[2])))
            file.write("    end loop\n")
            file.write("endfacet\n") 
            
            file.write("facet normal 0.0 0.0 0.0\n")
            file.write("    outer loop\n")
            file.write("            vertex {} {} {}\n".format(np.float32(q2[0]),np.float32(q2[1]),np.float32(q2[2])))
            file.write("            vertex {} {} {}\n".format(np.float32(q3[0]),np.float32(q3[1]),np.float32(q3[2])))
            file.write("            vertex {} {} {}\n".format(np.float32(q4[0]),np.float32(q4[1]),np.float32(q4[2])))
            file.write("    end loop\n")
            file.write("endfacet\n") 
            triangle_count+=2
        print("Written {} triangles".format(triangle_count))
        file.close()
        self.fileSaved.emit()

    def xRotation(self):    
        return self.xRot

    def yRotation(self):
        return self.yRot

    def zRotation(self):
        return self.zRot

    def minimumSizeHint(self):
        return QSize(50, 50)

    def sizeHint(self):
        return QSize(400, 400)

    def normalizeAngle(self, angle):
        while angle < 0:
            angle += 360 * 16
        while angle > 360 * 16:
            angle -= 360 * 16
        return angle

    def setXRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.xRot:
            self.xRot = angle
            self.emit(SIGNAL("xRotationChanged(int)"), angle)
            self.update()

    def setYRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.yRot:
            self.yRot = angle
            self.emit(SIGNAL("yRotationChanged(int)"), angle)
            self.update()

    def setZRotation(self, angle):
        angle = self.normalizeAngle(angle)
        if angle != self.zRot:
            self.zRot = angle
            self.emit(SIGNAL("zRotationChanged(int)"), angle)
            print(angle)
            self.update()
    
    def setZoom(self, val):
        if val != self.zoom:
            self.zoom = -val
            self.emit(SIGNAL("zoomChanged(int)"), val)
            self.update()

    def applyParams(self, minT, maxT, step_size):
        if not self.fileDir:
            return 
        self.lithophane.setParams(minT,maxT,step_size)
        self.updateImage(self.fileDir)

    def cleanup(self):
        self.makeCurrent()
        self.lithophaneVbo.destroy()
        del self.program
        self.program = None
        self.doneCurrent()

    def vertexShaderSourceCore(self):
        return """#version 150
                in vec4 vertex;
                in vec3 normal;
                out vec3 vert;
                out vec3 vertNormal;
                uniform mat4 projMatrix;
                uniform mat4 mvMatrix;
                uniform mat3 normalMatrix;
                void main() {
                   vert = vertex.xyz;
                   vertNormal = normalMatrix * normal;
                   gl_Position = projMatrix * mvMatrix * vertex;
                }"""

    def fragmentShaderSourceCore(self):
        return """#version 150
                in highp vec3 vert;
                in highp vec3 vertNormal;
                out highp vec4 fragColor;
                uniform highp vec3 lightPos;
                void main() {
                   highp vec3 L = normalize(lightPos - vert);
                   highp float NL = max(dot(normalize(vertNormal), L), 0.0);
                   highp vec3 color = vec3(0.39, 1.0, 0.0);
                   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);
                   fragColor = vec4(col, 1.0);
                }"""


    def vertexShaderSource(self):
        return """attribute vec4 vertex;
                attribute vec3 normal;
                varying vec3 vert;
                varying vec3 vertNormal;
                uniform mat4 projMatrix;
                uniform mat4 mvMatrix;
                uniform mat3 normalMatrix;
                void main() {
                   vert = vertex.xyz;
                   vertNormal = normalMatrix * normal;
                   gl_Position = projMatrix * mvMatrix * vertex;
                }"""

    def fragmentShaderSource(self):
        return """varying highp vec3 vert;
                varying highp vec3 vertNormal;
                uniform highp vec3 lightPos;
                void main() {
                   highp vec3 L = normalize(lightPos - vert);
                   highp float NL = max(dot(normalize(vertNormal), L), 0.0);
                   highp vec3 color = vec3(0.39, 1.0, 0.0);
                   highp vec3 col = clamp(color * 0.2 + color * 0.8 * NL, 0.0, 1.0);
                   gl_FragColor = vec4(col, 1);
                }"""

    def initializeGL(self):
        self.context().aboutToBeDestroyed.connect(self.cleanup)
        self.initializeOpenGLFunctions()
        self.glClearColor(0, 0, 0, 1)

        self.program = QOpenGLShaderProgram()

        if self.core:
            self.vertexShader = self.vertexShaderSourceCore()
            self.fragmentShader = self.fragmentShaderSourceCore()
        else:
            self.vertexShader = self.vertexShaderSource()
            self.fragmentShader = self.fragmentShaderSource()

        self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, self.vertexShader)
        self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, self.fragmentShader)
        self.program.bindAttributeLocation("vertex", 0)
        self.program.bindAttributeLocation("normal", 1)
        self.program.link()

        self.program.bind()
        self.projMatrixLoc = self.program.uniformLocation("projMatrix")
        self.mvMatrixLoc = self.program.uniformLocation("mvMatrix")
        self.normalMatrixLoc = self.program.uniformLocation("normalMatrix")
        self.lightPosLoc = self.program.uniformLocation("lightPos")

        self.vao.create()
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)

        self.lithophaneVbo.create()
        self.lithophaneVbo.bind()
        float_size = ctypes.sizeof(ctypes.c_float)
        self.lithophaneVbo.allocate(self.lithophane.constData(), 300000 *6 * float_size)
        self.setupVertexAttribs()
        self.camera.setToIdentity()
        self.camera.translate(0, 0, -90)

        self.program.setUniformValue(self.lightPosLoc, QVector3D(10, 0, 20))
        self.program.release()
        vaoBinder = None

    def setupVertexAttribs(self):
        self.lithophaneVbo.bind()
        f = QOpenGLContext.currentContext().functions()
        f.glEnableVertexAttribArray(0)
        f.glEnableVertexAttribArray(1)
        float_size = ctypes.sizeof(ctypes.c_float)

        null = VoidPtr(0)
        pointer = VoidPtr(3 * float_size)
        f.glVertexAttribPointer(0, 3, int(GL.GL_FLOAT), int(GL.GL_FALSE), 6 * float_size, null)
        f.glVertexAttribPointer(1, 3, int(GL.GL_FLOAT), int(GL.GL_FALSE), 6 * float_size, pointer)
        self.lithophaneVbo.release()
    
    def paintGL(self):
        self.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
        self.glEnable(GL.GL_DEPTH_TEST)
        self.glEnable(GL.GL_CULL_FACE)

        self.world.setToIdentity()
        self.world.rotate(self.xRot / 16, 1, 0, 0)
        self.world.rotate(self.yRot / 16, 0, 1, 0)
        self.world.rotate(self.zRot / 16, 0, 0, 1)
        self.camera.setToIdentity()
        self.camera.translate(0,0,self.zoom)
        self.world.translate(-self.lithophane.width*0.5*0.2,-self.lithophane.height*0.5*0.2 , 0)
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        self.program.bind()
        self.program.setUniformValue(self.projMatrixLoc, self.proj)
        self.program.setUniformValue(self.mvMatrixLoc, self.camera * self.world)
        normalMatrix = self.world.normalMatrix()
        self.program.setUniformValue(self.normalMatrixLoc, normalMatrix)

        self.glDrawArrays(GL.GL_QUADS, 0, self.lithophane.vertexCount())
        self.program.release()
        vaoBinder = None

    def resizeGL(self, width, height):
        self.proj.setToIdentity()
        self.proj.perspective(45, width / height, 0.01, 1000)

    def mousePressEvent(self, event):
        self.lastPos = QPoint(event.pos())

    def mouseMoveEvent(self, event):
        dx = event.x() - self.lastPos.x()
        dy = event.y() - self.lastPos.y()

        if event.buttons() & Qt.LeftButton:
            self.setXRotation(self.xRot + 8 * dy)
            self.setYRotation(self.yRot + 8 * dx)
        elif event.buttons() & Qt.RightButton:
            self.setXRotation(self.xRot + 8 * dy)
            self.setZRotation(self.zRot + 8 * dx)

        self.lastPos = QPoint(event.pos())
Exemple #8
0
class TriangleGL(QOpenGLWidget):
    def __init__(self, parent=None):
        QOpenGLWidget.__init__(self, parent)

        # shaders etc
        triangleTutoDir = os.path.dirname(__file__)
        trianglePardir = os.path.join(triangleTutoDir, os.pardir)
        trianglePardir = os.path.realpath(trianglePardir)
        mediaDir = os.path.join(trianglePardir, "media")
        shaderDir = os.path.join(mediaDir, "shaders")
        print(shaderDir)
        availableShaders = ["triangle"]
        self.shaders = {
            name: {
                "fragment": os.path.join(shaderDir, name + ".frag"),
                "vertex": os.path.join(shaderDir, name + ".vert")
            }
            for name in availableShaders
        }
        self.core = "--coreprofile" in QCoreApplication.arguments()

        # opengl data related
        self.context = QOpenGLContext()
        self.vao = QOpenGLVertexArrayObject()
        self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        self.program = QOpenGLShaderProgram()

        # some vertex data for corners of triangle
        self.vertexData = np.array(
            [
                -0.5,
                -0.5,
                0.0,  # x, y, z
                0.5,
                -0.5,
                0.0,  # x, y, z
                0.0,
                0.5,
                0.0
            ],  # x, y, z
            dtype=ctypes.c_float)
        # triangle color
        self.triangleColor = QVector4D(0.5, 0.5, 0.0, 0.0)  # yellow triangle
        # notice the correspondance the vec4 of fragment shader
        # and our choice here

    def loadShader(self, shaderName: str, shaderType: str):
        "Load shader"
        shader = self.shaders[shaderName]
        shaderSourcePath = shader[shaderType]
        if shaderType == "vertex":
            shader = QOpenGLShader(QOpenGLShader.Vertex)
        else:
            shader = QOpenGLShader(QOpenGLShader.Fragment)
        #
        isCompiled = shader.compileSourceFile(shaderSourcePath)

        if isCompiled is False:
            print(shader.log())
            raise ValueError(
                "{0} shader {2} known as {1} is not compiled".format(
                    shaderType, shaderName, shaderSourcePath))
        return shader

    def loadVertexShader(self, shaderName: str):
        "load vertex shader"
        return self.loadShader(shaderName, "vertex")

    def loadFragmentShader(self, shaderName: str):
        "load fragment shader"
        return self.loadShader(shaderName, "fragment")

    def getGlInfo(self):
        "Get opengl info"
        info = """
            Vendor: {0}
            Renderer: {1}
            OpenGL Version: {2}
            Shader Version: {3}
            """.format(pygl.glGetString(pygl.GL_VENDOR),
                       pygl.glGetString(pygl.GL_RENDERER),
                       pygl.glGetString(pygl.GL_VERSION),
                       pygl.glGetString(pygl.GL_SHADING_LANGUAGE_VERSION))
        return info

    def initializeGL(self):
        print('gl initial')
        print(self.getGlInfo())
        # create context and make it current
        self.context.create()
        self.context.aboutToBeDestroyed.connect(self.cleanUpGl)

        # initialize functions
        funcs = self.context.functions()
        funcs.initializeOpenGLFunctions()
        funcs.glClearColor(1, 1, 1, 1)

        # deal with shaders
        shaderName = "triangle"
        vshader = self.loadVertexShader(shaderName)
        fshader = self.loadFragmentShader(shaderName)

        # creating shader program
        self.program = QOpenGLShaderProgram(self.context)
        self.program.addShader(vshader)  # adding vertex shader
        self.program.addShader(fshader)  # adding fragment shader

        # bind attribute to a location
        self.program.bindAttributeLocation("aPos", 0)

        # link shader program
        isLinked = self.program.link()
        print("shader program is linked: ", isLinked)

        # bind the program
        self.program.bind()

        # specify uniform value
        colorLoc = self.program.uniformLocation("color")
        self.program.setUniformValue(colorLoc, self.triangleColor)

        # self.useShader("triangle")

        # deal with vao and vbo

        # create vao and vbo

        # vao
        isVao = self.vao.create()
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)

        # vbo
        isVbo = self.vbo.create()
        isBound = self.vbo.bind()

        # check if vao and vbo are created
        print('vao created: ', isVao)
        print('vbo created: ', isVbo)

        floatSize = ctypes.sizeof(ctypes.c_float)

        # allocate space on buffer
        self.vbo.allocate(self.vertexData.tobytes(),
                          floatSize * self.vertexData.size)
        funcs.glEnableVertexAttribArray(0)
        nullptr = VoidPtr(0)
        funcs.glVertexAttribPointer(0, 3, int(pygl.GL_FLOAT),
                                    int(pygl.GL_FALSE), 3 * floatSize, nullptr)
        self.vbo.release()
        self.program.release()
        vaoBinder = None

    def cleanUpGl(self):
        "Clean up everything"
        self.context.makeCurrent()
        self.vbo.destroy()
        del self.program
        self.program = None
        self.doneCurrent()

    def resizeGL(self, width: int, height: int):
        "Resize the viewport"
        funcs = self.context.functions()
        funcs.glViewport(0, 0, width, height)

    def paintGL(self):
        "drawing loop"
        funcs = self.context.functions()

        # clean up what was drawn
        funcs.glClear(pygl.GL_COLOR_BUFFER_BIT)

        # actual drawing
        vaoBinder = QOpenGLVertexArrayObject.Binder(self.vao)
        self.program.bind()
        funcs.glDrawArrays(
            pygl.GL_TRIANGLES,  # mode
            0,  # first
            3)  # count
        self.program.release()
        vaoBinder = None