Kivy - 帧缓冲区



Kivy 库提供了一个名为 "Fbo" 的类,它代表帧缓冲区(Framebuffer)离屏渲染。它是一个离屏窗口,您可以在上面绘制任何图形指令,然后将其用作特定 Kivy 组件画布的纹理。

Fbo 类定义在 kivy.graphics.fbo 模块中。第一步是创建 fbo 并将 fbo 纹理用于其他矩形。

from kivy.graphics import Fbo, Color, Rectangle
with self.canvas:
   self.fbo = Fbo(size=self.size)

接下来,向 Fbo 对象添加图形指令,例如矩形。例如:

with self.fbo:
   Color(1, 0, 0, .8)
   Rectangle(size=(256, 64))
   Color(0, 1, 0, .8)
   Rectangle(size=(64, 256))

最后,将 Fbo 纹理应用于画布。

self.texture = self.fbo.texture

请注意,如果 OpenGL 上下文丢失,则 FBO 会丢失。在这种情况下,您需要使用 Fbo.add_reload_observer() 方法重新上传数据。

add_reload_observer(callback) − 添加一个回调函数,在整个图形上下文重新加载后调用。回调参数将是上下文本身。

bind() 方法将 FBO 对象绑定到当前的 opengl 上下文。这样,所有绘图操作都将在帧缓冲区内进行,直到调用 release() 方法。release() 方法释放或取消绑定帧缓冲区。

self.fbo = FBO()
self.fbo.bind()

# do any drawing command
self.fbo.release()

self.canvas = self.fbo.texture

还有一个 remove_reload_observer(callback) 方法可以从观察者列表中移除之前由 add_reload_observer() 添加的回调函数。

clear_buffer()clear_color 方法分别清除帧缓冲区和清除颜色(以 (red, green, blue, alpha) 格式)。

示例

以下代码演示了在 Kivy 应用程序中使用帧缓冲区的方法。代码的重要部分是一个名为 FboFloatLayout 的类,它继承了 Kivy 的 FloatLayout 类。

构造函数 (__init__() 方法) 在浮动布局的画布上创建一个 Fbo 对象,在其上绘制一个矩形,并将其纹理设置为画布的纹理。

def __init__(self, **kwargs):
   self.canvas = Canvas()
   with self.canvas:
      self.fbo = Fbo(size=self.size)
      self.fbo_color = Color(1, 1, 1, 1)
      self.fbo_rect = Rectangle()
   
   with self.fbo:
      ClearColor(0, 0, 0, 0)
      ClearBuffers()
   
   self.texture = self.fbo.texture
   super(FboFloatLayout, self).__init__(**kwargs)

我们将向这个 FloatLayout 类添加一个按钮,但在那之前,需要重写 add_widget() 方法,以便将图形指令添加到 fbo,然后将其添加到画布。

def add_widget(self, *args, **kwargs):
   canvas = self.canvas
   self.canvas = self.fbo
   ret = super(FboFloatLayout, self).add_widget(*args, **kwargs)
   self.canvas = canvas
   return ret

FboFloatLayout 类还具有响应大小、位置和纹理变化的回调函数。

def on_size(self, instance, value):
   self.fbo.size = value
   self.texture = self.fbo.texture
   self.fbo_rect.size = value

def on_pos(self, instance, value):
   self.fbo_rect.pos = value

def on_texture(self, instance, value):
   self.fbo_rect.texture = value

现在来看 App 类。build() 方法添加一个按钮,并应用一系列动画效果,使按钮的位置反复在上下和左右之间变化。

def anim_btn(*args):
   animate = Animation(pos=(b.pos[0], Window.height - 50))
   animate += Animation(pos=(b.pos[0], 0))
   animate += Animation(pos_hint={'center_x': 1})
   animate += Animation(pos_hint={'center_x': 0})
   animate += Animation(pos_hint={'center_x': .5})
   animate.start(b)
   animate.repeat = True
   
b.bind(on_press=anim_btn)

为了方便起见,这些代码片段已组合在完整代码列表中:

from kivy.graphics import Color, Rectangle, Canvas,
ClearBuffers, ClearColor
from kivy.graphics.fbo import Fbo
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.properties import ObjectProperty, NumericProperty
from kivy.app import App
from kivy.animation import Animation
from kivy.core.window import Window

Window.size = (720, 400)

class FboFloatLayout(FloatLayout):
   texture = ObjectProperty(None, allownone=True)

   def __init__(self, **kwargs):
      self.canvas = Canvas()
      with self.canvas:
         self.fbo = Fbo(size=self.size)
         self.fbo_color = Color(1, 1, 1, 1)
         self.fbo_rect = Rectangle()

      with self.fbo:
         ClearColor(0, 0, 0, 0)
         ClearBuffers()
         
      self.texture = self.fbo.texture
      super(FboFloatLayout, self).__init__(**kwargs)

   def add_widget(self, *args, **kwargs):
      canvas = self.canvas
      self.canvas = self.fbo
      ret = super(FboFloatLayout, self).add_widget(*args, **kwargs)
      self.canvas = canvas
      return ret
      
   def on_size(self, instance, value):
      self.fbo.size = value
      self.texture = self.fbo.texture
      self.fbo_rect.size = value

   def on_pos(self, instance, value):
      self.fbo_rect.pos = value

   def on_texture(self, instance, value):
      self.fbo_rect.texture = value

class FBOdemoApp(App):
   def build(self):
      f = FboFloatLayout()
      b = Button(text="FBO", size_hint=(None, None), pos_hint={'center_x': .5})
      f.add_widget(b)

      def anim_btn(*args):
         animate = Animation(pos=(b.pos[0], Window.height - 50))
         animate += Animation(pos=(b.pos[0], 0))
         animate += Animation(pos_hint={'center_x': 1})
         animate += Animation(pos_hint={'center_x': 0})
         animate += Animation(pos_hint={'center_x': .5})
         animate.start(b)
         animate.repeat = True
      b.bind(on_press=anim_btn)
      return f
      
FBOdemoApp().run()

输出

应用程序启动时,底部显示一个标题为 FBO 的按钮。单击该按钮后,将开始执行定义的动画效果。

kivy framebuffer.jpg
广告