def render(self, camera):
        self._shader.bind()

        if self._backface_cull:
            self._gl.glEnable(self._gl.GL_CULL_FACE)
        else:
            self._gl.glDisable(self._gl.GL_CULL_FACE)

        if self._render_type == self.RenderType.Solid:
            self._gl.glEnable(self._gl.GL_DEPTH_TEST)
            self._gl.glDepthMask(self._gl.GL_TRUE)
        elif self._render_type == self.RenderType.Transparent:
            self._gl.glEnable(self._gl.GL_DEPTH_TEST)
            self._gl.glDepthMask(self._gl.GL_FALSE)
        elif self._render_type == self.RenderType.Overlay:
            self._gl.glDisable(self._gl.GL_DEPTH_TEST)

        if self._blend_mode == self.BlendMode.NoBlending:
            self._gl.glDisable(self._gl.GL_BLEND)
        elif self._blend_mode == self.BlendMode.Normal:
            self._gl.glEnable(self._gl.GL_BLEND)
            self._gl.glBlendFunc(self._gl.GL_SRC_ALPHA, self._gl.GL_ONE_MINUS_SRC_ALPHA)
        elif self._blend_mode == self.BlendMode.Additive:
            self._gl.glEnable(self._gl.GL_BLEND)
            self._gl.glBlendFunc(self._gl.GL_SRC_ALPHA, self._gl.GL_ONE)

        if self._state_setup_callback:
            self._state_setup_callback(self._gl)

        self._view_matrix = camera.getWorldTransformation().getInverse()
        self._projection_matrix = camera.getProjectionMatrix()
        self._view_projection_matrix = camera.getProjectionMatrix().multiply(self._view_matrix)

        self._shader.updateBindings(
            view_matrix = self._view_matrix,
            projection_matrix = self._projection_matrix,
            view_projection_matrix = self._view_projection_matrix,
            view_position = camera.getWorldPosition(),
            light_0_position = camera.getWorldPosition() + Vector(0, 50, 0)
        )

        # The VertexArrayObject (VAO) works like a VCR, recording buffer activities in the GPU.
        # When the same buffers are used elsewhere, one can bind this VertexArrayObject to
        # the context instead of uploading all buffers again.
        if OpenGLContext.properties["supportsVertexArrayObjects"]:
            vao = QOpenGLVertexArrayObject()
            vao.create()
            if not vao.isCreated():
                Logger.log("e", "VAO not created. Hell breaks loose")
            vao.bind()

        for item in self._items:
            self._renderItem(item)

        if self._state_teardown_callback:
            self._state_teardown_callback(self._gl)

        self._shader.release()
Beispiel #2
0
    def _vertexBuffersSetup(
            self, mesh: MeshData) -> Optional[QOpenGLVertexArrayObject]:
        # See if the mesh has already been stored to the GPU:
        vao = cast(Optional[QOpenGLVertexArrayObject],
                   mesh.getCachedUserValue(self._shader.getReferenceKey()))
        if vao is not None:
            return vao

        # Initialize VAO (VertexArrayObject). On activation, this will wrap around the other vertex/index buffers.
        # That enables reusing them without much fuss.
        if not OpenGLContext.properties["supportsVertexArrayObjects"]:
            Logger.log(
                "e",
                "RenderBatch: This OpenGL doesn't support VAO? You will not go to R^3 today."
            )
            return None

        vao = QOpenGLVertexArrayObject()
        vao.create()
        if not vao.isCreated():
            Logger.log(
                "e",
                "RenderBatch: VAO not created. You will not go to R^3 today.")
            return None

        # Setup VAO:
        vao.bind()

        vertex_buffer = OpenGL.getInstance().createVertexBuffer(mesh)
        vertex_buffer.bind()

        index_buffer = OpenGL.getInstance().createIndexBuffer(mesh)
        if index_buffer is not None:
            index_buffer.bind()

        self._setMeshAttributes(mesh)

        # Cache and return:
        mesh.setCachedUserValue(self._shader.getReferenceKey(), vao)
        vao.release()
        return vao