diff --git a/port/PyAssimp/README.md b/port/PyAssimp/README.md index 5bec88711..db014a5b3 100644 --- a/port/PyAssimp/README.md +++ b/port/PyAssimp/README.md @@ -1,8 +1,8 @@ PyAssimp Readme =============== --- a simple Python wrapper for Assimp using ctypes to access -the library. Requires Python >= 2.6. +A simple Python wrapper for Assimp using `ctypes` to access the library. +Requires Python >= 2.6. Python 3 support is mostly here, but not well tested. @@ -12,10 +12,10 @@ particular, only loading of models is currently supported (no export). USAGE ----- -To get started with pyAssimp, examine the sample.py script in scripts/, which -illustrates the basic usage. All Assimp data structures are wrapped using +To get started with pyAssimp, examine the `sample.py` script in `scripts/`, +which illustrates the basic usage. All Assimp data structures are wrapped using ctypes. All the data+length fields in Assimp's data structures (such as -'aiMesh::mNumVertices','aiMesh::mVertices') are replaced by simple python +`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python lists, so you can call len() on them to get their respective size and access members using []. @@ -57,18 +57,18 @@ release(scene) INSTALL ------- -Install pyassimp by running: +Install `pyassimp` by running: > python setup.py install -PyAssimp requires a assimp dynamic library (DLL on windows, -so on linux :-) in order to work. The default search directories +PyAssimp requires a assimp dynamic library (`DLL` on windows, +`.so` on linux :-) in order to work. The default search directories are: - the current directory -- on linux additionally: /usr/lib and /usr/local/lib +- on linux additionally: `/usr/lib` and `/usr/local/lib` To build that library, refer to the Assimp master INSTALL -instructions. To look in more places, edit ./pyassimp/helper.py. -There's an 'additional_dirs' list waiting for your entries. +instructions. To look in more places, edit `./pyassimp/helper.py`. +There's an `additional_dirs` list waiting for your entries. diff --git a/port/PyAssimp/pyassimp/core.py b/port/PyAssimp/pyassimp/core.py index 877272b1c..6df31be8e 100644 --- a/port/PyAssimp/pyassimp/core.py +++ b/port/PyAssimp/pyassimp/core.py @@ -346,60 +346,28 @@ def _get_properties(properties, length): for p in [properties[i] for i in range(length)]: #the name p = p.contents - key = str(p.mKey.data) + key = str(p.mKey.data).split('.')[1] #the data from ctypes import POINTER, cast, c_int, c_float, sizeof if p.mType == 1: arr = cast(p.mData, POINTER(c_float * int(p.mDataLength/sizeof(c_float)) )).contents - value = numpy.array([x for x in arr]) + value = [x for x in arr] elif p.mType == 3: #string can't be an array value = cast(p.mData, POINTER(structs.String)).contents.data elif p.mType == 4: arr = cast(p.mData, POINTER(c_int * int(p.mDataLength/sizeof(c_int)) )).contents - value = numpy.array([x for x in arr]) + value = [x for x in arr] else: value = p.mData[:p.mDataLength] + if len(value) == 1: + [value] = value + result[key] = value return result -def aiGetMaterialFloatArray(material, key): - AI_SUCCESS = 0 - from ctypes import byref, pointer, cast, c_float, POINTER, sizeof, c_uint - out = structs.Color4D() - max = c_uint(sizeof(structs.Color4D)) - r=_assimp_lib.dll.aiGetMaterialFloatArray(pointer(material), - key[0], - key[1], - key[2], - byref(out), - byref(max)) - - if (r != AI_SUCCESS): - raise AssimpError("aiGetMaterialFloatArray failed!") - - out._init() - return [out[i] for i in range(max.value)] - -def aiGetMaterialString(material, key): - AI_SUCCESS = 0 - from ctypes import byref, pointer, cast, c_float, POINTER, sizeof, c_uint - out = structs.String() - r=_assimp_lib.dll.aiGetMaterialString(pointer(material), - key[0], - key[1], - key[2], - byref(out)) - - if (r != AI_SUCCESS): - raise AssimpError("aiGetMaterialString failed!") - - return str(out.data) - - - def decompose_matrix(matrix): if not isinstance(matrix, structs.Matrix4x4): raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!") diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index a01da375c..6a6339d33 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -9,6 +9,7 @@ import ctypes from ctypes import POINTER import operator import numpy +from numpy import linalg import logging;logger = logging.getLogger("pyassimp") @@ -47,12 +48,14 @@ def transform(vector3, matrix4x4): def get_bounding_box(scene): bb_min = [1e10, 1e10, 1e10] # x,y,z bb_max = [-1e10, -1e10, -1e10] # x,y,z - return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max) + return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, linalg.inv(scene.rootnode.transformation)) -def get_bounding_box_for_node(node, bb_min, bb_max): +def get_bounding_box_for_node(node, bb_min, bb_max, transformation): + + transformation = numpy.dot(transformation, node.transformation) for mesh in node.meshes: for v in mesh.vertices: - v = transform(v, node.transformation) + v = transform(v, transformation) bb_min[0] = min(bb_min[0], v[0]) bb_min[1] = min(bb_min[1], v[1]) bb_min[2] = min(bb_min[2], v[2]) @@ -62,7 +65,7 @@ def get_bounding_box_for_node(node, bb_min, bb_max): for child in node.children: - bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max) + bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation) return bb_min, bb_max diff --git a/port/PyAssimp/scripts/advanced_3d_viewer.py b/port/PyAssimp/scripts/advanced_3d_viewer.py new file mode 100755 index 000000000..33fa84524 --- /dev/null +++ b/port/PyAssimp/scripts/advanced_3d_viewer.py @@ -0,0 +1,410 @@ +#!/usr/bin/env python +#-*- coding: UTF-8 -*- + +""" This program loads a model with PyASSIMP, and display it. + +It make a large use of shaders to illustrate a 'modern' OpenGL pipeline. + +Based on: +- pygame + mouselook code from http://3dengine.org/Spectator_%28PyOpenGL%29 + - http://www.lighthouse3d.com/tutorials + - http://www.songho.ca/opengl/gl_transform.html + - http://code.activestate.com/recipes/325391/ + - ASSIMP's C++ SimpleOpenGL viewer +""" +import sys + +import logging +logger = logging.getLogger("underworlds.3d_viewer") +gllogger = logging.getLogger("OpenGL") +gllogger.setLevel(logging.WARNING) +logging.basicConfig(level=logging.INFO) + +import OpenGL +#OpenGL.ERROR_CHECKING=False +#OpenGL.ERROR_LOGGING = False +#OpenGL.ERROR_ON_COPY = True +#OpenGL.FULL_LOGGING = True +from OpenGL.GL import * +from OpenGL.error import GLError +from OpenGL.GLU import * +from OpenGL.GLUT import * +from OpenGL.arrays import vbo +from OpenGL.GL import shaders + +import pygame + +import math, random +import numpy +from numpy import linalg + +from pyassimp import core as pyassimp +from pyassimp.postprocess import * +from pyassimp.helper import * + +class DefaultCamera: + def __init__(self, w, h, fov): + self.clipplanenear = 0.001 + self.clipplanefar = 100000.0 + self.aspect = w/h + self.horizontalfov = fov * math.pi/180 + self.transformation = [[ 0.68, -0.32, 0.65, 7.48], + [ 0.73, 0.31, -0.61, -6.51], + [-0.01, 0.89, 0.44, 5.34], + [ 0., 0., 0., 1. ]] + self.lookat = [0.0,0.0,-1.0] + + def __str__(self): + return "Default camera" + +class PyAssimp3DViewer: + + base_name = "PyASSIMP 3D viewer" + + def __init__(self, model, w=1024, h=768, fov=75): + + pygame.init() + pygame.display.set_caption(self.base_name) + pygame.display.set_mode((w,h), pygame.OPENGL | pygame.DOUBLEBUF) + + self.prepare_shaders() + + self.cameras = [DefaultCamera(w,h,fov)] + self.current_cam_index = 0 + + self.load_model(model) + + # for FPS computation + self.frames = 0 + self.last_fps_time = glutGet(GLUT_ELAPSED_TIME) + + + self.cycle_cameras() + + def prepare_shaders(self): + + phong_weightCalc = """ + float phong_weightCalc( + in vec3 light_pos, // light position + in vec3 frag_normal // geometry normal + ) { + // returns vec2( ambientMult, diffuseMult ) + float n_dot_pos = max( 0.0, dot( + frag_normal, light_pos + )); + return n_dot_pos; + } + """ + + vertex = shaders.compileShader( phong_weightCalc + + """ + uniform vec4 Global_ambient; + uniform vec4 Light_ambient; + uniform vec4 Light_diffuse; + uniform vec3 Light_location; + uniform vec4 Material_ambient; + uniform vec4 Material_diffuse; + attribute vec3 Vertex_position; + attribute vec3 Vertex_normal; + varying vec4 baseColor; + void main() { + gl_Position = gl_ModelViewProjectionMatrix * vec4( + Vertex_position, 1.0 + ); + vec3 EC_Light_location = gl_NormalMatrix * Light_location; + float diffuse_weight = phong_weightCalc( + normalize(EC_Light_location), + normalize(gl_NormalMatrix * Vertex_normal) + ); + baseColor = clamp( + ( + // global component + (Global_ambient * Material_ambient) + // material's interaction with light's contribution + // to the ambient lighting... + + (Light_ambient * Material_ambient) + // material's interaction with the direct light from + // the light. + + (Light_diffuse * Material_diffuse * diffuse_weight) + ), 0.0, 1.0); + }""", GL_VERTEX_SHADER) + + fragment = shaders.compileShader(""" + varying vec4 baseColor; + void main() { + gl_FragColor = baseColor; + } + """, GL_FRAGMENT_SHADER) + + self.shader = shaders.compileProgram(vertex,fragment) + self.set_shader_accessors( ( + 'Global_ambient', + 'Light_ambient','Light_diffuse','Light_location', + 'Material_ambient','Material_diffuse', + ), ( + 'Vertex_position','Vertex_normal', + ), self.shader) + + def set_shader_accessors(self, uniforms, attributes, shader): + # add accessors to the shaders uniforms and attributes + for uniform in uniforms: + location = glGetUniformLocation( shader, uniform ) + if location in (None,-1): + logger.warning('No uniform: %s'%( uniform )) + setattr( shader, uniform, location ) + + for attribute in attributes: + location = glGetAttribLocation( shader, attribute ) + if location in (None,-1): + logger.warning('No attribute: %s'%( attribute )) + setattr( shader, attribute, location ) + + + def prepare_gl_buffers(self, mesh): + + mesh.gl = {} + + # Fill the buffer for vertex and normals positions + v = numpy.array(mesh.vertices, 'f') + n = numpy.array(mesh.normals, 'f') + + mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v,n))) + + # Fill the buffer for vertex positions + mesh.gl["faces"] = glGenBuffers(1) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + mesh.faces, + GL_STATIC_DRAW) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0) + + + def load_model(self, path, postprocess = aiProcessPreset_TargetRealtime_MaxQuality): + logger.info("Loading model:" + path + "...") + + if postprocess: + self.scene = pyassimp.load(path, postprocess) + else: + self.scene = pyassimp.load(path) + logger.info("Done.") + + scene = self.scene + #log some statistics + logger.info(" meshes: %d" % len(scene.meshes)) + logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) + logger.info(" materials: %d" % len(scene.materials)) + self.bb_min, self.bb_max = get_bounding_box(self.scene) + logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) + + self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] + + for index, mesh in enumerate(scene.meshes): + self.prepare_gl_buffers(mesh) + + # Finally release the model + pyassimp.release(scene) + + logger.info("Ready for 3D rendering!") + + def cycle_cameras(self): + if not self.cameras: + logger.info("No camera in the scene") + return None + self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) + self.current_cam = self.cameras[self.current_cam_index] + self.set_camera(self.current_cam) + logger.info("Switched to camera <%s>" % self.current_cam) + + def set_camera_projection(self, camera = None): + + if not camera: + camera = self.cameras[self.current_cam_index] + + znear = camera.clipplanenear + zfar = camera.clipplanefar + aspect = camera.aspect + fov = camera.horizontalfov + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + + # Compute gl frustrum + tangent = math.tan(fov/2.) + h = znear * tangent + w = h * aspect + + # params: left, right, bottom, top, near, far + glFrustum(-w, w, -h, h, znear, zfar) + # equivalent to: + #gluPerspective(fov * 180/math.pi, aspect, znear, zfar) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + + def set_camera(self, camera): + + self.set_camera_projection(camera) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + cam = transform([0.0, 0.0, 0.0], camera.transformation) + at = transform(camera.lookat, camera.transformation) + gluLookAt(cam[0], cam[2], -cam[1], + at[0], at[2], -at[1], + 0, 1, 0) + + def render(self, wireframe = False, twosided = False): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) + glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) + + shader = self.shader + + glUseProgram(shader) + glUniform4f( shader.Global_ambient, .4,.2,.2,.1 ) + glUniform4f( shader.Light_ambient, .4,.4,.4, 1.0 ) + glUniform4f( shader.Light_diffuse, 1,1,1,1 ) + glUniform3f( shader.Light_location, 2,2,10 ) + + self.recursive_render(self.scene.rootnode, shader) + + + glUseProgram( 0 ) + + def recursive_render(self, node, shader): + """ Main recursive rendering method. + """ + + # save model matrix and apply node transformation + glPushMatrix() + m = node.transformation.transpose() # OpenGL row major + glMultMatrixf(m) + + for mesh in node.meshes: + + stride = 24 # 6 * 4 bytes + + glUniform4f( shader.Material_diffuse, *mesh.material.properties["diffuse"] ) + glUniform4f( shader.Material_ambient, *mesh.material.properties["ambient"] ) + + vbo = mesh.gl["vbo"] + vbo.bind() + + glEnableVertexAttribArray( shader.Vertex_position ) + glEnableVertexAttribArray( shader.Vertex_normal ) + + glVertexAttribPointer( + shader.Vertex_position, + 3, GL_FLOAT,False, stride, vbo + ) + + glVertexAttribPointer( + shader.Vertex_normal, + 3, GL_FLOAT,False, stride, vbo+12 + ) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glDrawElements(GL_TRIANGLES, len(mesh.faces) * 3, GL_UNSIGNED_INT, None) + + + vbo.unbind() + glDisableVertexAttribArray( shader.Vertex_position ) + + glDisableVertexAttribArray( shader.Vertex_normal ) + + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + for child in node.children: + self.recursive_render(child, shader) + + glPopMatrix() + + + def loop(self): + + pygame.display.flip() + pygame.event.pump() + self.keys = [k for k, pressed in enumerate(pygame.key.get_pressed()) if pressed] + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + # Compute FPS + gl_time = glutGet(GLUT_ELAPSED_TIME) + self.frames += 1 + if gl_time - self.last_fps_time >= 1000: + current_fps = self.frames * 1000 / (gl_time - self.last_fps_time) + pygame.display.set_caption(self.base_name + " - %.0f fps" % current_fps) + self.frames = 0 + self.last_fps_time = gl_time + + + return True + + def controls_3d(self, + mouse_button=1, \ + up_key=pygame.K_UP, \ + down_key=pygame.K_DOWN, \ + left_key=pygame.K_LEFT, \ + right_key=pygame.K_RIGHT): + """ The actual camera setting cycle """ + mouse_dx,mouse_dy = pygame.mouse.get_rel() + if pygame.mouse.get_pressed()[mouse_button]: + look_speed = .2 + buffer = glGetDoublev(GL_MODELVIEW_MATRIX) + c = (-1 * numpy.mat(buffer[:3,:3]) * \ + numpy.mat(buffer[3,:3]).T).reshape(3,1) + # c is camera center in absolute coordinates, + # we need to move it back to (0,0,0) + # before rotating the camera + glTranslate(c[0],c[1],c[2]) + m = buffer.flatten() + glRotate(mouse_dx * look_speed, m[1],m[5],m[9]) + glRotate(mouse_dy * look_speed, m[0],m[4],m[8]) + + # compensate roll + glRotated(-math.atan2(-m[4],m[5]) * \ + 57.295779513082320876798154814105 ,m[2],m[6],m[10]) + glTranslate(-c[0],-c[1],-c[2]) + + # move forward-back or right-left + if up_key in self.keys: + fwd = .1 + elif down_key in self.keys: + fwd = -.1 + else: + fwd = 0 + + if left_key in self.keys: + strafe = .1 + elif right_key in self.keys: + strafe = -.1 + else: + strafe = 0 + + if abs(fwd) or abs(strafe): + m = glGetDoublev(GL_MODELVIEW_MATRIX).flatten() + glTranslate(fwd*m[2],fwd*m[6],fwd*m[10]) + glTranslate(strafe*m[0],strafe*m[4],strafe*m[8]) + +if __name__ == '__main__': + if not len(sys.argv) > 1: + print("Usage: " + __file__ + " ") + sys.exit(2) + + app = PyAssimp3DViewer(model = sys.argv[1], w = 1024, h = 768, fov = 75) + + while app.loop(): + app.render() + app.controls_3d(0) + if pygame.K_f in app.keys: pygame.display.toggle_fullscreen() + if pygame.K_s in app.keys: app.screenshot() + if pygame.K_v in app.keys: app.check_visibility() + if pygame.K_TAB in app.keys: app.cycle_cameras() + if pygame.K_ESCAPE in app.keys: + break diff --git a/port/PyAssimp/scripts/opengl_viewer.py b/port/PyAssimp/scripts/simple_opengl_viewer.py similarity index 76% rename from port/PyAssimp/scripts/opengl_viewer.py rename to port/PyAssimp/scripts/simple_opengl_viewer.py index 2cfc4748c..8373f7f03 100755 --- a/port/PyAssimp/scripts/opengl_viewer.py +++ b/port/PyAssimp/scripts/simple_opengl_viewer.py @@ -1,14 +1,21 @@ #!/usr/bin/env python #-*- coding: UTF-8 -*- -""" This program demonstrate the use of pyassimp to render -objects in OpenGL. +""" This program demonstrates the use of pyassimp to load and +render objects with OpenGL. -It loads a 3D model with ASSIMP and display it. +'c' cycles between cameras (if any available) +'q' to quit + +This example mixes 'old' OpenGL fixed-function pipeline with +Vertex Buffer Objects. Materials are supported but textures are currently ignored. -Half-working keyboard + mouse navigation is supported. +For a more advanced example (with shaders + keyboard/mouse +controls), check scripts/sdl_viewer.py + +Author: Séverin Lemaignan, 2012 This sample is based on several sources, including: - http://www.lighthouse3d.com/tutorials @@ -21,9 +28,8 @@ import os, sys from OpenGL.GLUT import * from OpenGL.GLU import * from OpenGL.GL import * -from OpenGL.arrays import ArrayDatatype -import logging;logger = logging.getLogger("assimp_opengl") +import logging;logger = logging.getLogger("pyassimp_opengl") logging.basicConfig(level=logging.INFO) import math @@ -40,20 +46,14 @@ width = 900 class GLRenderer(): def __init__(self): + self.scene = None - self.drot = 0.0 - self.dp = 0.0 - - self.angle = 0.0 - self.x = 1.0 - self.z = 3.0 - self.lx = 0.0 - self.lz = 0.0 self.using_fixed_cam = False self.current_cam_index = 0 - self.x_origin = -1 # x position of the mouse when pressing left btn + # store the global scene rotation + self.angle = 0. # for FPS calculation self.prev_time = 0 @@ -61,6 +61,10 @@ class GLRenderer(): self.frames = 0 def prepare_gl_buffers(self, mesh): + """ Creates 3 buffer objets for each mesh, + to store the vertices, the normals, and the faces + indices. + """ mesh.gl = {} @@ -90,8 +94,7 @@ class GLRenderer(): glBindBuffer(GL_ARRAY_BUFFER,0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0) - - def load_dae(self, path, postprocess = None): + def load_model(self, path, postprocess = None): logger.info("Loading model:" + path + "...") if postprocess: @@ -129,9 +132,11 @@ class GLRenderer(): if not self.using_fixed_cam: glLoadIdentity() - gluLookAt(self.x ,1., self.z, # pos - self.x + self.lx - 1.0, 1., self.z + self.lz - 3.0, # look at - 0.,1.,0.) # up vector + + gluLookAt(0.,0.,3., + 0.,0.,-5., + 0.,1.,0.) + def set_camera(self, camera): @@ -178,13 +183,13 @@ class GLRenderer(): tmp = max(x_max, y_max) z_max = self.bb_max[2] - self.bb_min[2] tmp = max(z_max, tmp) - + if not restore: tmp = 1. / tmp logger.info("Scaling the scene by %.03f" % tmp) glScalef(tmp, tmp, tmp) - + # center the model direction = -1 if not restore else 1 glTranslatef( direction * self.scene_center[0], @@ -192,25 +197,23 @@ class GLRenderer(): direction * self.scene_center[2] ) return x_max, y_max, z_max - + def apply_material(self, mat): - """ Apply an OpenGL, using one OpenGL list per material to cache + """ Apply an OpenGL, using one OpenGL display list per material to cache the operation. """ if not hasattr(mat, "gl_mat"): # evaluate once the mat properties, and cache the values in a glDisplayList. - - diffuse = mat.properties.get("$clr.diffuse", numpy.array([0.8, 0.8, 0.8, 1.0])) - specular = mat.properties.get("$clr.specular", numpy.array([0., 0., 0., 1.0])) - ambient = mat.properties.get("$clr.ambient", numpy.array([0.2, 0.2, 0.2, 1.0])) - emissive = mat.properties.get("$clr.emissive", numpy.array([0., 0., 0., 1.0])) - shininess = min(mat.properties.get("$mat.shininess", 1.0), 128) - wireframe = mat.properties.get("$mat.wireframe", 0) - twosided = mat.properties.get("$mat.twosided", 1) - - from OpenGL.raw import GL - setattr(mat, "gl_mat", GL.GLuint(0)) - mat.gl_mat = glGenLists(1) + + diffuse = numpy.array(mat.properties.get("diffuse", [0.8, 0.8, 0.8, 1.0])) + specular = numpy.array(mat.properties.get("specular", [0., 0., 0., 1.0])) + ambient = numpy.array(mat.properties.get("ambient", [0.2, 0.2, 0.2, 1.0])) + emissive = numpy.array(mat.properties.get("emissive", [0., 0., 0., 1.0])) + shininess = min(mat.properties.get("shininess", 1.0), 128) + wireframe = mat.properties.get("wireframe", 0) + twosided = mat.properties.get("twosided", 1) + + setattr(mat, "gl_mat", glGenLists(1)) glNewList(mat.gl_mat, GL_COMPILE) glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse) @@ -239,6 +242,8 @@ class GLRenderer(): self.lz = -math.cos(self.angle) self.set_default_camera() + self.angle = (gl_time - self.prev_time) * 0.1 + self.prev_time = gl_time # Compute FPS @@ -290,9 +295,10 @@ class GLRenderer(): """ GLUT callback to redraw OpenGL surface """ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) - + + glRotatef(self.angle,0.,1.,0.) self.recursive_render(self.scene.rootnode) - + glutSwapBuffers() self.do_motion() return @@ -307,42 +313,6 @@ class GLRenderer(): if key == 'q': sys.exit(0) - def onspecialkeypress(self, key, x, y): - - fraction = 0.05 - - if key == GLUT_KEY_UP: - self.dp = 0.5 - if key == GLUT_KEY_DOWN: - self.dp = -0.5 - if key == GLUT_KEY_LEFT: - self.drot = -0.01 - if key == GLUT_KEY_RIGHT: - self.drot = 0.01 - - def onspecialkeyrelease(self, key, x, y): - - if key == GLUT_KEY_UP: - self.dp = 0. - if key == GLUT_KEY_DOWN: - self.dp = 0. - if key == GLUT_KEY_LEFT: - self.drot = 0.0 - if key == GLUT_KEY_RIGHT: - self.drot = 0.0 - - def onclick(self, button, state, x, y): - if button == GLUT_LEFT_BUTTON: - if state == GLUT_UP: - self.drot = 0 - self.x_origin = -1 - else: # GLUT_DOWN - self.x_origin = x - - def onmousemove(self, x, y): - if self.x_origin >= 0: - self.drot = (x - self.x_origin) * 0.001 - def render(self, filename=None, fullscreen = False, autofit = True, postprocess = None): """ @@ -364,7 +334,8 @@ class GLRenderer(): print("Fullscreen mode not available!") sys.exit(1) - self.load_dae(filename, postprocess = postprocess) + self.load_model(filename, postprocess = postprocess) + glClearColor(0.1,0.1,0.1,1.) #glShadeModel(GL_SMOOTH) @@ -374,16 +345,10 @@ class GLRenderer(): glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) - #lightZeroPosition = [10.,4.,10.,1.] - #lightZeroColor = [0.8,1.0,0.8,1.0] #green tinged - #glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition) - #glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor) - #glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1) - #glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05) glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) glEnable(GL_NORMALIZE) glEnable(GL_LIGHT0) - + glutDisplayFunc(self.display) @@ -399,14 +364,8 @@ class GLRenderer(): glPushMatrix() - # Register GLUT callbacks for keyboard and mouse glutKeyboardFunc(self.onkeypress) - glutSpecialFunc(self.onspecialkeypress) glutIgnoreKeyRepeat(1) - glutSpecialUpFunc(self.onspecialkeyrelease) - - glutMouseFunc(self.onclick) - glutMotionFunc(self.onmousemove) glutMainLoop()