Blender-ZeroEngine-MSH2-Plugin/src_research_readme/blender_2.43_scripts/collada_import.py

1298 lines
43 KiB
Python

#!BPY
"""
Name: 'COLLADA 1.3.1 (.dae) ...'
Blender: 237
Group: 'Import'
Tooltip: 'Import scene from COLLADA format (.dae)'
"""
__author__ = "Mikael Lagre"
__url__ = ("blender", "blenderartist.org", "Project homepage, http://colladablender.sourceforge.net",)
__version__ = "0.4"
__bpydoc__ = """\Description: Imports a COLLADA 1.3.1 file into a Blender scene.
Usage: Run the script from the menu or inside Blender.
Notes: Does not import animation.
"""
# --------------------------------------------------------------------------
# Collada importer version 0.2
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# Copyright (C) 2005: Mikael Lagre' contactme@mikaellagre.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
_ERROR = False
try:
import math
except:
print "Error! Could not find math module"
_ERROR = True
try:
import Blender
from Blender import *
except:
print "Error! Could not find Blender modules!"
_ERROR = True
try:
from xml.dom.minidom import *
except:
print 'Error! Could not find reader.Sax2 module'
_ERROR = True
if _ERROR:
from sys import version_info
version = '%s.%s' % version_info[0:2]
print """
This script requires the xml module that is part of a
default standalone Python install.
To run the collada importer and exporter you need to have
Python version %s installed in your system. It can be downloaded from:
http://www.python.org
Notes:
- The minor (third) version number doesn't matter, you can have either
Python %s.1 or %s.2 or higher.
- If you do have Python %s installed and still can't run the scripts, then
make sure Blender's Python interpreter is finding the standalone modules
(run 'System Information' from Blender's Help -> System menu).
""" % (version, version, version, version)
Draw.PupMenu("Please install full version of python %t | Check the console for more info")
import re
#filename = 'C:\\test.xml'
whitespace = re.compile( '\s+' )
angleToRadian = 3.1415926 / 180.0
radianToAngle = 180.0 / 3.1415926
warnings = False
class Param:
name = None
type = None
flow = None
data = None
def __init__( self, elementNode ):
self.name = CP.PN.toConstant( CP.PN(), elementNode.attributes.getNamedItem( 'name' ).value )
self.type = elementNode.attributes.getNamedItem( 'type' )
if ( self.type != None ):
self.type = self.type.value
self.flow = elementNode.attributes.getNamedItem( 'flow' )
if ( self.flow != None ):
self.flow = self.flow.value
firstChild = elementNode.firstChild
if ( firstChild is not None ):
if ( firstChild.nodeType == Node.TEXT_NODE ):
self.data = firstChild.nodeValue
class Technique:
profile = None
def __init__( self, elementNode ):
self.profile = CP.toConstantProfile( CP(), elementNode.attributes.getNamedItem( 'profile' ).value )
class Input:
idx = None
semantic = None
source = None
def __init__( self, elementNode ):
self.idx = elementNode.attributes.getNamedItem( 'idx' )
if ( self.idx is not None ):
self.idx = self.idx.value
self.semantic = CP.IS.toConstant( CP.IS(), elementNode.attributes.getNamedItem( 'semantic' ).value )
self.source = elementNode.attributes.getNamedItem( 'source' ).value
class Source:
#id = None
#name = None
#data = None
#count = None
#params = None
def __init__( self, sourceNode ):
self.id = sourceNode.attributes.getNamedItem( 'id' ).value
# self.name = sourceNode.attributes.getNamedItem( 'name' ).value
self.data = []
self.params = 0
self.count = None
# Get COMMON profile
techniqueElements = sourceNode.getElementsByTagName( 'technique' )
commonProfile = getCommonProfile( techniqueElements )
if not ( commonProfile is None ):
accessorElements = commonProfile.getElementsByTagName( 'accessor' )
# Get first accessor only
if ( accessorElements ):
accessor = accessorElements[ 0 ]
source = accessor.attributes.getNamedItem( 'source' ).value
source = source[1:]
count = accessor.attributes.getNamedItem( 'count' ).value
# Get nr Params in order to store list in our data list
paramElements = accessor.getElementsByTagName( 'param' )
# NOTE: For this routine it does not matter what the param
# values are since they are accessed logically when reading
# the face values
nrParams = len( paramElements )
# Get source array
float_arrays = sourceNode.getElementsByTagName( 'float_array' )
for array in float_arrays:
id = array.attributes.getNamedItem( 'id' ).value
if ( id == source ):
rawData = getRawData( array )
if ( nrParams == 1 ):
for index in range( 0, len( rawData ), nrParams ):
self.data.append( float( rawData[ index ] ) )
elif ( nrParams == 2 ):
for index in range( 0, len( rawData ), nrParams ):
data = float( rawData[ index ] ), float( rawData[ index + 1 ] )
self.data.append( data )
elif ( nrParams == 3 ):
for index in range( 0, len( rawData ), nrParams ):
data = float( rawData[ index ] ), float( rawData[ index + 1 ] ), float( rawData[ index + 2 ] )
self.data.append( data )
def getParamData( elementNode ):
return Param( elementNode )
def getTechniqueData( elementNode ):
return Technique( elementNode )
def getInputData( elementNode ):
return Input( elementNode )
def getCommonProfile( techniqueElements ):
for technique in techniqueElements:
techniqueData = Technique( technique )
if ( techniqueData.profile == CP.COMMON ):
return technique
return None
def toFloat3( stringValue ):
split = stringValue.split( ) #whitespace.split( stringValue, 2 )
return [ float( split[ 0 ] ), float( split[ 1 ] ), float( split[ 2 ] ) ]
def toMatrix4x4( matrixElement ):
m = getRawData( matrixElement )
vec1 = [ float(m[0]), float(m[4]), float(m[8]), float(m[12]) ]
vec2 = [ float(m[1]), float(m[5]), float(m[9]), float(m[13]) ]
vec3 = [ float(m[2]), float(m[6]), float(m[10]), float(m[14]) ]
vec4 = [ float(m[3]), float(m[7]), float(m[11]), float(m[15]) ]
return Mathutils.Matrix( vec1, vec2, vec3, vec4 )
def getRawData( arrayElement ):
firstChild = arrayElement.firstChild
if ( firstChild is not None ):
if ( firstChild.nodeType == Node.TEXT_NODE ):
data = firstChild.nodeValue.split( )
return data
# Find correct element
def getElements( myNode, tagName ):
nodes = []
for child in myNode.childNodes:
if child.nodeName == tagName:
nodes.append( child )
return nodes
# Make a Euler object with radian angles instead
def toEulerAngleInRadians( euler ):
euler.x *= angleToRadian
euler.y *= angleToRadian
euler.z *= angleToRadian
return euler
def addVec3( vector1, vector2 ):
vector1.x += vector2.x
vector1.y += vector2.y
vector1.z += vector2.z
def getEuler( rotateElement ):
data = getRawData( rotateElement )
euler = [ float( data[ 0 ] ) * float( data[ 3 ] ) * angleToRadian,
float( data[ 1 ] ) * float( data[ 3 ] ) * angleToRadian,
float( data[ 2 ] ) * float( data[ 3 ] ) * angleToRadian ]
return Mathutils.Euler( euler )
def getVector3( element ):
data = getRawData( element )
value = [ float( data[ 0 ] ), float( data[ 1 ] ), float( data[ 2 ] ) ]
return Mathutils.Vector( value )
def getImageSourcePath( source, filePath ):
# Try and load our texture from 'filePath' (local .dae import path)
texturesDir = filePath + '/'
texturesDir = texturesDir.replace( '\\', '/' ) # Bill Gates!!!
splitPath = source.split( '/' )
if ( len( splitPath ) > 0 ):
fileName = splitPath[ len( splitPath ) - 1 ]
mupp = texturesDir + fileName
if ( Blender.sys.exists( mupp ) == 1 ):
return mupp
# File does not exist to try and remove characters from string and see if file exists
source = source.replace( 'file://', '' )
if ( Blender.sys.exists( source ) == 1 ):
return source
source = source.replace( 'file://.', '' )
if ( Blender.sys.exists( source ) == 1 ):
return source
# File did not exists so try and load our texture from 'texturesdir'
texturesDir = Blender.Get( 'texturesdir' )
texturesDir = texturesDir.replace( '\\', '/' ) # Bill Gates!!!
splitPath = source.split( '/' )
if ( len( splitPath ) > 0 ):
fileName = splitPath[ len( splitPath ) - 1 ]
source = texturesDir + fileName
if ( Blender.sys.exists( source ) == 1 ):
return source
return None
# COLLADA Common Profile constants strings
# ( for COLLADA specification 1.3.1 )
# Also in this collada common profile class is library type constants
# flow types and other xs:NMTOKEN constants definied in the schema
class _CommonProfile:
COMMON = 1
BLENDER = 2
str = [ "", "COMMON", "BLENDER" ]
def toConstantProfile( self, str ):
index = 0
for s in _CommonProfile.str:
if ( s == str ):
return index
index += 1
class _ParamName:
A = 1
AMBIENT = 2
ANGLE = 3
ATTENUATION = 4
ATTENUATION_SCALE = 5
B = 6
BOTTOM = 7
COLOR = 8
DIFFUSE = 9
EMISSION = 10
FALLOFF = 11
FALLOFF_SCALE = 12
G = 13
LEFT = 14
P = 15
Q = 16
R = 17
REFLECTIVE = 18
REFLECTIVITY = 19
RIGHT = 20
S = 21
SHININESS = 22
SPECULAR = 23
T = 24
TANGENT_X = 25
TANGENT_Y = 26
TANGENT_Z = 27
TIME = 28
TOP = 29
TRANSPARENCY = 30
TRANSPARENT = 31
U = 32
V = 33
W = 34
X = 35
XFOV = 36
Y = 37
YFOV = 38
Z = 39
ZFAR = 40
ZNEAR = 41
str = [ "", "A", "AMBIENT", "ANGLE", "ATTENUATION",
"ATTENUATION_SCALE", "B", "BOTTOM", "COLOR", "DIFFUSE",
"EMISSION", "FALLOFF", "FALLOFF_SCALE", "G", "LEFT",
"P", "Q", "R", "REFLECTIVE", "REFLECTIVITY", "RIGHT", "S",
"SHININESS", "SPECULAR", "T", "TANGENT.X", "TANGENT.Y",
"TANGENT.Z", "TIME", "TOP", "TRANSPARENCY", "TRANSPARENT",
"U", "V", "W", "X", "XFOV", "Y", "YFOV", "Z", "ZFAR", "ZNEAR" ]
def toConstant( self, str ):
index = 0
for s in CP.PN.str:
if ( s == str ):
return index
index += 1
class _ProgramIDAndURL:
ANGLE_MAP = 1
BEZIER = 2
BSPLINE = 3
CARDINAL = 4
CONSTANT = 5
CUBE_MAP = 6
FISH_EYE = 7
HERMITE = 8
LAMBERT = 9
LINEAR = 10
ORTHOGRAPHIC = 11
PANORAMA = 12
PERSPECTIVE = 13
PHONG = 14
REAR_FISH_EYE = 15
SPHERICAL = 16
str = [ "", "ANGLE_MAP", "BEZIER", "BSPLINE", "CARDINAL", "CONSTANT",
"CUBE_MAP", "FISH_EYE", "HERMITE", "LAMBERT", "LINEAR",
"ORTHOGRAPHIC", "PANORAMA", "PERSPECTIVE", "PHONG",
"REAR_FISH_EYE", "SPHERICAL" ]
def toConstant( self, str ):
index = 0
for s in CP.PIAU.str:
if ( s == str ):
return index
index += 1
class _CodeAndEntrySemantic:
FRAGMENT_PROGRAM = 1
VERTEX_PROGRAM = 2
class _InputSemantic:
BIND_SHAPE_NORMAL = 1
BIND_SHAPE_POSITION = 2
BINORMAL = 3
COLOR = 4
IMAGE = 5
INPUT = 6
IN_TANGENT = 7
INTERPOLATION = 8
INV_BIND_MATRIX = 9
JOINT = 10
JOINTS_AND_WEIGHTS = 11
NORMAL = 12
OUTPUT = 13
OUT_TANGENT = 14
POSITION = 15
TANGENT = 16
TEXCOORD = 17
TEXTURE = 18
UV = 19
VERTEX = 20
WEIGHT = 21
str = [ "", "BIND_SHAPE_NORMAL", "BIND_SHAPE_POSITION", "BINORMAL",
"COLOR", "IMAGE", "INPUT", "IN_TANGENT", "INETRPOLATION",
"INV_BIND_MATRIX", "JOINT", "JOINTS_AND_WEIGHTS", "NORMAL",
"OUTPUT", "OUT_TANGENT", "POSITION", "TANGENT", "TEXCOORD",
"TEXTURE", "UV", "VERTEX", "WEIGHT" ]
def toConstant( self, str ):
index = 0
for s in CP.IS.str:
if ( s == str ):
return index
index += 1
class _ChannelAndControllerTarget:
#( # )[( # )]
A = 1
ANGLE = 2
B = 3
G = 4
P = 5
Q = 6
R = 7
S = 8
T = 9
TIME = 10
U = 11
V = 12
W = 13
X = 14
Y = 15
Z = 16
class _LibraryType:
ANIMATION = 1
CAMERA = 2
CODE = 3
CONTROLLER = 4
GEOMETRY = 5
IMAGE = 6
LIGHT = 7
MATERIAL = 8
PROGRAM = 9
TEXTURE = 10
str = [ "", "ANIMATION", "CAMERA", "CODE", "CONTROLLER", "GEOMETRY",
"IMAGE", "LIGHT", "MATERIAL", "PROGRAM", "TEXTURE" ]
def toConstant( self, str ):
index = 0
for s in CP.LT.str:
if ( s == str ):
return index
index += 1
class _FlowType:
IN = 1
OUT = 2
INOUT = 3
str = [ "", "IN", "OUT", "INOUT" ]
def toConstant( self, str ):
index = 0
for s in CP.FT.str:
if ( s == str ):
return index
index += 1
class _NodeType:
NODE = 1
JOINT = 2
str = [ "", "NODE", "JOINT" ]
def toConstant( self, str ):
index = 0
for s in CP.NT.str:
if ( s == str ):
return index
index += 1
class _LightType:
AMBIENT = 1
DIRECTIONAL = 2
POINT = 3
SPOT = 4
str = [ "", "AMBIENT", "DIRECTIONAL", "POINT", "SPOT" ]
def toConstant( self, str ):
index = 0
for s in CP.LIGHT.str:
if ( s == str ):
return index
index += 1
# Definition of modules for easier access in code
# Note: This is pretty stupid I know ...
class PN( _ParamName ):
pass
class PIAU( _ProgramIDAndURL ):
pass
class CAES( _CodeAndEntrySemantic ):
pass
class IS( _InputSemantic ):
pass
class CACT( _ChannelAndControllerTarget ):
pass
class LT( _LibraryType ):
pass
class FT( _FlowType ):
pass
class NT( _NodeType ):
pass
class LIGHT( _LightType ):
pass
# Common Profile
class CP( _CommonProfile ):
pass
def importImage( imageElement, filePath ):
global library
global warnings
# Get attributes
source = imageElement.attributes.getNamedItem( 'source' )
id = imageElement.attributes.getNamedItem( 'id' ).value
name = imageElement.attributes.getNamedItem( 'name' )
# Get a correct source
imageSource = None
if ( source != None ):
source = source.value
imageSource = getImageSourcePath( source, filePath )
blenderImage = None
if not ( imageSource == None ):
blenderImage = Image.Load( imageSource )
if ( name != None ):
blenderImage.setName( name.value )
elif ( id != None ):
blenderImage.setName( id )
else:
print 'Warning: Texture %s could not be loaded. Check if texture exist or modify texture path in .dae file' % ( source )
warnings = True
return id, blenderImage
def importTexture( textureElement ):
global library
# Get <texture> attributes
id = textureElement.attributes.getNamedItem( 'id' ).value
name = textureElement.attributes.getNamedItem( 'name' )
if name != None:
name = name.value
else:
name = id
# Create new texture
blenderTexture = Texture.New( name )
# Check for supported texture param
# Current support is only DIFFUSE
params = textureElement.getElementsByTagName( 'param' )
imageType = 'Image'
for param in params:
paramData = getParamData( param )
if ( paramData.name == CP.PN.DIFFUSE ):
imageType = 'Image'
break;
# Set texture type
blenderTexture.setType( imageType )
# Get common profile
techniques = textureElement.getElementsByTagName( 'technique' )
commonProfile = getCommonProfile( techniques )
if ( commonProfile is not None ):
inputs = commonProfile.getElementsByTagName( 'input' )
for input in inputs:
inputData = getInputData( input )
if ( inputData.semantic == CP.IS.IMAGE ):
source = inputData.source
source = source.replace( '#', '' )
if ( library.has_key( source ) ):
imageSource = library[ source ]
if ( imageSource != None ):
blenderTexture.setImage( imageSource )
return id, blenderTexture
def importMaterial( materialElement ):
global library
id = materialElement.attributes.getNamedItem( 'id' ).value
name = materialElement.attributes.getNamedItem( 'name' )
if name != None:
name = name.value
else:
name = id
material = Material.New( name )
# Get shader(s)
shaders = materialElement.getElementsByTagName( 'shader' )
shader = None
if ( len( shaders ) > 1 ):
print 'Warning: Multiple shaders on material %s' % id
print 'First shader data used only'
shader = shaders[ 0 ]
# Get COMMON technique
techniques = shader.getElementsByTagName( 'technique' )
common = getCommonProfile( techniques )
if ( common ):
# TODO: Create a LAMBERT diffuse shader and PHONG specular shader
# NOTE: This is not supported yet in Blender 2.37
# Get first pass only
passes = common.getElementsByTagName( 'pass' )
firstPass = None
if ( len( passes ) > 1 ):
print 'Warning shader has multiple passes. Using first pass only'
firstPass = passes[ 0 ]
# Get input semantics
inputSemantics = firstPass.getElementsByTagName( 'input' )
textureSlot = 0
for input in inputSemantics:
if ( textureSlot < 9 ):
inputData = getInputData( input )
# Check for TEXTURE semantic. If present create link to texture
if ( inputData.semantic == CP.IS.TEXTURE ):
source = inputData.source.replace( '#', '' )
# texture = Texture.Get( source )
texture = library[ source ]
if ( texture != None ):
# Default: Map to color and use UV as tex coordinates.
material.setTexture( textureSlot, texture, Texture.TexCo.UV, Texture.MapTo.COL )
# Increase texture slot
textureSlot += 1
else:
print 'Warning: More than 8 textures linked to this material. Additional texture(s) ignored'
break;
# Get program (if any)
programs = shader.getElementsByTagName( 'program' )
if ( programs is not None ):
program = programs[ 0 ]
# Evaluate params
transparent = 1.0, 1.0, 1.0
transparency = 1.0
params = program.getElementsByTagName( 'param' )
for param in params:
paramData = getParamData( param )
name = paramData.name
if ( name == CP.PN.COLOR ):
material.setRGBCol( toFloat3( paramData.data ) )
elif ( name == CP.PN.DIFFUSE ):
material.setRGBCol( toFloat3( paramData.data ) )
elif ( name == CP.PN.AMBIENT ):
ambient = Mathutils.Vector( toFloat3( paramData.data ) )
material.setAmb( ambient.length )
elif ( name == CP.PN.SPECULAR ):
material.setSpecCol( toFloat3( paramData.data ) )
elif ( name == CP.PN.EMISSION ):
emission = Mathutils.Vector( toFloat3( paramData.data ) )
material.setEmit( emission.length )
elif ( name == CP.PN.SHININESS ):
shininess = float( paramData.data) * 4.0
material.setHardness( int( shininess ) )
elif ( name == CP.PN.TRANSPARENT ):
transparent = Mathutils.Vector( toFloat3( paramData.data) )
material.setAlpha( 1.0 - transparent.length )
elif ( name == CP.PN.TRANSPARENCY ):
transparent *= float( paramData.data )
material.setAlpha( 1.0 - transparent.length )
elif ( name == CP.PN.REFLECTIVE ):
material.setMirCol( toFloat3( paramData.data ) )
elif ( name == CP.PN.REFLECTIVITY ):
reflectivity = float( paramData.data )
material.setRef( reflectivity )
return id, material
def importGeometry( geometryElement ):
global library
id = geometryElement.attributes.getNamedItem( 'id' ).value
name = geometryElement.attributes.getNamedItem( 'name' )
# Get mesh element
meshes = geometryElement.getElementsByTagName( 'mesh' )
if not ( meshes == None ):
mesh = meshes[ 0 ]
# Set name
if name:
name = name.value
else:
name = id
# Create mesh
nmesh = Blender.NMesh.New( name )
# Get sources
sourceList = dict()
sourceElements = mesh.getElementsByTagName( 'source' )
for sourceElement in sourceElements:
source = Source( sourceElement )
sourceList[ source.id ] = source
# Get vertices element
vPos = None
vNormal = None
vTexCoord = None
verticesElements = mesh.getElementsByTagName( 'vertices' )
if not ( verticesElements is None ):
vertices = verticesElements[ 0 ]
# Get input semantics for this element
inputs = vertices.getElementsByTagName( 'input' )
for input in inputs:
inputData = getInputData( input )
if ( inputData.semantic == CP.IS.POSITION ):
vPos = sourceList[ inputData.source[1:] ]
elif ( inputData.semantic == CP.IS.NORMAL ):
vNormal = sourceList[ inputData.source[1:] ]
elif ( inputData.semantic == CP.IS.TEXCOORD ):
vTexCoord = sourceList[ inputData.source[1:] ]
nmesh.hasVertexUV( 1 )
# Get <polygons>, <triangles> element
polygonElements = mesh.getElementsByTagName( 'polygons' )
if ( polygonElements == None ):
polygonElements = mesh.getElementsByTagName( 'triangles' )
if ( polygonElements == None ):
print 'Unsupported mesh data type import!'
for polygons in polygonElements:
# Mesh information lists
pVertices = []
pNormal = None
pTexCoord = None
# Get material and create new Material if we could not find any
material = None
materialSource = polygons.attributes.getNamedItem( 'material' )
if ( materialSource != None ):
materialSource = materialSource.value
materialSource = materialSource[1:]
if ( materialSource != '' ):
material = library[ materialSource ]
# material = Material.Get( materialSource )
# Add material to mesh (if present)
firstImage = None
if ( material != None ):
nmesh.addMaterial( material )
# Get first image of first texture and set it to each face
textures = material.getTextures()
firstImage = None
if len( textures ) > 0:
firstTexture = textures[ 0 ]
if ( firstTexture != None ):
firstImage = firstTexture.tex.image
# Get input semantics
inputElements = polygons.getElementsByTagName( 'input' )
inputSemantics = []
nrSemantics = 0
for input in inputElements:
inputData = getInputData( input )
inputSemantics.append( inputData.semantic )
nrSemantics += 1
if ( inputData.semantic == CP.IS.VERTEX ):
# Create NMesh vertices list
vIndex = 0
for v in vPos.data:
vertex = NMesh.Vert( v[ 0 ], v[ 1 ], v[ 2 ] )
vertex.index = vIndex
## if not ( vNormal is None ):
## vertex.normal = Mathutils.Vector( vNormal.data[ vIndex ] )
if not ( vTexCoord is None ):
vertex.uvco = Mathutils.Vector( vTexCoord.data[ vIndex ] )
pVertices.append( vertex )
vIndex += 1
# Set NMesh vertices list
nmesh.verts = pVertices
elif ( inputData.semantic == CP.IS.NORMAL ):
pNormal = sourceList[ inputData.source[1:] ]
elif ( inputData.semantic == CP.IS.TEXCOORD ):
nmesh.hasFaceUV( 1 )
pTexCoord = sourceList[ inputData.source[1:] ]
# Create Face for each p element
pElements = polygons.getElementsByTagName( 'p' )
for p in pElements:
polygonData = getRawData( p )
nrVertices = len( polygonData ) / nrSemantics
newFace = NMesh.Face( )
vIndex = 0
for s in range( nrVertices ):
semanticIndex = 0
vList = []
nList = []
perFaceUV = []
for semantic in inputSemantics:
arrIndex = vIndex * nrSemantics + semanticIndex
index = int( polygonData[ arrIndex ] )
vert = None
if ( semantic == CP.IS.VERTEX ):
vert = pVertices[ index ]
# vList.append( vert )
newFace.append( vert )
elif ( semantic == CP.IS.NORMAL ):
if not ( vert is None ):
vert.no = pNormal.data[ index ]
elif ( semantic == CP.IS.TEXCOORD ):
#perFaceUV.append( pTexCoord.data[ index ] )
newFace.uv.append( pTexCoord.data[ index ] )
semanticIndex +=1
vIndex += 1
# newFace.uv = perFaceUV
if ( firstImage != None ):
newFace.image = firstImage
newFace.mode |= Blender.NMesh.FaceModes[ 'TEX' ]
if ( material != None ):
newFace.materialIndex = 0
newFace.hide = 0
newFace.smooth = 0
nmesh.addFace( newFace )
# Put mesh in blender
nmesh.update( 1, 0, 0 )
return id, nmesh
def importLight( lightElement ):
# Get light type and id
name = lightElement.attributes.getNamedItem( 'name' )
id = lightElement.attributes.getNamedItem( 'id' ).value
type = lightElement.attributes.getNamedItem( 'type' )
newLight = None
if type != None:
type = type.value
if ( type == 'AMBIENT' ):
newLight = Lamp.New( 'Hemi' )
elif ( type == 'DIRECTIONAL' ):
newLight = Lamp.New( 'Sun' )
elif ( type == 'SPOT' ):
newLight = Lamp.New( 'Spot' )
elif ( type == 'POINT' ):
newLight = Lamp.New( 'Lamp' )
else:
type = 'POINT'
newLight = Lamp.New( 'Lamp' )
# Name our light
if not name is None:
newLight.name = name.value
# Get Params
params = lightElement.getElementsByTagName( 'param' )
attenuationType = 'CONSTANT'
attenuationScale = 1.0
#falloffType = 'LINEAR'
falloffScale = 1.0
angle = 45.0
for param in params:
paramData = getParamData( param )
if ( paramData.name == CP.PN.COLOR ):
newLight.col = toFloat3( paramData.data )
elif ( paramData.name == CP.PN.ATTENUATION ):
attenuationType = paramData.data
elif ( paramData.name == CP.PN.ATTENUATION_SCALE ):
attenuationScale = float( paramData.data )
#elif ( paramData.name == CP.PN.FALLOFF ):
# falloffType = paramData.data
elif ( paramData.name == CP.PN.FALLOFF_SCALE ):
falloffScale = float( paramData.data )
elif ( paramData.name == CP.PN.ANGLE ):
angle = float( paramData.data )
# Set energy to 1.0 and distance to 20.0 (default)
newLight.setEnergy( 1.0 )
newLight.setDist( 20.0 )
# Set light attenuation
if ( attenuationType == 'LINEAR' ):
if ( attenuationScale > 0.0 ):
dist = 2.0 / attenuationScale
else:
dist = 5000.0
newLight.setDist( dist )
elif ( attenuationType == 'QUADRATIC' ):
newLight.mode |= Lamp.Modes[ 'Quad' ]
# NOTE: This Quad2 value only applies to the formula used
# in the blender export to calculate the quadratic attenuation
# and to the distance value of 20.0 and energy value of 1.0
quad2Value = ( 1.0 / attenuationScale ) * 0.1
newLight.setQuad2( quad2Value )
# Specific Spot light parameters
if ( type == 'SPOT' ):
# Set spot angle
newLight.setSpotSize( angle )
# Set falloff data
newLight.setSpotBlend( falloffScale / 128.0 )
return id, newLight
def importCamera( cameraElement ):
name = cameraElement.attributes.getNamedItem( 'name' )
id = cameraElement.attributes.getNamedItem( 'id' ).value
if name != None:
name = name.value
else:
name = id
# Create our camera
newCamera = Camera.New( 'persp', name )
# Get COMMON Profile
techniqueElements = cameraElement.getElementsByTagName( 'technique' )
commonProfile = getCommonProfile( techniqueElements )
# Get optics
optics = commonProfile.getElementsByTagName( 'optics' )
if ( len( optics ) > 0 ):
optics = optics[ 0 ]
# Get Program(s)
programs = optics.getElementsByTagName( 'program' )
if programs != None:
program = programs[ 0 ]
url = program.attributes.getNamedItem( 'url' )
if url != None:
url = url.value
# PERSPECTIVE Camera type
if ( url == 'PERSPECTIVE' ):
paramElements = program.getElementsByTagName( 'param' )
for paramElement in paramElements:
param = getParamData( paramElement )
if ( param.name == CP.PN.YFOV ):
yfov = float( param.data )
lens = 16.0 / math.tan( yfov * 0.5 * ( 3.1415926 / 180.0 ) )
newCamera.setLens( lens )
if ( param.name == CP.PN.XFOV ): # TODO: XFOV is not the same...
xfov = float( param.data )
lens = 16.0 / math.tan( yfov * 0.5 )
newCamera.setLens( lens )
if ( param.name == CP.PN.ZNEAR ):
znear = float( param.data )
newCamera.setClipStart( znear )
if ( param.name == CP.PN.ZFAR ):
zfar = float( param.data )
newCamera.setClipEnd( zfar )
else:
print 'Data for ORTHOGRAPHIC Camera type ignored.'
return id, newCamera
def importLibrary( libNode, filePath ):
global filename
global library
global currentScene
# Get library elements
libraryElements = libNode.getElementsByTagName( 'library' )
imageElements = None
textureElements = None
materialElements = None
geometryElement = None
lightElements = None
cameraElements = None
for child in libraryElements:
typeValue = child.attributes.getNamedItem( 'type' ).value
if ( typeValue == 'IMAGE' ):
imageElements = child.getElementsByTagName( 'image' )
elif ( typeValue == 'TEXTURE' ):
textureElements = child.getElementsByTagName( 'texture' )
elif ( typeValue == 'MATERIAL' ):
materialElements = child.getElementsByTagName( 'material' )
elif ( typeValue == 'GEOMETRY' ):
geometryElement = child.getElementsByTagName( 'geometry' )
elif ( typeValue == 'LIGHT' ):
lightElements = child.getElementsByTagName( 'light' )
elif ( typeValue == 'CAMERA' ):
cameraElements = child.getElementsByTagName( 'camera' )
# Import library data and put into library dictionary
if imageElements != None:
for image in imageElements:
imageData = importImage( image, filePath )
if ( imageData[ 1 ] != None ):
library[ imageData[ 0 ] ] = imageData[ 1 ]
if textureElements != None:
for texture in textureElements:
textureData = importTexture( texture )
library[ textureData[ 0 ] ] = textureData[ 1 ]
if materialElements != None:
for material in materialElements:
materialData = importMaterial( material )
library[ materialData[ 0 ] ] = materialData[ 1 ]
if geometryElement != None:
for mesh in geometryElement:
meshData = importGeometry( mesh )
library[ meshData[ 0 ] ] = 'Mesh', meshData[ 1 ]
if lightElements != None:
for light in lightElements:
lightData = importLight( light )
library[ lightData[ 0 ] ] = 'Lamp', lightData[ 1 ]
if cameraElements != None:
for camera in cameraElements:
cameraData = importCamera( camera )
library[ cameraData[ 0 ] ] = 'Camera', cameraData[ 1 ]
""" Import Collada scene into Blender scene """
def importScene( colladaNode ):
global currentScene
global library
# Build scene
# TODO: Add option for creating a new scene or import into current scene!
# Get <scene> element
sceneElements = colladaNode.getElementsByTagName( 'scene' )
sceneElement = None
if not sceneElements is None:
sceneElement = sceneElements[ 0 ]
name = sceneElement.attributes.getNamedItem( 'name' )
if not name is None:
currentScene.setName( name.value )
# Import nodes
nodeElements = getElements( sceneElement, 'node' )
if not nodeElements is None:
for node in nodeElements:
type = node.attributes.getNamedItem( 'type' )
if not type is None:
if type.value == 'JOINT':
pass
else:
importNode( None, node )
else:
importNode( None, node )
# Update scene
currentScene.update( )
Blender.Redraw( )
def importNode( myParent, thisNode ):
global currentScene
global library
newObject = None
# Create new object in blender
thisNodeID = thisNode.attributes.getNamedItem( 'id' ).value
# print '<node id=' + thisNodeID + '>'
# Get instance
instanceElements = getElements( thisNode, 'instance' )
if len( instanceElements ) > 0:
instanceElement = instanceElements[ 0 ]
instanceURL = instanceElement.attributes.getNamedItem( 'url' ).value
instanceURL = instanceURL[1:]
# Get Data object (which is a tuple of ['TYPE', Data ] )
if library.has_key( instanceURL ):
data = library[ instanceURL ]
if not data is None:
newObject = Object.New( data[ 0 ], thisNodeID )
newObject.link( data[ 1 ] )
if newObject is None:
newObject = Object.New( 'Empty', thisNodeID )
# Get baked transform
matrixElement = getElements( thisNode, 'matrix' )
relativeMatrix = Mathutils.Matrix( )
if len( matrixElement ) > 0:
matrixElement = matrixElement[ 0 ]
relativeMatrix = toMatrix4x4( matrixElement )
newObject.setLocation( relativeMatrix.translationPart() )
# Euler angles now has to be in radians ...
newObject.setEuler( toEulerAngleInRadians( relativeMatrix.rotationPart().toEuler( ) ) )
else:
# Look for unbaked transform
translationElements = getElements( thisNode, 'translate' )
rotationElements = getElements( thisNode, 'rotate' )
scaleElements = getElements( thisNode, 'scale' )
# Set translation
translateVec = Mathutils.Vector()
for translate in translationElements:
addVec3( translateVec, getVector3( translate ) )
newObject.setLocation( translateVec )
# Set rotation
rotationEuler = Mathutils.Euler( [ 0.0, 0.0, 0.0 ] )
for rotate in rotationElements:
euler = getEuler( rotate )
rotationEuler.x += euler.x
rotationEuler.y += euler.y
rotationEuler.z += euler.z
newObject.setEuler( rotationEuler )
# Set scale value
for scale in scaleElements:
value = getVector3( scale )
newObject.setSize( value.x, value.y, value.z )
# Link object to scene
currentScene.link( newObject )
# Get other nodes
childList = []
nodeElements = getElements( thisNode, 'node' )
if not nodeElements is None:
for node in nodeElements:
type = node.attributes.getNamedItem( 'type' )
if not type is None:
if type.value == 'JOINT':
pass
else:
childList.append( importNode( newObject, node ) )
else:
childList.append( importNode( newObject, node ) )
# Make this new object parent of child objects
if len( childList ) > 0:
newObject.makeParent( childList, 0, 1 )
return newObject
def main( filename ):
global library
global currentScene
global warnings
currentScene = Scene.GetCurrent( )
library = dict()
libraryElements = None
sceneElement = None
# Open file
startTime = Blender.sys.time()
# Build DOM tree
doc = parse( filename )
# Get COLLADA element
collada = doc.firstChild
# Extract filePath from filename
filePath = Blender.sys.dirname( filename )
# Import library
importLibrary( collada, filePath )
# Import scene hiearchy
importScene( collada )
endTime = Blender.sys.time()
importTime = endTime - startTime
print "Import time: %.6f" % ( importTime )
# Handle warnings
if ( warnings ):
Draw.PupMenu( 'Warning%t|Some information could not be imported. Check console for details' )
def callback_fileselector( filename ):
if ( Blender.sys.exists( filename ) == 1 ):
main( filename )
else:
Draw.PupMenu( "ERROR: File does not exist!" )
print 'File does not exist!'
def ImportGUI( ):
Window.FileSelector( callback_fileselector, 'Import .dae', '' )
if not ( _ERROR == True ):
ImportGUI()
#main( filename )