mirror of https://github.com/kivy/kivy.git
add simple 3D rendering example
This commit is contained in:
parent
83ea2e07de
commit
73e45e5b5b
|
@ -0,0 +1,61 @@
|
|||
from kivy.app import App
|
||||
from kivy.clock import Clock
|
||||
from kivy.core.window import Window
|
||||
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 objloader import ObjFile
|
||||
|
||||
|
||||
class Renderer(Widget):
|
||||
def __init__(self, **kwargs):
|
||||
self.canvas = RenderContext(compute_normal_mat=True)
|
||||
self.canvas.shader.source = resource_find('simple.glsl')
|
||||
self.scene = ObjFile(resource_find("monkey.obj"))
|
||||
super(Renderer, self).__init__(**kwargs)
|
||||
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):
|
||||
asp = self.width / float(self.height)
|
||||
proj = Matrix().view_clip(-asp, asp, -1, 1, 1, 100, 1)
|
||||
self.canvas['projection_mat'] = proj
|
||||
self.canvas['diffuse_light'] = (1.0, 1.0, 0.8)
|
||||
self.canvas['ambient_light'] = (0.1, 0.1, 0.1)
|
||||
self.rot.angle += 1
|
||||
|
||||
def setup_scene(self):
|
||||
Color(1, 1, 1, 1)
|
||||
PushMatrix()
|
||||
Translate(0, 0, -3)
|
||||
self.rot = Rotate(1, 0, 1, 0)
|
||||
m = self.scene.objects.values()[0]
|
||||
UpdateNormalMatrix()
|
||||
self.mesh = Mesh(
|
||||
vertices=m.vertices,
|
||||
indices=m.indices,
|
||||
fmt=m.vertex_format,
|
||||
mode='triangles',
|
||||
)
|
||||
PopMatrix()
|
||||
|
||||
|
||||
class RendererApp(App):
|
||||
def build(self):
|
||||
return Renderer()
|
||||
|
||||
if __name__ == "__main__":
|
||||
RendererApp().run()
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,108 @@
|
|||
|
||||
|
||||
|
||||
class MeshData(object):
|
||||
def __init__(self, **kwargs):
|
||||
self.name = kwargs.get("name")
|
||||
self.vertex_format = [
|
||||
('v_pos', 3, 'float'),
|
||||
('v_normal', 3, 'float'),
|
||||
('v_tc0', 2, 'float')]
|
||||
self.vertices = []
|
||||
self.indices = []
|
||||
|
||||
|
||||
class ObjFile:
|
||||
|
||||
def finish_object(self):
|
||||
if self._current_object == None:
|
||||
return
|
||||
|
||||
mesh = MeshData()
|
||||
idx = 0
|
||||
for f in self.faces:
|
||||
verts = f[0]
|
||||
norms = f[1]
|
||||
for i in range(3):
|
||||
v = self.vertices[verts[i]-1]
|
||||
n = self.normals[norms[i]-1]
|
||||
data = [v[0], v[1], v[2], n[0], n[1], n[2], 0.0,0.0]
|
||||
mesh.vertices.extend(data)
|
||||
tri = [idx, idx+1, idx+2]
|
||||
mesh.indices.extend(tri)
|
||||
idx += 3
|
||||
|
||||
self.objects[self._current_object] = mesh
|
||||
self.faces = []
|
||||
|
||||
def __init__(self, filename, swapyz=False):
|
||||
"""Loads a Wavefront OBJ file. """
|
||||
self.objects = {}
|
||||
self.vertices = []
|
||||
self.normals = []
|
||||
self.texcoords = []
|
||||
self.faces = []
|
||||
|
||||
self._current_object = None
|
||||
|
||||
material = None
|
||||
for line in open(filename, "r"):
|
||||
if line.startswith('#'): continue
|
||||
if line.startswith('s'): continue
|
||||
values = line.split()
|
||||
if not values: continue
|
||||
if values[0] == 'o':
|
||||
self.finish_object()
|
||||
self._current_object = values[1]
|
||||
#elif values[0] == 'mtllib':
|
||||
# self.mtl = MTL(values[1])
|
||||
#elif values[0] in ('usemtl', 'usemat'):
|
||||
# material = values[1]
|
||||
if values[0] == 'v':
|
||||
v = map(float, values[1:4])
|
||||
if swapyz:
|
||||
v = v[0], v[2], v[1]
|
||||
self.vertices.append(v)
|
||||
elif values[0] == 'vn':
|
||||
v = map(float, values[1:4])
|
||||
if swapyz:
|
||||
v = v[0], v[2], v[1]
|
||||
self.normals.append(v)
|
||||
elif values[0] == 'vt':
|
||||
self.texcoords.append(map(float, values[1:3]))
|
||||
elif values[0] == 'f':
|
||||
face = []
|
||||
texcoords = []
|
||||
norms = []
|
||||
for v in values[1:]:
|
||||
w = v.split('/')
|
||||
face.append(int(w[0]))
|
||||
if len(w) >= 2 and len(w[1]) > 0:
|
||||
texcoords.append(int(w[1]))
|
||||
else:
|
||||
texcoords.append(0)
|
||||
if len(w) >= 3 and len(w[2]) > 0:
|
||||
norms.append(int(w[2]))
|
||||
else:
|
||||
norms.append(0)
|
||||
self.faces.append((face, norms, texcoords, material))
|
||||
self.finish_object()
|
||||
|
||||
|
||||
def MTL(filename):
|
||||
contents = {}
|
||||
mtl = None
|
||||
return
|
||||
for line in open(filename, "r"):
|
||||
if line.startswith('#'): continue
|
||||
values = line.split()
|
||||
if not values: continue
|
||||
if values[0] == 'newmtl':
|
||||
mtl = contents[values[1]] = {}
|
||||
elif mtl is None:
|
||||
raise ValueError, "mtl file doesn't start with newmtl stmt"
|
||||
mtl[values[0]] = values[1:]
|
||||
return contents
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/* 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-------------------------------------------------------
|
||||
|
||||
attribute vec3 v_pos;
|
||||
attribute vec3 v_normal;
|
||||
|
||||
uniform mat4 modelview_mat;
|
||||
uniform mat4 projection_mat;
|
||||
|
||||
varying vec4 normal_vec;
|
||||
varying vec4 vertex_pos;
|
||||
|
||||
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);
|
||||
gl_Position = projection_mat * pos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
---FRAGMENT SHADER-----------------------------------------------------
|
||||
|
||||
uniform mat4 normal_mat;
|
||||
|
||||
varying vec4 normal_vec;
|
||||
varying vec4 vertex_pos;
|
||||
|
||||
void main (void){
|
||||
//correct normal, and compute light vector (assume light at the eye)
|
||||
vec4 v_normal = normalize( vec4(mat3(normal_mat) * vec3(normal_vec), 0.0) ) ;
|
||||
vec4 v_light = normalize( vec4(0,0,0,1) - vertex_pos );
|
||||
|
||||
//reflectance based on lamberts law of cosine
|
||||
float theta = clamp(dot(v_normal, v_light), 0.0, 1.0);
|
||||
gl_FragColor = vec4(theta, theta, theta, 1.0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue