[currently viewing: /raytrace/scene_export.py]
"""Registration info for Blender menus:
Name: '342 scene description (.txt)...'
Blender: 232
Group: 'Export'
Tooltip: 'Export for the 342 raytracer scene file'
"""
#-----------------------------------------------------------------
# Export for the 342 raytracer scene file
#-----------------------------------------------------------------
####################################
# Global Variables
####################################
_safeOverwrite = True # If false, will overwrite files without asking.
# Private, don't change these
_file = None
_fatalError = False
####################################
# Library dependancies
####################################
import sys
from math import *
from os.path import exists, join
try:
import Blender
from Blender import World, Camera, Object, NMesh, Lamp, Draw, BGL
from Blender.Mathutils import *
except:
print "Fatal Error! Unable to find Blender modules!"
print "Are you running this script from within blender?"
_fatalError = True
##########################################################
# Callbacks, needed before Main
##########################################################
def select_file(filename):
if filename.find('.txt', -4) <= 0: filename += '.txt'
if exists(filename) and _safeOverwrite:
result = Draw.PupMenu("File Already Exists, Overwrite?%t|Yes%x1|No%x0")
if(result != 1):
return
export_file(filename)
########################################
# Main
########################################
if(not _fatalError):
if Blender.Get('version') < 232:
print "Warning: this exporter may not function with versions of blender"
print "older than 2.32. It if fails please download the latest version"
print "from http://blender.org"
if sys.hexversion < 0x020300F0:
print "NOTICE: Python 2.2 or older, applying Document.writexml patch"
Document.writexml = patch2_2_Document_writexml
DocumentType.writexml = patch2_2_DocumentType_writexml
Blender.Window.FileSelector(select_file,"Export scene file")
###########################################################
# Functions for writing output file
##########################################################
def export_file(filename):
global _file
_file = open(filename,"w")
print ""
print "*** Exporting scene file to:"
print " ", filename
writeFile(_file)
print "*** Done"
########################################################
# Functions for writing scene structure
########################################################
def writeFile(file):
# World details
writeWorld()
##
# There's no reason to have this as three loops
# -- the data can be written in any order, but this is
# asthetically pleasing.
# There may be easier ways to get 'just the lights',
# and 'just the objects'.
# Get the scene objects
objects = Object.Get()
# Camera
for obj in objects:
if obj.getType() == "Camera":
writeCamera(obj)
# Lights
_file.write("\n")
_file.write("# Outputting the lights in the scene\n")
_file.write("# NOTE: Converted all blender light sources to point lights\n")
_file.write("\n")
for obj in objects:
if obj.getType() == "Lamp":
writeLamp(obj)
#Meshes
_file.write("\n\n")
_file.write("# Outputting the meshes in the scene\n")
_file.write("# NOTE: make sure all faces are triangles!!\n")
for obj in objects:
if obj.getType() == "Mesh":
writeMesh(obj.getData(), obj.matrixWorld)
# Done!
_file.write("\nendview\n")
##
# Output a matrix in "non-transposed" format ....
def writeMatrix(matrix):
_file.write("transformation\n")
_file.write(" %.3f %.3f %.3f %.3f\n"
% (matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0]))
_file.write(" %.3f %.3f %.3f %.3f\n"
% (matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1]))
_file.write(" %.3f %.3f %.3f %.3f\n"
% (matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2]))
_file.write(" %.3f %.3f %.3f %.3f\n"
% (matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]))
##
#############################################################
# Functions for exporting Mesh Objects
#############################################################
def writeMesh(mesh, matrix):
print "Exporting Mesh : \"%s\" %i vertices, %i faces" %\
(mesh.name,len(mesh.verts),len(mesh.faces))
if(mesh.getMode() & NMesh.Modes['AUTOSMOOTH']):
print "Warning: Autosmoothing is not supported."
print "Export will behave as if this feature were off"
if (len(mesh.materials) > 1):
print ""
print "Warning: Object has more than one material."
print "Only one material property will be output!!"
print ""
_file.write("\n# Multiple Materials not exported.\n")
_file.write("# Mesh: %s" % mesh.name)
_file.write("\nmesh\n")
if (len(mesh.materials) == 0):
writeDefaultMaterial()
else:
writeMaterial(mesh.materials[0])
writeVertexData(mesh, matrix)
##########################################################
# Functions for exporting vertex data
##########################################################
def writeVertexData(mesh, matrix):
print "Vertex"
getVertices(mesh, matrix)
getIndices(mesh)
def getVertices(mesh, matrix):
_file.write("vertices %i\n" % (len(mesh.verts)) )
for vert in mesh.verts:
vertex = apply_transform(vert, matrix)
_file.write(" %.3f %.3f %.3f\n" % (tuple(vertex)))
def getIndices(mesh):
_file.write("faces %i\n" % (len(mesh.faces)) )
for face in mesh.faces:
_file.write(" ")
if (len(face.v) != 3):
_file.write("error_in_blender_scene: non-triangle mesh found!!!\n ")
for vert in face.v:
_file.write("%i " % vert.index)
_file.write("\n")
_file.write("\n")
############################################################
# Functions for exporting material data
############################################################
##
# Exporting default material
def writeDefaultMaterial():
_file.write("ambient 0.500 0.500 0.500\n")
_file.write("diffuse 0.640 0.640 0.640\n")
_file.write("specular 0.500 0.500 0.500 50.00\n")
_file.write("mirror 0.000 0.000 0.000\n")
##
# Exporting material
def writeMaterial(mat):
_file.write("ambient %.3f %.3f %.3f\n" % (mat.amb, mat.amb, mat.amb))
_file.write("diffuse %.3f %.3f %.3f\n" % (tuple(getDiffuse(mat))))
_file.write("specular %.3f %.3f %.3f " % (tuple(getSpecular(mat))))
_file.write("%.3f\n" % (mat.hard))
_file.write("mirror %.3f %.3f %.3f\n" % (tuple(getMirror(mat))))
def getColour(c):
return "%.3f %.3f %.3f" % (c[0], c[1], c[2])
# the following get colour functions are a best guess
# as to how to convert blender's colour model
##
# Not dealing with emissive materials
def getEmissive(mat):
eCol = mat.rgbCol
for c in range(3):
eCol[c] *= mat.emit
return eCol
##
# Diffuse == (diffuse_colour) * (diffuse_reflectivity)
# * (1 - (mirror_reflectivity))
#
# I guess ... the latter factor looks 'odd' to me!
#
def getDiffuse(mat):
dCol = mat.rgbCol
for c in range(3):
dCol[c] *= mat.ref
dCol[c] *= (1 - mat.rayMirr)
return dCol
##
# Specular == (specular_colour) * (specular_reflectivity)
#
# making sure it's in the range [0.0, 1.0]
#
def getSpecular(mat):
sCol = mat.specCol
for c in range(3):
sCol[c] = min(sCol[c]*mat.spec,1.0)
return sCol
##
# Mirror == (mirror_colour) * (mirror_reflectivity)
#
# I'm always assuming that the object is 'reflective'
#
def getMirror(mat):
mCol = mat.mirCol
for c in range(3):
mCol[c] *= mat.rayMirr
return mCol
#########################################################
# Functions for exporting details about the World
#########################################################
def writeWorld():
print "Exporting the World"
## Some hard coded values for the view screen
## Rather dodgy, and may need to be fixed!!!
##
_file.write("\n")
_file.write("# default value for the size of the image to be created\n")
_file.write("imagesize 320 \n")
_file.write("\n")
## An attempt to get some information about the world
## Background == Horizon
_file.write("# The background colour of the scene\n")
_file.write("# -- using the blender 'horizon' value\n")
hor = (World.Get())[0].getHor()
_file.write("background %.3f %.3f %.3f\n" % tuple(hor) )
_file.write("\n")
## Get some information about the world
_file.write("# The ambient lighting of the scene\n")
amb = (World.Get())[0].getAmb()
_file.write("ambient %.3f %.3f %.3f\n" % tuple(amb) )
_file.write("\n")
#########################################################
# Functions for exporting camera data
#########################################################
def writeCamera(obj):
print "Exporting Camera : \"%s\"" % (obj.name)
_file.write("# the default camera is located at the origin\n")
_file.write("# the default viewplane has corners\n")
_file.write("# -- top left: (-16, 16, -lens) \n")
_file.write("# -- bottom right: ( 16, -16, -lens) \n")
_file.write("# ((Actually, Blender uses a 32*24 viewplane))\n")
_file.write("# \n")
_file.write("camera\n")
## The camera's 'lens' -- distance to standard viewplane (32 * 24)
cam = (Camera.Get())[0].getLens()
_file.write("lens %.3f\n" % (cam) )
## Output the camera transformation from the 'standard position'
writeMatrix(obj.matrixWorld)
_file.write("\n")
#########################################################
# Functions for exporting light data
#########################################################
def writeLamp(obj):
light = obj.getData()
print "Exporting Light : \"%s\"" % (obj.name)
# if(light.type == Lamp.Types['Lamp']):
# writePointLight(obj)
# else:
# print "Error: Light type not recognized"
# output all blender light sources as point lights
writePointLight(obj)
def writePointLight(obj):
light = obj.getData()
_file.write("light ")
_file.write("%.3f %.3f %.3f " % (obj.loc) )
_file.write("%.3f %.3f %.3f\n" % (tuple(light.col)) )
###############################################
# Basic utility functions
###############################################
def radians(deg):
return deg * pi/180.0
def degs(rad):
return rad * 180.0/pi
def euler2AxisAngle(rot):
c = ( cos(rot[0]/2.0), cos(rot[1]/2.0), cos(rot[2]/2.0) )
s = ( sin(rot[0]/2.0), sin(rot[1]/2.0), sin(rot[2]/2.0) )
a = 2*acos( c[0]*c[1]*c[2] + s[0]*s[1]*s[2] )
z = c[0]*c[1]*s[2] - s[0]*s[1]*c[2]
y = c[0]*s[1]*c[2] + s[0]*c[1]*s[2]
x = s[0]*c[1]*c[2] - c[0]*s[1]*s[2]
if( abs(a) < 0.0001 ): a = 0
if( abs(x) < 0.0001 ): x = 0
if( abs(y) < 0.0001 ): y = 0
if( abs(z) < 0.0001 ): z = 0
len = sqrt( x*x + y*y + z*z )
if( abs(len) > 0.0001 ):
x /= len
y /= len
z /= len
return ( x, y, z, a )
def euler2Vector(rot):
vec = Vector([0,0,-1])
x,y,z = rot
mat = Euler([degs(x),degs(y),degs(z)]).toMatrix()
res = VecMultMat(vec,mat.rotationPart())
return res[0],res[1],res[2]
# =======================
# === Apply Transform ===
# =======================
def apply_transform(vertex, matrix):
x, y, z = vertex
xloc, yloc, zloc = matrix[3][0], matrix[3][1], matrix[3][2]
xcomponent = x*matrix[0][0] + y*matrix[1][0] + z*matrix[2][0] + xloc
ycomponent = x*matrix[0][1] + y*matrix[1][1] + z*matrix[2][1] + yloc
zcomponent = x*matrix[0][2] + y*matrix[1][2] + z*matrix[2][2] + zloc
vertex = [xcomponent, ycomponent, zcomponent]
return vertex
