2014-12-07 41 views
1

我有一個kivy應用程序,我希望在特定RenderContext上繪製的所有東西都具有着色器後處理效果(類似於文檔中kivy示例中的EffectWidget示例中演示的效果)。如何更改kivy RenderContext的片段着色器?

world控件的構造函數創建了RenderContext

self.prc = RenderContext() 

設置它的投影矩陣(這工作)

self.prc['projection_mat'] = proj_mat 

,然後嘗試它的片段着色器設置爲最小副本默認的片段着色器應該使所有東西都變爲不透明(基本上調暗屏幕)的十分之一。

self.prc.shader.fs = """ 
#ifdef GL_ES 
    precision highp float; 
#endif 

/* Outputs from the vertex shader */ 
varying vec4 frag_color; 
varying vec2 tex_coord0; 

/* uniform texture samplers */ 
uniform sampler2D texture0; 

void main (void){ 
    gl_FragColor = 0.1*frag_color * texture2D(texture0, tex_coord0); 
} 
""" 

如果此着色器的代碼不正確,程序不運行,抱怨着色器的編譯錯誤,這表示着色器正在編制。但是,我沒有看到着色器的任何影響。一切呈現在prc上,但在正常的不透明度。我究竟做錯了什麼?謝謝你的時間!


編輯!

我被要求提供一個完整的可運行示例。以下程序繪製兩個矩形。左邊的矩形具有自己的RenderContext,不受灰度後處理影響(它被繪製爲紅色)。右邊的矩形沒有自己的RenderContext,它正確地受到後處理影響,因此

下面是代碼:

from kivy.app import App 
from kivy.uix.widget import Widget 
from kivy.uix.floatlayout import FloatLayout 
from kivy.graphics import * 
from kivy.graphics.opengl import * 
from kivy.graphics.shader import * 
from kivy.core.window import Window 
from kivy.graphics.transformation import Matrix 

from kivy.logger import Logger 

class World(Widget) : 
    def __init__(self, **kwargs): 
     Logger.debug('world.init()') 

     # Parent RenderContext for subsuming all other render contexts 
     self.prc=RenderContext() 
     proj_mat = Matrix() 
     proj_mat.look_at(0.,0.,1., # eye position coords 
         0.,0.,0., # looking at these coords 
         0,1.,0) # a vector that points up 

     if Window.height > Window.width : 
      self.xRadius = float(Window.width)/Window.height 
      self.yRadius = 1.0 
      proj_mat.scale(1.0/self.xRadius,1.0,1.0) 
     else : 
      self.xRadius = 1.0 
      self.yRadius = float(Window.height)/Window.width 
      proj_mat.scale(1.0,1.0/self.yRadius,1.0) 

     self.prc['projection_mat'] = proj_mat 

     ## an effect shader used to make objects monochromatic (grayscale) 
     self.prc.shader.fs = """ 
#ifdef GL_ES 
precision highp float; 
#endif 

/* Outputs from the vertex shader */ 
varying vec4 frag_color; 
varying vec2 vTexCoords0; 

/* uniform texture samplers */ 
uniform sampler2D texture0; 

uniform vec2 resolution; 
uniform float time; 

void main() { 
    vec4 rgb = texture2D(texture0, vTexCoords0); 
    float c = (rgb.x + rgb.y + rgb.z) * 0.3333; 
    gl_FragColor = vec4(c, c, c, 1.0); 
} 
""" 

     if not self.prc.shader.success : 
      raise Exception('Effect shader compile failed.') 

     self.canvas = self.prc 

     ## Left Rectangle drawn with its own RenderContext 
     ## this is not affected by the effect shader (if it were, it would be drawn as white) 
     ## but it is affected by the parent's projection matrix 
     self.spriteRC = RenderContext(use_parent_projection=True) 
     self.spriteRC.add(Color(1,0,0,1)) 
     self.spriteRC.add(Rectangle(pos=(-0.25,0.0),size=(0.1,0.1))) 

     ## Right Rectangle object drawn directly to the canvas 
     ## this **is** affected by the effect shader 
     self.canvas.add(Color(1,0,0,1)) 
     self.canvas.add(Rectangle(pos=(0.25,0),size=(0.1,0.1))) 
     self.canvas.add(self.spriteRC) 



     super(World, self).__init__(**kwargs) 

class GameApp(App): 
    def build(self): 
     w = World() 
     fl = FloatLayout() 
     fl.add_widget(w) 
     return fl 

if __name__ == '__main__': 
    GameApp().run() 
+0

我認爲我的整個方法可能是錯的,也許我想要的功能更好地由kivy的'fbo'類提供。不確定 - 現在正在調查。 – weemattisnot 2014-12-07 19:44:04

+0

要運行示例代碼,我必須在着色器中用''tex_coord0''替換''vTexCoords0''。我有Kivy 1.9.1運行。 – Rolf 2016-05-23 15:48:21

回答

5

着色器不能在管道堆積。只有最新的綁定會被使用,它不是Kivy的限制,但這就是OpenGL的工作原理。即:

self.c1 = RenderContext() 
self.c2 = RenderContext() 
self.c2.add(Rectangle()) 
self.c1.add(self.c2) 

該矩形將只處理最新的着色器,在c2中的一個。

爲了讓矩形具有特定的着色器,然後使用c1着色器處理輸出,請使用Framebuffer(Fbo是RenderContext子類)!

self.c1 = RenderContext() 
self.c2 = Fbo(size=...) 
self.c2.add(Rectangle()) 
self.c1.add(self.c2) # this is just for triggering the render from c1 when c2 content changes 
self.c1.add(Rectangle(size=self.c2.size, texture=self.c2.texture)) 

我錯過了所有的Color和其他參數,但它只是爲了演示。您可以像在RenderContext上一樣更改Fbo上的着色器。