Kivy - OpenGL



Kivy 框架擁有強大的圖形功能,其構建在 OpenGL 和 SDL 指令之上。Kivy 使用 OpenGL ES 2 圖形庫,並基於頂點緩衝物件和著色器。“kivy.graphics.opengl” 模組是圍繞 OpenGL 命令的 Python 包裝器。

著色器是使用者定義的程式,旨在在圖形處理器的某些階段執行。著色器是用 OpenGL 著色語言 (GLSL) 編寫的,這是一種高階著色語言,其語法基於 C 程式語言。

在 Web 上建立圖形的兩種常用著色器是頂點著色器和片段(畫素)著色器。

  • 頂點著色器 - 它們接收來自先前流水線階段的輸入(例如頂點位置、顏色和光柵化畫素),並自定義輸出到下一個階段。

  • 片段著色器 - 它們接收所有畫素的二維位置作為輸入,並自定義每個畫素的輸出顏色。

本教程不詳細討論 GLSL 的功能和語法。我們將在本章中使用一個開源著色器檔案 (kaleidoscope.glsl)。

#ifdef GL_ES
precision highp float;
#endif

uniform vec2 resolution;
uniform float time;
uniform sampler2D tex0;
uniform sampler2D tex1;

void main(void){
   vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy;
   vec2 uv;
   float a = atan(p.y,p.x);
   float r = sqrt(dot(p,p));
   
   uv.x = 7.0*a/3.1416;
   uv.y = -time+ sin(7.0*r+time) + .7*cos(time+7.0*a);
   float w = .5+.5*(sin(time+7.0*r)+ .7*cos(time+7.0*a));
   vec3 col = texture2D(tex0,uv*.5).xyz;
   gl_FragColor = vec4(col*w,1.0);
}

在我們的 Kivy 應用程式碼中,我們使用一個 .kv 檔案,它只在 FloatLayout 小部件的畫布上繪製一個矩形。

<ShaderWidget>:
   canvas:
      Color:
         rgb: 1, 0, 0
   Rectangle:
      pos: self.pos
      size: self.size

此 "kv" 檔案的 ShaderWidget 規則對應於 ShaderWidget 類。它安排一個時鐘間隔,在每秒後觸發以更新著色器定義中的 glsl 變數。

class ShaderWidget(FloatLayout):
   fs = StringProperty(None)
   def __init__(self, **kwargs):
      self.canvas = RenderContext()
      super(ShaderWidget, self).__init__(**kwargs)
      Clock.schedule_interval(self.update_glsl, 1 / 60.)

"fs" 類變數儲存來自 glsl 檔案的程式碼。來自 kivy.graphics 模組的 RenderContext() 方法儲存所有必要的繪圖資訊,即頂點著色器和片段著色器等。

"fs" StringProperty 繫結到 "on_fs()" 方法,該方法將設定著色器。

def on_fs(self, instance, value):
   shader = self.canvas.shader
   old_value = shader.fs
   shader.fs = value
   if not shader.success:
      shader.fs = old_value
      raise Exception('failed')

每次預定的時鐘事件發生時,都會呼叫 update_glsl() 方法。它基本上更新應用視窗上每個畫素的片段顏色。

def update_glsl(self, *largs):
   self.canvas['time'] = Clock.get_boottime()
   self.canvas['resolution'] = list(map(float, self.size))
   win_rc = Window.render_context
   self.canvas['projection_mat'] = win_rc['projection_mat']
   self.canvas['modelview_mat'] = win_rc['modelview_mat']
   self.canvas['frag_modelview_mat'] = win_rc['frag_modelview_mat']

App 類簡單地從 kv 檔案和類定義載入 ShaderWidget。

示例

完整的程式碼如下:

from kivy.clock import Clock
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.core.window import Window
from kivy.graphics import RenderContext
from kivy.properties import StringProperty
from kivy.core.window import Window

Window.size=(720,400)
file=open('kaleidoscope.glsl')
shader=file.read()

class ShaderWidget(FloatLayout):
   fs = StringProperty(None)

   def __init__(self, **kwargs):
      self.canvas = RenderContext()
      super(ShaderWidget, self).__init__(**kwargs)
      Clock.schedule_interval(self.update_glsl, 1 / 60.)

   def on_fs(self, instance, value):
      shader = self.canvas.shader
      old_value = shader.fs
      shader.fs = value
      if not shader.success:
         shader.fs = old_value
         raise Exception('failed')

   def update_glsl(self, *largs):
      self.canvas['time'] = Clock.get_boottime()
      self.canvas['resolution'] = list(map(float, self.size)).
      win_rc = Window.render_context
      self.canvas['projection_mat'] = win_rc['projection_mat']
      self.canvas['modelview_mat'] = win_rc['modelview_mat']
      self.canvas['frag_modelview_mat'] = win_rc['frag_modelview_mat']

class 'kaleidoscopeApp(App):
   title='kaleidoscope'
   def build(self):
      return ShaderWidget(fs=shader)

'kaleidoscopeApp().run()

輸出

執行此程式碼並檢查輸出:

kivy openGl
廣告
© . All rights reserved.