Cube with widgets
Example shaded 3D cubeNow we will expand on the previous example and add a cube class which will give us a cube to work with.
In this example we use a .kv file and create some widgets we also load a custom widget to load our scene into.
This should give you a good idea of rendering your own scene and usig kivy widgets to control the scene if you need to later on.
Pack a load of widgets around our model, we will not do anything with these other than draw them to the screen.
1 2 3 4 5 6 7 8 9 10 11 12 |
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()
|
below is the interface fille that is loaded to pack a load of widgets around our model, we will not do anything with these other than display them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#: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:
Accordion:
orientation: 'vertical'
AccordionItem:
title: 'Panel 1'
Button:
text: 'Button 1'
Button:
text: 'Button 2'
Button:
text: 'Button 3'
AccordionItem:
title: 'Panel 2'
Button:
text: 'Button 4'
Button:
text: 'Button 5'
Button:
text: 'Button 6'
AccordionItem:
title: 'Panel 3'
Button:
text: 'Button 7'
Button:
text: 'Button 8'
Button:
text: 'Button 9'
OpenglWidget:
width: 200
height: 200
TreeView:
label: 'Toolsets'
BoxLayout:
height: 40
size_hint_y: None
Button:
text: 'Button 1'
Button:
text: 'button 2'
|
Very simple solid colour shader for our cube.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
---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 = frag_color;
}
|
This is the meat of the code it creates a custom widget, it gets loaded from the interface file above and then handlers rendering the scene .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
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
class point:
__slots__ = ['x', 'y', 'z', 'xyz', 'vertex']
def __init__(self, p, c=(1, 0, 0)):
""" Position in 3d space as a tuple or list, and colour in tuple or list format"""
self.x, self.y, self.z = p
self.vertex = array([self.x, self.y, self.z, c[0], c[1], c[2]], 'f')
class cube:
def __init__(self, p1, color, size=0.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 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,
)
class OpenglWidget(Widget):
def __init__(self, **kwargs):
self.canvas = RenderContext(compute_normal_mat=True)
self.canvas.shader.source = resource_find('kivy.glsl')
self.c = cube((0, 0, 0), (1, 0, 0), 2.0)
self.vertices = []
for item in self.c.get_data():
for a in item:
self.vertices.append(a)
self.vertices.append(1) # add alpha
self.indices = range(0, len(self.vertices))
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 / 60.)
def setup_gl_context(self, *args):
glEnable(GL_DEPTH_TEST)
def reset_gl_context(self, *args):
glDisable(GL_DEPTH_TEST)
def update_glsl(self, *largs):
aspect = float(self.height) / float(self.width)
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.rot.angle += 1
def setup_scene(self):
Color(0, 0, 0, 1)
PushMatrix()
self.rot = Rotate(1, 0, 1, 0)
vertex_format = [
('v_pos', 3, 'float'),
('v_color', 4, 'float'),
]
UpdateNormalMatrix()
self.mesh = Mesh(
vertices=self.vertices,
indices=self.indices,
fmt=vertex_format,
mode='triangles',
)
PopMatrix()
|