Skip to content

Instantly share code, notes, and snippets.

@onslauth
Last active November 23, 2017 19:04
Show Gist options
  • Save onslauth/1c84ab40bda2abd38cfe39bd83d66a04 to your computer and use it in GitHub Desktop.
Save onslauth/1c84ab40bda2abd38cfe39bd83d66a04 to your computer and use it in GitHub Desktop.
from kivy.config import Config
Config.set('kivy', 'log_level', 'debug')
from kivy.app import App
from kivy.lang import Builder
from kivy.factory import Factory
from kivy.uix.boxlayout import BoxLayout
from object_renderer import ObjectRenderer
kv = """
#:import rand_float random.uniform
<Test>:
FloatLayout:
id: box
size_hint: 1.0, 1.0
canvas:
Color:
rgba: ( 0, 1, 0, 1 )
Rectangle:
pos: self.pos
size: self.size
"""
class Test(BoxLayout):
def __init__(self, *args, **kwargs):
super(Test, self).__init__(*args, **kwargs)
#self.add_label()
self.add_object( )
def add_object(self):
object_renderer = ObjectRenderer( size_hint = ( None, None ),
size = ( 300, 300 ),
pos = self.pos )
object_renderer.pos = ( 100, 100 )
self.ids.box.add_widget( object_renderer )
object_renderer.setup_canvas( )
def add_label(self):
self.ids.box.add_widget(Factory.CustomLabel())
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
Builder.load_string(kv)
TestApp().run()
from kivy.uix.widget import Widget
from kivy.resources import resource_find
from kivy.uix.image import Image
from kivy.graphics.fbo import Fbo
from kivy.graphics import (
Callback, PushMatrix, PopMatrix, Rotate, Translate, Scale,
Rectangle, Color, Mesh, UpdateNormalMatrix, Canvas)
from kivy.graphics.transformation import Matrix
from kivy.graphics.opengl import (
glEnable, glDisable, GL_DEPTH_TEST)
from kivy.properties import (
StringProperty, ListProperty, ObjectProperty, NumericProperty,
BooleanProperty, DictProperty)
from os.path import join, dirname
import numpy as np
class ObjectRenderer(Widget):
obj_translation = ListProperty([0, 0, 0])
obj_rotation = ListProperty([0, 0, 0])
obj_scale = NumericProperty(1)
obj_texture = StringProperty('')
texture = ObjectProperty(None, allownone=True)
cam_translation = ListProperty([0, 0, 0])
cam_rotation = ListProperty([0, 0, 0])
display_all = BooleanProperty(True)
light_sources = DictProperty()
ambiant = NumericProperty(.5)
diffuse = NumericProperty(.5)
specular = NumericProperty(.5)
mode = StringProperty('triangles')
def __init__(self, **kwargs):
self.canvas = Canvas()
with self.canvas:
self.fbo = Fbo(size=self.size,
with_depthbuffer=True,
compute_normal_mat=True,
clear_color=(0., 0., 0., 0.))
# This sets the current color of the rectangle passed to the view port.
# The Fbo contents are rendered by using the below rectangle. If no Color
# is passed in here, the rectangle will use the current colour, which happens to be
# the parent widgets colour. This will then work as a filter when rendering any further instructions
# and we end up with mixed colours, instead of the clean colours we are trying to draw.
Color( 1, 1, 1, 1 )
self.viewport = Rectangle(size=self.size, pos=self.pos)
self.fbo.shader.source = resource_find(
join(dirname(__file__), 'shaders.glsl'))
self.vertex_format = [ ( b'v_pos', 3, 'float' ),
( b'v_color', 4, 'float' ),
( b'v_tc0', 2, 'float' ) ]
super(ObjectRenderer, self).__init__(**kwargs)
def on_obj_rotation(self, *args):
self.obj_rot_x.angle = self.obj_rotation[0]
self.obj_rot_y.angle = self.obj_rotation[1]
self.obj_rot_z.angle = self.obj_rotation[2]
def on_cam_rotation(self, *args):
self.cam_rot_x.angle = self.cam_rotation[0]
self.cam_rot_y.angle = self.cam_rotation[1]
self.cam_rot_z.angle = self.cam_rotation[2]
def on_obj_translation(self, *args):
self.obj_translate.xyz = self.cam_translation
def on_cam_translation(self, *args):
self.cam_translate.xyz = self.cam_translation
def on_obj_scale(self, *args):
self.scale.xyz = [self.obj_scale, ] * 3
def on_display_all(self, *args):
self.setup_canvas()
def on_light_sources(self, *args):
self.fbo['light_sources'] = [
ls[:] for ls in self.light_sources.values()]
self.fbo['nb_lights'] = len(self.light_sources)
def on_ambiant(self, *args):
self.fbo['ambiant'] = self.ambiant
def on_diffuse(self, *args):
self.fbo['diffuse'] = self.diffuse
def on_specular(self, *args):
self.fbo['specular'] = self.specular
def on_mode(self, *args):
self.setup_canvas()
def setup_canvas(self, *args):
with self.fbo:
self.cb = Callback(self.setup_gl_context)
PushMatrix()
self.setup_scene()
PopMatrix()
self.cb = Callback(self.reset_gl_context)
def on_size(self, instance, value):
self.fbo.size = value
self.viewport.texture = self.fbo.texture
self.viewport.size = value
self.update_glsl()
def on_pos(self, instance, value):
self.viewport.pos = value
def on_texture(self, instance, value):
self.viewport.texture = value
def setup_gl_context(self, *args):
glEnable(GL_DEPTH_TEST)
self.fbo.clear_buffer()
def reset_gl_context(self, *args):
glDisable(GL_DEPTH_TEST)
def update_glsl(self, *args):
asp = self.width / float(self.height)
proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1)
self.fbo['projection_mat'] = proj
def setup_scene(self):
Color(1, 1, 1, 0)
PushMatrix()
self.cam_translate = Translate(self.cam_translation)
# Rotate(0, 1, 0, 0)
self.cam_rot_x = Rotate(self.cam_rotation[0], 1, 0, 0)
self.cam_rot_y = Rotate(self.cam_rotation[1], 0, 1, 0)
self.cam_rot_z = Rotate(self.cam_rotation[2], 0, 0, 1)
self.scale = Scale(self.obj_scale)
UpdateNormalMatrix()
self.draw_object()
PopMatrix()
def draw_object(self):
self.obj_rot_x = Rotate(self.obj_rotation[0], 1, 0, 0)
self.obj_rot_y = Rotate(self.obj_rotation[1], 0, 1, 0)
self.obj_rot_z = Rotate(self.obj_rotation[2], 0, 0, 1)
self.obj_translate = Translate(xyz=self.obj_translation)
texture = None
vertices = np.zeros( ( 3, 9 ), 'f' )
vertices[ 0 ] = [ -0.5, -0.5, -1, 0, 0, 1, 1, 0, 0 ]
vertices[ 1 ] = [ -0.5, 0.5, -1, 0, 0, 1, 1, 0, 0 ]
vertices[ 2 ] = [ 0.5, 0.5, -1, 0, 0, 1, 1, 0, 0 ]
#vertices = [ -0.5, -0.5, -1, 0, 0, 1, 1, 0, 0, -0.5, 0.5, -1, 0, 0, 1, 1, 0, 0, 0.5, 0.5, -1, 0, 0, 1, 1, 0, 0 ]
indices = [ 0, 1, 2 ]
#print( "vertices: {}".format( vertices.ravel( ) ) )
Mesh(
vertices=vertices.ravel( ),
indices=indices,
fmt=self.vertex_format,
mode=self.mode )
/* simple.glsl
simple diffuse lighting based on laberts cosine law; see e.g.:
http://en.wikipedia.org/wiki/Lambertian_reflectance
http://en.wikipedia.org/wiki/Lambert%27s_cosine_law
*/
---VERTEX SHADER-------------------------------------------------------
#ifdef GL_ES
precision highp float;
#endif
attribute vec3 v_pos;
attribute vec3 v_normal;
attribute vec4 v_color;
attribute vec2 v_tc0;
uniform mat4 modelview_mat;
uniform mat4 projection_mat;
uniform float Tr;
varying vec4 normal_vec;
varying vec4 vertex_pos;
varying vec4 color_vec;
varying vec2 tc0_vec;
void main (void) {
//compute vertex position in eye_sapce and normalize normal vector
vec4 pos = modelview_mat * vec4(v_pos,1.0);
vertex_pos = pos;
normal_vec = vec4(v_normal,0.0);
color_vec = v_color;
tc0_vec = v_tc0;
gl_Position = projection_mat * pos;
}
---FRAGMENT SHADER-----------------------------------------------------
#ifdef GL_ES
precision highp float;
#endif
varying vec4 normal_vec;
varying vec4 vertex_pos;
varying vec4 color_vec;
varying vec2 tc0_vec;
uniform sampler2D texture0;
uniform mat4 normal_mat;
uniform vec3 Kd;
uniform vec3 Ka;
uniform vec3 Ks;
uniform float Tr;
uniform float Ns;
uniform float intensity;
void main (void){
//correct normal, and compute light vector (assume light at the eye)
vec4 v_normal = normalize( normal_mat * normal_vec );
vec4 v_light = normalize( vec4(0,0,0,1) - vertex_pos );
//reflectance based on lamberts law of cosine
vec3 Ia = intensity*Kd;
vec3 Id = intensity*Ka * max(dot(v_light, v_normal), 0.0);
vec3 Is = intensity*Ks * pow(max(dot(v_light, v_normal), 0.0), Ns);
//gl_FragColor = vec4(Ia + Id + Is, Tr);
vec4 t = texture2D( texture0, tc0_vec );
gl_FragColor = t * color_vec;
//gl_FragColor = vec4( 1.0, 1.0, 1.0, 1.0 );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment