Showing a 3-D model on our Raspberry Pi
Deprecated: ltrim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 3030
Deprecated: parse_str(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/class.jetpack.php on line 4255
Deprecated: Creation of dynamic property Jetpack_Carousel::$localize_strings is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/modules/carousel/jetpack-carousel.php on line 339
Eric got his OBJ loader working, we think, so it came time for me to integrate his code with my demo renderers. It kind of worked. I added a normal attribute to the vertex shader and sent it along to the fragment shader, where I calculated some simple directional lighting in eye space. I drew the indexed geometry. And the result is a bit off:
We’re looking at Al’s backside, but we’re seeing through some of him. It looks like my depth test isn’t working. That’s work for another day.
Our test renderer looks like this:
from pyopengles import *
from render import Renderer
from eric import TriMesh
import render
import time
import sys
WIDTH = 1680
HEIGHT = 1050
class TriMoveRenderer(Renderer):
def __init__(self):
self.context = EGL()
self.startTime = time.time()
self.vertexShader = """
attribute vec3 position;
attribute vec3 normal;
varying vec3 fnormal;
void main() {
gl_Position = vec4(position, 1.0);
fnormal = normal;
}
"""
self.fragmentShader = """
precision mediump float;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
const vec3 albedo = vec3(1.0);
const float ambientStrength = 0.1;
const float diffuseStrength = 1.0 - ambientStrength;
const vec3 lightDirection = normalize(vec3(5.0, 5.0, -5.0));
const vec3 eyeDirection = vec3(0.0, 0.0, -1.0);
const float shininess = 50.0;
varying vec3 fnormal;
void main() {
vec3 normal = normalize(fnormal);
vec3 ambient = ambientStrength * albedo;
float nDotL = dot(normal, lightDirection);
vec3 diffuse = diffuseStrength * nDotL * albedo;
vec3 halfVector = normalize(eyeDirection + lightDirection);
float nDotH = dot(normal, halfVector);
vec3 specular = pow(nDotH, cos(shininess)) * vec3(1.0);
vec3 color = ambient + diffuse + specular;
gl_FragColor = vec4(color, 1.0);
}
"""
self.binding = ((0, 'position'),
(1, 'normal'),)
self.program = self.context.get_program(self.vertexShader, self.fragmentShader, self.binding)
opengles.glUseProgram(self.program)
self.mouseUID = opengles.glGetUniformLocation(self.program, "mouse")
self.resolutionUID = opengles.glGetUniformLocation(self.program, "resolution")
self.timeUID = opengles.glGetUniformLocation(self.program, "time")
opengles.glUseProgram(0)
opengles.glUseProgram(self.program)
opengles.glUniform2f(self.resolutionUID, eglfloat(WIDTH), eglfloat(HEIGHT))
opengles.glUniform2f(self.mouseUID, eglfloat(0.5), eglfloat(0.5))
opengles.glUseProgram(0)
opengles.glClearColor(eglfloat(0.45), eglfloat(0.35), eglfloat(0.15), eglfloat(1.0))
mesh = TriMesh('../al.obj')
self.vertices = eglfloats(mesh.verts)
self.normals = eglfloats(mesh.vNorms)
self.faces = eglshorts(mesh.faces)
self.checkError('after init')
opengles.glEnable(GL_DEPTH_TEST)
def onMouseEvent(self, event):
opengles.glUseProgram(self.program)
opengles.glUniform2f(self.mouseUID, eglfloat(event.x / float(WIDTH)), eglfloat(event.y / float(HEIGHT)))
opengles.glUseProgram(0)
def onDraw(self):
opengles.glViewport(0, 0, self.context.width, self.context.height);
opengles.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
opengles.glPointSize(eglfloat(5.0))
self.checkError('before use program')
opengles.glUseProgram(self.program)
opengles.glUniform2f(self.resolutionUID, eglfloat(WIDTH), eglfloat(HEIGHT))
opengles.glUniform1f(self.timeUID, eglfloat(time.time() - self.startTime))
opengles.glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, self.vertices)
opengles.glEnableVertexAttribArray(0)
opengles.glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, self.normals)
opengles.glEnableVertexAttribArray(1)
opengles.glDrawElements(GL_TRIANGLES, len(self.faces), GL_UNSIGNED_SHORT, self.faces)
opengles.glUseProgram(0)
self.checkError('after draw')
openegl.eglSwapBuffers(self.context.display, self.context.surface)
def checkError(self, msg):
e = opengles.glGetError()
if e:
print msg, 'Error: ', hex(e)
sys.exit(1)
if __name__ == "__main__":
with TriMoveRenderer() as renderer:
render.go(WIDTH, HEIGHT, 0.02, renderer)
I added an eglshorts to pyopengles, as glDrawElements wouldn’t accept ints. I also learned how to make a package in Python: make a directory named with your package name and add an __init__.py file inside of it. I made a package named eric and dropped TriMesh.py inside.
