add simple 3D rendering example

This commit is contained in:
Thomas Hansen 2012-12-18 17:11:29 -06:00
parent 83ea2e07de
commit 73e45e5b5b
4 changed files with 8180 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}