Skip to content

Instantly share code, notes, and snippets.

@olymk2
Last active June 17, 2022 05:30
Show Gist options
  • Save olymk2/cf0b9f44543b853d94e0 to your computer and use it in GitHub Desktop.
Save olymk2/cf0b9f44543b853d94e0 to your computer and use it in GitHub Desktop.
kivy fbo with multiple shaders
import os
import sys
import time
from kivy.app import App
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.core.image import Image
from kivy.uix.widget import Widget
from kivy.uix.stencilview import StencilView
from kivy.resources import resource_find
from kivy.graphics.transformation import Matrix
from kivy.graphics.opengl import *
from kivy.graphics import *
from kivy.graphics.opengl import glEnable
from kivy.graphics.fbo import Fbo
from kivy.graphics import Color, Rectangle, Canvas
from numpy import array
#https://github.com/Kovak/KivyExamples/blob/master/Drawing_Multiple_Shapes_Shaders/main.py
#https://github.com/kivy/kivy/wiki/Advanced-Graphics:-In-Progress
#https://github.com/Kovak/KivEnt/blob/new_rendering/modules/core/kivent_core/renderers.pyx#L311
gui = """
#:kivy 1.0
FloatLayout:
GridLayout:
cols: 1
row_force_default: False
padding: 5
BoxLayout:
height: 80
size_hint_y: None
Button:
text: 'Button 1'
Button:
text: 'Button 2'
BoxLayout:
StencilView:
FramebufferWidget:
width: 200
height: 200
BoxLayout:
height: 40
size_hint_y: None
Button:
text: 'Button 1'
Button:
text: 'button 2'"""
shader1_vs = """
#ifdef GL_ES
precision highp float;
#endif
attribute vec3 v_pos;
attribute vec4 v_color;
uniform mat4 modelview_mat;
uniform mat4 projection_mat;
varying vec4 frag_color;
void main (void) {
vec4 pos = modelview_mat * vec4(v_pos,1.0);
gl_Position = projection_mat * pos;
frag_color = v_color;
}"""
shader1_fs = """
#ifdef GL_ES
precision highp float;
#endif
varying vec4 frag_color;
void main (void){
gl_FragColor = vec4(0, 0, 1, 1);
}"""
shader2_vs = """
#ifdef GL_ES
precision highp float;
#endif
attribute vec3 v_pos;
attribute vec4 v_color;
uniform mat4 modelview_mat;
uniform mat4 projection_mat;
varying vec4 frag_color;
void main (void) {
vec4 pos = modelview_mat * vec4(v_pos,1.0);
gl_Position = projection_mat * pos;
frag_color = v_color;
}"""
shader2_fs = """
#ifdef GL_ES
precision highp float;
#endif
varying vec4 frag_color;
void main (void){
gl_FragColor = vec4(0, 1, 0, 1);
}"""
class point:
__slots__ = ['x', 'y', 'z', 'xyz', 'vertex']
def __init__(self, p, c=(1, 0, 0)):
self.x, self.y, self.z = p
self.vertex = array([self.x, self.y, self.z, c[0], c[1], c[2], 1], 'f')
class cube:
def __init__(self, p1, color, size=1.5):
self.color = array([1, 0, 0], 'f')
self.points = (
point((p1[0] - size, p1[1] + size, p1[2] - size), (color)),
point((p1[0] - size, p1[1] + size, p1[2] + size), (color)),
point((p1[0] + size, p1[1] + size, p1[2] + size), (color)),
point((p1[0] + size, p1[1] + size, p1[2] - size), (color)),
point((p1[0] - size, p1[1] - size, p1[2] - size), (color)),
point((p1[0] - size, p1[1] - size, p1[2] + size), (color)),
point((p1[0] + size, p1[1] - size, p1[2] + size), (color)),
point((p1[0] + size, p1[1] - size, p1[2] - size), (color)),
)
def move_test(self):
for p in self.points:
print p.x
#~ print dir(p)
p.x = p.x + 0.1
print p.x
def get_data(self):
return (
self.points[0].vertex, self.points[2].vertex, self.points[1].vertex,
self.points[0].vertex, self.points[3].vertex, self.points[2].vertex,
self.points[0].vertex, self.points[1].vertex, self.points[5].vertex,
self.points[0].vertex, self.points[5].vertex, self.points[4].vertex,
self.points[0].vertex, self.points[7].vertex, self.points[3].vertex,
self.points[0].vertex, self.points[4].vertex, self.points[7].vertex,
self.points[6].vertex, self.points[3].vertex, self.points[2].vertex,
self.points[6].vertex, self.points[3].vertex, self.points[7].vertex,
self.points[6].vertex, self.points[1].vertex, self.points[2].vertex,
self.points[6].vertex, self.points[5].vertex, self.points[1].vertex,
self.points[6].vertex, self.points[4].vertex, self.points[5].vertex,
self.points[6].vertex, self.points[7].vertex, self.points[4].vertex,
)
def get_vertices(self):
return [point for tri in self.get_data() for point in tri]
def get_indices(self):
return range(0, 36)
class FramebufferWidget(Widget):
def __init__(self, **kwargs):
self.canvas = RenderContext()
super(FramebufferWidget, self).__init__(**kwargs)
self.cube_widget1 = RenderContext(use_parent_modelview=True, use_parent_projection=True)
self.cube_widget1.shader.fs = shader1_fs
self.cube_widget1.shader.vs = shader1_vs
self.cube_widget2 = RenderContext(use_parent_modelview=True, use_parent_projection=True)
self.cube_widget2.shader.fs = shader2_fs
self.cube_widget2.shader.vs = shader2_vs
self.cube1 = cube((0, -10.0, 0), (1, 0, 0), 8.5)
self.cube2 = cube((0, 10.0, 0), (0, 1, 0), 8.5)
self.canvas.add(self.cube_widget1)
self.canvas.add(self.cube_widget2)
self.kivy_setup()
def kivy_setup(self):
self.rot1 = Rotate(1, 0, 1, 0)
self.rot2 = Rotate(1, 0, 1, 0)
self.canvas.add(self.cube_widget1)
self.canvas.add(self.cube_widget2)
with self.canvas:
self.cb = Callback(self.setup_gl_context)
PushMatrix()
self.setup_scene()
PopMatrix()
self.cb = Callback(self.reset_gl_context)
Clock.schedule_interval(self.update_glsl, 1 / 5.)
def gl_error(self, text = '', kill=False):
err = glGetError()
if not err:
return
while err:
print '## GL ## = ' + text + 'OPENGL Error Code = ', err
err = glGetError()
if kill == True:
sys.exit(0)
def setup_gl_context(self, *args):
glEnable(GL_DEPTH_TEST)
def reset_gl_context(self, *args):
glDisable(GL_DEPTH_TEST)
def camera(self, viewport, field_of_view, aspect, near_plane, far_plane, location, lookat):
"""call this when ever the screen is updated calculates whats visible and where the camera exists"""
matrix_projection = Matrix()
matrix_projection.identity()
matrix_projection.perspective(field_of_view, aspect, near_plane, far_plane)
matrix_model_view = Matrix().look_at(
location[0], location[1], location[2],
lookat[0], lookat[1], lookat[2],
0.0, 1.0, 0.0)
return (matrix_projection, matrix_model_view)
def update_glsl(self, *largs):
aspect = float(self.width) / float(self.height)
aspect = float(self.height) / float(self.width)
projection_mat, model_mat = self.camera(
viewport=None, field_of_view=45.0, aspect=aspect, near_plane=1.0, far_plane=80, location=(0, 0, 20.0), lookat=(0, 0, 0))
self.gl_error('test1')
self.canvas['projection_mat'] = projection_mat
self.canvas['modelview_mat'] = model_mat
self.gl_error('test1')
self.rot1.angle += 1
self.rot2.angle += 1
self.cube1.move_test()
self.cube2.move_test()
self.setup_scene()
def setup_scene(self):
vertex_format = [
('v_pos', 3, 'float'),
('v_color', 4, 'float'),
]
self.cube1.move_test()
PushMatrix()
with self.cube_widget1:
self.mesh = Mesh(
vertices=self.cube1.get_vertices(),
indices=self.cube1.get_indices(),
fmt=vertex_format,
mode='triangles',
)
PopMatrix()
self.cube2.move_test()
PushMatrix()
with self.cube_widget2:
#self.rot2 = Rotate(1, 0, 1, 0)
self.mesh = Mesh(
vertices=self.cube2.get_vertices(),
indices=self.cube2.get_indices(),
fmt=vertex_format,
mode='triangles',
)
PopMatrix()
class FramebuffertestApp(App):
def build(self):
return Builder.load_string(gui)
if __name__ == '__main__':
FramebuffertestApp().run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment