Merge git://github.com/bjowi/assimp

pull/16/merge
acgessler 2013-01-20 13:33:03 +01:00
commit 29a7126589
7 changed files with 488 additions and 149 deletions

View File

@ -1,4 +1,4 @@
Open Asset Import Library (_assimp_) Open Asset Import Library (assimp)
======== ========
@ -29,8 +29,9 @@ __Note__: this `README` refers to the file structure used by release packages, w
The library provides importers for a lot of file formats, including: The library provides importers for a lot of file formats, including:
- 3DS - 3DS
- BLEND - BLEND (Blender 3D)
- DAE (Collada) - DAE (Collada)
- FBX
- IFC-STEP - IFC-STEP
- ASE - ASE
- DXF - DXF
@ -121,5 +122,3 @@ For the formal details, see the `LICENSE` file.
------------------------------ ------------------------------
(This repository is a mirror of the SVN repository located [here](https://assimp.svn.sourceforge.net/svnroot/assimp). Thanks to [klickverbot](https://github.com/klickverbot) for setting this up!)

View File

@ -1,10 +1,10 @@
prefix=@CMAKE_INSTALL_PREFIX@ prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@/@BIN_INSTALL_DIR@ exec_prefix=@CMAKE_INSTALL_PREFIX@/@ASSIMP_BIN_INSTALL_DIR@
libdir=@CMAKE_INSTALL_PREFIX@/@LIB_INSTALL_DIR@ libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
includedir=@CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@/assimp includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@/assimp
Name: @CMAKE_PROJECT_NAME@ Name: @CMAKE_PROJECT_NAME@
Description: Import various well-known 3D model formats in an uniform manner. Description: Import various well-known 3D model formats in an uniform manner.
Version: @PROJECT_VERSION@ Version: @PROJECT_VERSION@
Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@ Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@
Cflags: -I${includedir} Cflags: -I${includedir}

View File

@ -1,8 +1,8 @@
PyAssimp Readme PyAssimp Readme
=============== ===============
-- a simple Python wrapper for Assimp using ctypes to access A simple Python wrapper for Assimp using `ctypes` to access the library.
the library. Requires Python >= 2.6. Requires Python >= 2.6.
Python 3 support is mostly here, but not well tested. 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 USAGE
----- -----
To get started with pyAssimp, examine the sample.py script in scripts/, which To get started with pyAssimp, examine the `sample.py` script in `scripts/`,
illustrates the basic usage. All Assimp data structures are wrapped using 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 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 lists, so you can call len() on them to get their respective size and access
members using []. members using [].
@ -57,18 +57,18 @@ release(scene)
INSTALL INSTALL
------- -------
Install pyassimp by running: Install `pyassimp` by running:
> python setup.py install > python setup.py install
PyAssimp requires a assimp dynamic library (DLL on windows, PyAssimp requires a assimp dynamic library (`DLL` on windows,
so on linux :-) in order to work. The default search directories `.so` on linux :-) in order to work. The default search directories
are: are:
- the current directory - 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 To build that library, refer to the Assimp master INSTALL
instructions. To look in more places, edit ./pyassimp/helper.py. instructions. To look in more places, edit `./pyassimp/helper.py`.
There's an 'additional_dirs' list waiting for your entries. There's an `additional_dirs` list waiting for your entries.

View File

@ -346,60 +346,28 @@ def _get_properties(properties, length):
for p in [properties[i] for i in range(length)]: for p in [properties[i] for i in range(length)]:
#the name #the name
p = p.contents p = p.contents
key = str(p.mKey.data) key = str(p.mKey.data).split('.')[1]
#the data #the data
from ctypes import POINTER, cast, c_int, c_float, sizeof from ctypes import POINTER, cast, c_int, c_float, sizeof
if p.mType == 1: if p.mType == 1:
arr = cast(p.mData, POINTER(c_float * int(p.mDataLength/sizeof(c_float)) )).contents 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 elif p.mType == 3: #string can't be an array
value = cast(p.mData, POINTER(structs.String)).contents.data value = cast(p.mData, POINTER(structs.String)).contents.data
elif p.mType == 4: elif p.mType == 4:
arr = cast(p.mData, POINTER(c_int * int(p.mDataLength/sizeof(c_int)) )).contents 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: else:
value = p.mData[:p.mDataLength] value = p.mData[:p.mDataLength]
if len(value) == 1:
[value] = value
result[key] = value result[key] = value
return result 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): def decompose_matrix(matrix):
if not isinstance(matrix, structs.Matrix4x4): if not isinstance(matrix, structs.Matrix4x4):
raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!") raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!")

View File

@ -9,6 +9,7 @@ import ctypes
from ctypes import POINTER from ctypes import POINTER
import operator import operator
import numpy import numpy
from numpy import linalg
import logging;logger = logging.getLogger("pyassimp") import logging;logger = logging.getLogger("pyassimp")
@ -47,12 +48,14 @@ def transform(vector3, matrix4x4):
def get_bounding_box(scene): def get_bounding_box(scene):
bb_min = [1e10, 1e10, 1e10] # x,y,z bb_min = [1e10, 1e10, 1e10] # x,y,z
bb_max = [-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 mesh in node.meshes:
for v in mesh.vertices: 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[0] = min(bb_min[0], v[0])
bb_min[1] = min(bb_min[1], v[1]) bb_min[1] = min(bb_min[1], v[1])
bb_min[2] = min(bb_min[2], v[2]) 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: 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 return bb_min, bb_max

View File

@ -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__ + " <model>")
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

View File

@ -1,14 +1,21 @@
#!/usr/bin/env python #!/usr/bin/env python
#-*- coding: UTF-8 -*- #-*- coding: UTF-8 -*-
""" This program demonstrate the use of pyassimp to render """ This program demonstrates the use of pyassimp to load and
objects in OpenGL. 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. 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: This sample is based on several sources, including:
- http://www.lighthouse3d.com/tutorials - http://www.lighthouse3d.com/tutorials
@ -21,9 +28,8 @@ import os, sys
from OpenGL.GLUT import * from OpenGL.GLUT import *
from OpenGL.GLU import * from OpenGL.GLU import *
from OpenGL.GL 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) logging.basicConfig(level=logging.INFO)
import math import math
@ -40,20 +46,14 @@ width = 900
class GLRenderer(): class GLRenderer():
def __init__(self): def __init__(self):
self.scene = None 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.using_fixed_cam = False
self.current_cam_index = 0 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 # for FPS calculation
self.prev_time = 0 self.prev_time = 0
@ -61,6 +61,10 @@ class GLRenderer():
self.frames = 0 self.frames = 0
def prepare_gl_buffers(self, mesh): 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 = {} mesh.gl = {}
@ -90,8 +94,7 @@ class GLRenderer():
glBindBuffer(GL_ARRAY_BUFFER,0) glBindBuffer(GL_ARRAY_BUFFER,0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0)
def load_model(self, path, postprocess = None):
def load_dae(self, path, postprocess = None):
logger.info("Loading model:" + path + "...") logger.info("Loading model:" + path + "...")
if postprocess: if postprocess:
@ -129,9 +132,11 @@ class GLRenderer():
if not self.using_fixed_cam: if not self.using_fixed_cam:
glLoadIdentity() glLoadIdentity()
gluLookAt(self.x ,1., self.z, # pos
self.x + self.lx - 1.0, 1., self.z + self.lz - 3.0, # look at gluLookAt(0.,0.,3.,
0.,1.,0.) # up vector 0.,0.,-5.,
0.,1.,0.)
def set_camera(self, camera): def set_camera(self, camera):
@ -178,13 +183,13 @@ class GLRenderer():
tmp = max(x_max, y_max) tmp = max(x_max, y_max)
z_max = self.bb_max[2] - self.bb_min[2] z_max = self.bb_max[2] - self.bb_min[2]
tmp = max(z_max, tmp) tmp = max(z_max, tmp)
if not restore: if not restore:
tmp = 1. / tmp tmp = 1. / tmp
logger.info("Scaling the scene by %.03f" % tmp) logger.info("Scaling the scene by %.03f" % tmp)
glScalef(tmp, tmp, tmp) glScalef(tmp, tmp, tmp)
# center the model # center the model
direction = -1 if not restore else 1 direction = -1 if not restore else 1
glTranslatef( direction * self.scene_center[0], glTranslatef( direction * self.scene_center[0],
@ -192,25 +197,23 @@ class GLRenderer():
direction * self.scene_center[2] ) direction * self.scene_center[2] )
return x_max, y_max, z_max return x_max, y_max, z_max
def apply_material(self, mat): 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. the operation.
""" """
if not hasattr(mat, "gl_mat"): # evaluate once the mat properties, and cache the values in a glDisplayList. 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])) diffuse = numpy.array(mat.properties.get("diffuse", [0.8, 0.8, 0.8, 1.0]))
specular = mat.properties.get("$clr.specular", numpy.array([0., 0., 0., 1.0])) specular = numpy.array(mat.properties.get("specular", [0., 0., 0., 1.0]))
ambient = mat.properties.get("$clr.ambient", numpy.array([0.2, 0.2, 0.2, 1.0])) ambient = numpy.array(mat.properties.get("ambient", [0.2, 0.2, 0.2, 1.0]))
emissive = mat.properties.get("$clr.emissive", numpy.array([0., 0., 0., 1.0])) emissive = numpy.array(mat.properties.get("emissive", [0., 0., 0., 1.0]))
shininess = min(mat.properties.get("$mat.shininess", 1.0), 128) shininess = min(mat.properties.get("shininess", 1.0), 128)
wireframe = mat.properties.get("$mat.wireframe", 0) wireframe = mat.properties.get("wireframe", 0)
twosided = mat.properties.get("$mat.twosided", 1) twosided = mat.properties.get("twosided", 1)
from OpenGL.raw import GL setattr(mat, "gl_mat", glGenLists(1))
setattr(mat, "gl_mat", GL.GLuint(0))
mat.gl_mat = glGenLists(1)
glNewList(mat.gl_mat, GL_COMPILE) glNewList(mat.gl_mat, GL_COMPILE)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse) glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse)
@ -239,6 +242,8 @@ class GLRenderer():
self.lz = -math.cos(self.angle) self.lz = -math.cos(self.angle)
self.set_default_camera() self.set_default_camera()
self.angle = (gl_time - self.prev_time) * 0.1
self.prev_time = gl_time self.prev_time = gl_time
# Compute FPS # Compute FPS
@ -290,9 +295,10 @@ class GLRenderer():
""" GLUT callback to redraw OpenGL surface """ GLUT callback to redraw OpenGL surface
""" """
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glRotatef(self.angle,0.,1.,0.)
self.recursive_render(self.scene.rootnode) self.recursive_render(self.scene.rootnode)
glutSwapBuffers() glutSwapBuffers()
self.do_motion() self.do_motion()
return return
@ -307,42 +313,6 @@ class GLRenderer():
if key == 'q': if key == 'q':
sys.exit(0) 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): def render(self, filename=None, fullscreen = False, autofit = True, postprocess = None):
""" """
@ -364,7 +334,8 @@ class GLRenderer():
print("Fullscreen mode not available!") print("Fullscreen mode not available!")
sys.exit(1) sys.exit(1)
self.load_dae(filename, postprocess = postprocess) self.load_model(filename, postprocess = postprocess)
glClearColor(0.1,0.1,0.1,1.) glClearColor(0.1,0.1,0.1,1.)
#glShadeModel(GL_SMOOTH) #glShadeModel(GL_SMOOTH)
@ -374,16 +345,10 @@ class GLRenderer():
glEnable(GL_CULL_FACE) glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST) 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) glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
glEnable(GL_NORMALIZE) glEnable(GL_NORMALIZE)
glEnable(GL_LIGHT0) glEnable(GL_LIGHT0)
glutDisplayFunc(self.display) glutDisplayFunc(self.display)
@ -399,14 +364,8 @@ class GLRenderer():
glPushMatrix() glPushMatrix()
# Register GLUT callbacks for keyboard and mouse
glutKeyboardFunc(self.onkeypress) glutKeyboardFunc(self.onkeypress)
glutSpecialFunc(self.onspecialkeypress)
glutIgnoreKeyRepeat(1) glutIgnoreKeyRepeat(1)
glutSpecialUpFunc(self.onspecialkeyrelease)
glutMouseFunc(self.onclick)
glutMotionFunc(self.onmousemove)
glutMainLoop() glutMainLoop()