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
廣告