Last active
June 17, 2022 05:30
-
-
Save olymk2/cf0b9f44543b853d94e0 to your computer and use it in GitHub Desktop.
kivy fbo with multiple shaders
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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