9.0 KiB
Executable File
9.0 KiB
Executable File
Draw two cubes using Kivy with different shaders.
.. title: Draw two cubes using Kivy with different shaders. .. slug: drawing-two-cubes-with-different-shaders-using-kivy .. date: 2014-09-01 12:00:00 UTC .. tags: python, opengl, kivy, glsl .. category: python .. description: Kivy example draw two cubes with different shaders and vertices so they can be moved seperately. .. type: text

Expanding on the last example this code demonstrates loading multiple models and using different shaders per model.
import kivy
kivy.require('1.0.7')
from kivy.app import App
from opengl_widget import OpenglWidget
class DemoApp(App):
pass
if __name__ == '__main__':
DemoApp().run()
#:kivy 1.0
FloatLayout:
OpenglWidget:
First shader to create a green object.
---VERTEX SHADER-------------------------------------------------------
#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;
}
---FRAGMENT SHADER-----------------------------------------------------
#ifdef GL_ES
precision highp float;
#endif
varying vec4 frag_color;
varying vec2 uv_vec;
uniform sampler2D tex;
void main (void){
gl_FragColor = vec4(0, 1, 0, 1);
}
Second shader creates a blue object.
---VERTEX SHADER-------------------------------------------------------
#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;
}
---FRAGMENT SHADER-----------------------------------------------------
#ifdef GL_ES
precision highp float;
#endif
varying vec4 frag_color;
varying vec2 uv_vec;
uniform sampler2D tex;
void main (void){
gl_FragColor = vec4(0, 0, 1, 1);
}
import os
import sys
from kivy.app import App
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.resources import resource_find
from kivy.graphics.transformation import Matrix
from kivy.graphics.opengl import *
from kivy.graphics import *
from kivy.uix.widget import Widget
from kivy.graphics import Color, Ellipse
from numpy import array
#store a single vertex in this class
class point:
def __init__(self, p, c=(1, 0, 0, 1)):
self.x, self.y, self.z = p
self.vertex = array([self.x, self.y, self.z, c[0], c[1], c[2], c[3]], 'f')
#simple class to create the vertices for a cube for testing.
class cube:
def __init__(self, p1, color=(1, 0, 0, 1), size=0.5):
self.color = array([1, 0, 0, 1], '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 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[2].vertex, self.points[3].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,
)
#custom widget for render our scene into
class OpenglWidget(Widget):
def __init__(self, **kwargs):
self.instructions = InstructionGroup()
self.canvas = RenderContext(compute_normal_mat=True)
self.canvas.shader.source = resource_find('kivy.glsl')
#create first shader for cube 1
self.cube1 = RenderContext(compute_normal_mat=True)
self.cube1.shader.source = resource_find('kivy-blue.glsl')
#create first shader for cube 2
self.cube2 = RenderContext(compute_normal_mat=True)
self.cube2.shader.source = resource_find('kivy-green.glsl')
#create 2 cubes for testing
cube1 = cube((0, -4, 0), size = 2.0)
cube2 = cube((0, 4, 0), size = 2.0)
#generate vertex array for cube 1
self.vertices_cube1 = []
for item in cube1.get_data():
for a in item:
self.vertices_cube1.append(a)
#generate vertex array for cube 2
self.vertices_cube2 = []
for item in cube2.get_data():
for a in item:
self.vertices_cube2.append(a)
#calcualte indices for both cubes
self.indices_cube1 = range(0, 36)
self.indices_cube2 = range(0, 36)
#add our render contexts to an instruction group for drawing
self.instructions.add(self.cube1)
self.instructions.add(self.cube2)
self.canvas.add(self.instructions)
with self.canvas:
self.cb = Callback(self.setup_gl_context)
PushMatrix()
self.scene()
PopMatrix()
self.cb = Callback(self.reset_gl_context)
Clock.schedule_interval(self.update_glsl, 1 / 60.)
#create our scene and update our two models
def scene(self):
Color(0, 0, 0, 1)
with self.cube2:
self.cube1_mesh()
with self.cube1:
self.cube2_mesh()
def setup_gl_context(self, *args):
glEnable(GL_DEPTH_TEST)
def reset_gl_context(self, *args):
glDisable(GL_DEPTH_TEST)
#setup the projection matrices
def update_glsl(self, *largs):
aspect = float(self.width) / float(self.height)
projection_mat = Matrix()
projection_mat.perspective(45.0, aspect, 1.0, 80.0)
model = Matrix().look_at(
0.0, 0.0, 25.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0)
self.canvas['projection_mat'] = projection_mat
self.canvas['modelview_mat'] = model
self.cube1['projection_mat'] = projection_mat
self.cube1['modelview_mat'] = model
self.cube2['projection_mat'] = projection_mat
self.cube2['modelview_mat'] = model
self.rot_cube1.angle += 1
self.rot_cube2.angle += 1
def cube1_mesh(self):
Color(0, 0, 0, 1)
PushMatrix()
self.rot_cube1 = Rotate(1, 0, 1, 0)
vertex_format = [
('v_pos', 3, 'float'),
('v_color', 4, 'float'),
]
UpdateNormalMatrix()
self.mesh1 = Mesh(
vertices=self.vertices_cube1,
indices=self.indices_cube1,
fmt=vertex_format,
mode='triangles',
)
PopMatrix()
def cube2_mesh(self):
PushMatrix()
Color(0, 0, 0, 1)
self.rot_cube2 = Rotate(1, 0, -1, 0)
vertex_format = [
('v_pos', 3, 'float'),
('v_color', 4, 'float'),
]
UpdateNormalMatrix()
self.mesh2 = Mesh(
vertices=self.vertices_cube2,
indices=self.indices_cube2,
fmt=vertex_format,
mode='triangles',
)
PopMatrix()
def setup_scene(self):
Color(0, 0, 0, 1)
self.cube1_mesh()
self.cube1_mesh()