2014-12-07 6 views
1

나는 특정 RenderContext에 그려진 모든 것을 원하는 shader 사후 처리 이펙트 (문서의 kivy-examples에있는 EffectWidget 예제에서 설명한 효과와 유사)가 필요한 kivy 응용 프로그램을 가지고 있습니다. world 위젯의 생성자에서 kivy RenderContext의 프래그먼트 셰이더를 변경하는 방법은 무엇입니까?

는 I은 RenderContext

self.prc = RenderContext() 

는 최소한의 복사본 프래그먼트 쉐이더를 설정하려고 한 다음 그 투영 매트릭스 (이 작동)

self.prc['projection_mat'] = proj_mat 

세트 만들 기본 조각 셰이더는 모든 것을 10 분의 1로 불투명하게 만듭니다 (기본적으로 화면을 어둡게합니다).

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으로 렌더링 된 모든 것이 그려 지지만 일반적인 불투명도입니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까? 시간 내 줘서 고마워!


EDIT!

완전한 실행 가능한 예를 제공해야합니다. 다음 프로그램은 두 개의 직사각형을 그립니다. 왼쪽의 Rectangle는 독자적인 RenderContext를 가져, 그레이 스케일의 후 처리의 영향을받지 않습니다 (빨강으로 묘화됩니다). 오른쪽의 Rectangle는 독자적인 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

+0

샘플 코드를 실행하려면 셰이더의''tex_coord0''에 의해''vTexCoords0''를 대체해야했습니다. 1.9.1을 실행 중입니다. – Rolf

답변

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)) 

여기에있는 모든 색상 및 기타 매개 변수가 빠졌지 만 데모 용입니다. Fbo에서 RenderContext에서와 같은 방식으로 쉐이더를 변경할 수 있습니다.