Glsl 如何更改kivy RenderContext的片段着色器?

Glsl 如何更改kivy RenderContext的片段着色器?,glsl,kivy,post-processing,Glsl,Kivy,Post Processing,我有一个kivy应用程序,我希望在特定RenderContext上绘制的所有内容都应用着色器后处理效果,类似于文档中kivy示例中的EffectWidget示例中演示的效果 在world小部件的构造函数中,我创建了RenderContext 设置它的投影矩阵,这样就行了 self.prc['projection_mat'] = proj_mat 然后尝试将其片段着色器设置为默认片段着色器的最小副本,使所有内容都成为不透明的十分之一,基本上使屏幕变暗 self.prc.shader.fs = "

我有一个kivy应用程序,我希望在特定RenderContext上绘制的所有内容都应用着色器后处理效果,类似于文档中kivy示例中的EffectWidget示例中演示的效果

在world小部件的构造函数中,我创建了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()

着色器不能堆叠在管道中。只使用最新的绑定,这不是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))

我错过了这里所有的颜色和其他参数,但这只是为了演示。可以像在RenderContext上一样更改Fbo上的着色器。

着色器不能堆叠在管道中。只使用最新的绑定,这不是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))

我错过了这里所有的颜色和其他参数,但这只是为了演示。您可以像在RenderContext上一样更改Fbo上的着色器。

我认为我的整个方法可能是错误的,也许kivy的Fbo类更好地提供了我想要的功能。但不确定-现在正在研究这个问题。要运行示例代码,我必须在着色器中将vTexCoords0替换为tex_coord0。我已经运行了kivy 1.9.1。我认为我的整个方法可能是错误的,也许我想要的功能是由kivy的fbo类提供的。但不确定-现在正在研究这个问题。要运行示例代码,我必须在着色器中将vTexCoords0替换为tex_coord0。我有kivy 1.9.1在运行。