Kivy, glsl: why do I see a different display of the same shader?

34 views
Skip to first unread message

me2 beats

unread,
Jul 31, 2018, 11:18:45 AM7/31/18
to Kivy users support
Here is an example that demonstrates the essence of my question.

main.py
from kivy.app import App
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.graphics import RenderContext
from kivy.properties import StringProperty
from kivy.uix.widget import Widget

import kivy.core.window

shader
= '''
$HEADER$

uniform vec2 resolution;

void main(void)
{
    vec2 position = (gl_FragCoord.xy / resolution.xy);

    float color = 0.0;
    color += position.y / position.x;
    if(color < 0.2) { color = 0.2; }
    vec3 output_color = vec3(color * 1.5, color, color * 2.0);

    gl_FragColor = vec4(output_color, 1.0);
}

'''


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

   
def __init__(self, **kwargs):
       
self.canvas = RenderContext(use_parent_projection=True)
       
super(ShaderWidget, self).__init__(**kwargs)
       
self.canvas['time'] = Clock.get_boottime()
       
Clock.schedule_interval(self.update_glsl, 1 / 60.)

   
def update_glsl(self, *largs):
       
self.canvas['time'] = Clock.get_boottime()
       
self.canvas['resolution'] = [float(v) for v in self.size]

   
def on_fs(self, instance, value):
        shader
= self.canvas.shader
        shader
.fs = value

class TestApp(App):
   
def build(self):
        main_widget
= Factory.MainWidget()
        main_widget
.mini.fs = shader
        main_widget
.mini2.fs = shader
       
return main_widget

TestApp().run()

test.kv:

<MiniShaderWidget@ShaderWidget>:
    canvas:
        Color:
            rgb: 1.0, 1.0, 1.0
        Rectangle:
            pos: self.pos
            size: self.size


<MainWidget@ShaderWidget+FloatLayout>:
    mini: mini
    mini2: mini2

    BoxLayout
        MiniShaderWidget
            id: mini

        Label
            text: 'label'

        MiniShaderWidget
            id: mini2

In this app, I have a window that consists of three equal parts.


The shader from the same source (the variable shader) is drawn to the left and right.


The shader looks like a transition from white to violet.


In the middle, I added a label called "label" just to make it easier to distinguish the left shader from the right one.


I took this example and reworked it a bit from here


The question is: I expect to see the same picture on the left and right, but I see different images of the same shader. Why is this so?


Is it possible to make the same picture on the left and right?

Erik Bethke

unread,
Aug 9, 2018, 5:01:06 PM8/9/18
to Kivy users support
Hey there,

I answered your question over on stackoverflow:
https://stackoverflow.com/questions/51616095/kivy-glsl-why-do-i-see-a-different-display-of-the-same-shader/51623112?noredirect=1#comment90214260_51623112

But the TL;DR summary - you are currently rendering two identical shader widgets on top of each other and then the label in the center.

What you want to do is create to separate shader widgets in the .kv file and then have fun with their size and position properties.

me2 beats

unread,
Aug 9, 2018, 7:57:06 PM8/9/18
to Kivy users support
Hi!
Thanks for responding on stackoverflow, I accepted it.
It became much clearer, although not completely in my case, perhaps I asked the question not quite clearly.

My main goal is to use widgets with shaders without having to manually calculate and set size and position of each of them.

Please see this example:

from kivy.app import App
from kivy.lang import Builder

root
= Builder.load_string('''
BoxLayout
    Button
    Button
    Button
'''
)

class TestApp(App):
   
def build(self): return root

TestApp().run()


There is no any number here!

Here is Boxlayout, and three buttons that fill the screen space.
And we don't need to specify any values.

This makes app creation more fast, convenient and universal imo.

Now I go to the site http://glslsandbox.com/
and select several shaders (or create my own)

And I want them to be located on the same principle as in the example with boxlayout, above.

Boxlayout
    Shader1
    Shader2
    Shader3

It is necessary that I do not manually change the values ​​of the parameters inside each shader.

I want to see n shaders, reduced n times, located from left to right, and looking the way I see them in the browser on the site http://glslsandbox.com/

I suggest such a metaphor: imagine that you simultaneously launched 3 different kivy applications (on Windows or Ubuntu) and arranged these three windows 
from left to right. and in each of these windows, a shader is drawn to the entire application screen. this is what I want (but of course in one application)

Take a look at this example:

from kivy.app import App
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.graphics import RenderContext
from kivy.properties import StringProperty
from kivy.uix.widget import Widget


import kivy.core.window


shader
=
'''

$HEADER$

uniform vec2 resolution;
uniform vec2 pos;

//vec2 center = vec2(resolution.x* 1.5, resolution.y* 0.5);
vec2 center = vec2(resolution.x*0.5, resolution.y*0.5)+0.5*pos+0.5*pos;
float radius = min(resolution.x, resolution.y) * .5;

float circle(vec2 coord, vec2 center, float radius) {
  float distanceToCenter = distance(coord, center);
  return smoothstep(distanceToCenter - 2., distanceToCenter, radius);
}

void main() {
  vec2 coord = vec2(gl_FragCoord);
  vec4 color = vec4(1., 0.2, 0.6,1.);

  float isFilled = circle(coord, center, radius);
  gl_FragColor =  color*isFilled;
}


'''




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

   
def __init__(self, **kwargs):
       
self.canvas = RenderContext(use_parent_projection=True)
       
super(ShaderWidget, self).__init__(**kwargs)
       
self.canvas['time'] = Clock.get_boottime()
       
Clock.schedule_interval(self.update_glsl, 1 / 60.)

   
def update_glsl(self, *largs):
       
self.canvas['time'] = Clock.get_boottime()

        p_x
,p_y = self.pos
        s_x
,s_y = self.size
       
self.canvas['resolution'] = [float(s_x),float(s_y)]
       
self.canvas['pos'] = [float(p_x),float(p_y)]


   
def on_fs(self, instance, value):
        shader
= self.canvas.shader
        shader
.fs = value

class TestApp(App):
   
def build(self):
        main_widget
= Factory.MainWidget()
        main_widget
.mini.fs =
shader
        main_widget
.mini1.fs = shader
       
return main_widget

TestApp().run()


test.kv

<MiniShaderWidget@ShaderWidget>:
    canvas:

        Rectangle:
            pos: self.pos
            size: self.size


<MainWidget@BoxLayout>:
    mini: mini
    mini1: mini1


    Label
        text: 'label'


    Label
        text: 'label'

    MiniShaderWidget
        id: mini

    MiniShaderWidget
        id: mini1


(you can see the attached link; this is how this app looks like)


this is almost what I want, but here I changed the variable center (in shader code)
but I want it to work like this:
vec2 center = resolution * 0.5;






пятница, 10 августа 2018 г., 2:01:06 UTC+5 пользователь Erik Bethke написал:
example_shaders.png
Reply all
Reply to author
Forward
0 new messages