rss_feed

Drawing a cube while rendering widgets

homeHome
pagespython
pagesopengl
pageskivy
pagesglsl

Cube with widgets

Example shaded 3D cube

Now 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()