Kivy 简明教程
Kivy - Framebuffer
Kivy 库提供了一个“Fbo”类,该类表示帧缓冲区外屏。这是一个非屏幕窗口,您可以在其上绘制任何图形指令,然后将其用作某个 Kivy 小部件的画布的纹理。
Fbo 类在 kivy.graphics.fbo 模块中定义。第一步是创建 fbo 并在其他矩形上使用 fbo 纹理。
from kivy.graphics import Fbo, Color, Rectangle
with self.canvas:
self.fbo = Fbo(size=self.size)
接下来,将图形指令(例如 Rectangle)添加到 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) 格式清除帧缓冲区和清除颜色。
Example
以下代码演示了如何在 Kivy 应用程序中使用 Framebuffer。代码的重要部分是一个名为 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)
出于方便考虑,这些代码片段被整理在了 complete code 清单中 −
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()